blob: 6c5c52fa1a55387200a551cffb7985262c0993b5 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700143 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700144 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 static final boolean VALIDATE_TOKENS = false;
146 static final boolean SHOW_ACTIVITY_START_TIME = true;
147
148 // Control over CPU and battery monitoring.
149 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
150 static final boolean MONITOR_CPU_USAGE = true;
151 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
152 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
153 static final boolean MONITOR_THREAD_CPU_USAGE = false;
154
Dianne Hackborn1655be42009-05-08 14:29:01 -0700155 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700156 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 private static final String SYSTEM_SECURE = "ro.secure";
159
160 // This is the maximum number of application processes we would like
161 // to have running. Due to the asynchronous nature of things, we can
162 // temporarily go beyond this limit.
163 static final int MAX_PROCESSES = 2;
164
165 // Set to false to leave processes running indefinitely, relying on
166 // the kernel killing them as resources are required.
167 static final boolean ENFORCE_PROCESS_LIMIT = false;
168
169 // This is the maximum number of activities that we would like to have
170 // running at a given time.
171 static final int MAX_ACTIVITIES = 20;
172
173 // Maximum number of recent tasks that we can remember.
174 static final int MAX_RECENT_TASKS = 20;
175
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700176 // Amount of time after a call to stopAppSwitches() during which we will
177 // prevent further untrusted switches from happening.
178 static final long APP_SWITCH_DELAY_TIME = 5*1000;
179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 // How long until we reset a task when the user returns to it. Currently
181 // 30 minutes.
182 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
183
184 // Set to true to disable the icon that is shown while a new activity
185 // is being started.
186 static final boolean SHOW_APP_STARTING_ICON = true;
187
188 // How long we wait until giving up on the last activity to pause. This
189 // is short because it directly impacts the responsiveness of starting the
190 // next activity.
191 static final int PAUSE_TIMEOUT = 500;
192
193 /**
194 * How long we can hold the launch wake lock before giving up.
195 */
196 static final int LAUNCH_TIMEOUT = 10*1000;
197
198 // How long we wait for a launched process to attach to the activity manager
199 // before we decide it's never going to come up for real.
200 static final int PROC_START_TIMEOUT = 10*1000;
201
202 // How long we wait until giving up on the last activity telling us it
203 // is idle.
204 static final int IDLE_TIMEOUT = 10*1000;
205
206 // How long to wait after going idle before forcing apps to GC.
207 static final int GC_TIMEOUT = 5*1000;
208
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700209 // The minimum amount of time between successive GC requests for a process.
210 static final int GC_MIN_INTERVAL = 60*1000;
211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 // How long we wait until giving up on an activity telling us it has
213 // finished destroying itself.
214 static final int DESTROY_TIMEOUT = 10*1000;
215
216 // How long we allow a receiver to run before giving up on it.
217 static final int BROADCAST_TIMEOUT = 10*1000;
218
219 // How long we wait for a service to finish executing.
220 static final int SERVICE_TIMEOUT = 20*1000;
221
222 // How long a service needs to be running until restarting its process
223 // is no longer considered to be a relaunch of the service.
224 static final int SERVICE_RESTART_DURATION = 5*1000;
225
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700226 // How long a service needs to be running until it will start back at
227 // SERVICE_RESTART_DURATION after being killed.
228 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
229
230 // Multiplying factor to increase restart duration time by, for each time
231 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
232 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
233
234 // The minimum amount of time between restarting services that we allow.
235 // That is, when multiple services are restarting, we won't allow each
236 // to restart less than this amount of time from the last one.
237 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 // Maximum amount of time for there to be no activity on a service before
240 // we consider it non-essential and allow its process to go on the
241 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700242 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
244 // How long we wait until we timeout on key dispatching.
245 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
246
247 // The minimum time we allow between crashes, for us to consider this
248 // application to be bad and stop and its services and reject broadcasts.
249 static final int MIN_CRASH_INTERVAL = 60*1000;
250
251 // How long we wait until we timeout on key dispatching during instrumentation.
252 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
253
254 // OOM adjustments for processes in various states:
255
256 // This is a process without anything currently running in it. Definitely
257 // the first to go! Value set in system/rootdir/init.rc on startup.
258 // This value is initalized in the constructor, careful when refering to
259 // this static variable externally.
260 static int EMPTY_APP_ADJ;
261
262 // This is a process with a content provider that does not have any clients
263 // attached to it. If it did have any clients, its adjustment would be the
264 // one for the highest-priority of those processes.
265 static int CONTENT_PROVIDER_ADJ;
266
267 // This is a process only hosting activities that are not visible,
268 // so it can be killed without any disruption. Value set in
269 // system/rootdir/init.rc on startup.
270 final int HIDDEN_APP_MAX_ADJ;
271 static int HIDDEN_APP_MIN_ADJ;
272
The Android Open Source Project4df24232009-03-05 14:34:35 -0800273 // This is a process holding the home application -- we want to try
274 // avoiding killing it, even if it would normally be in the background,
275 // because the user interacts with it so much.
276 final int HOME_APP_ADJ;
277
Christopher Tate6fa95972009-06-05 18:43:55 -0700278 // This is a process currently hosting a backup operation. Killing it
279 // is not entirely fatal but is generally a bad idea.
280 final int BACKUP_APP_ADJ;
281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 // This is a process holding a secondary server -- killing it will not
283 // have much of an impact as far as the user is concerned. Value set in
284 // system/rootdir/init.rc on startup.
285 final int SECONDARY_SERVER_ADJ;
286
287 // This is a process only hosting activities that are visible to the
288 // user, so we'd prefer they don't disappear. Value set in
289 // system/rootdir/init.rc on startup.
290 final int VISIBLE_APP_ADJ;
291
292 // This is the process running the current foreground app. We'd really
293 // rather not kill it! Value set in system/rootdir/init.rc on startup.
294 final int FOREGROUND_APP_ADJ;
295
296 // This is a process running a core server, such as telephony. Definitely
297 // don't want to kill it, but doing so is not completely fatal.
298 static final int CORE_SERVER_ADJ = -12;
299
300 // The system process runs at the default adjustment.
301 static final int SYSTEM_ADJ = -16;
302
303 // Memory pages are 4K.
304 static final int PAGE_SIZE = 4*1024;
305
Jacek Surazski82a73df2009-06-17 14:33:18 +0200306 // System property defining error report receiver for system apps
307 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
308
309 // System property defining default error report receiver
310 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 // Corresponding memory levels for above adjustments.
313 final int EMPTY_APP_MEM;
314 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800315 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700316 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 final int SECONDARY_SERVER_MEM;
318 final int VISIBLE_APP_MEM;
319 final int FOREGROUND_APP_MEM;
320
321 final int MY_PID;
322
323 static final String[] EMPTY_STRING_ARRAY = new String[0];
324
325 enum ActivityState {
326 INITIALIZING,
327 RESUMED,
328 PAUSING,
329 PAUSED,
330 STOPPING,
331 STOPPED,
332 FINISHING,
333 DESTROYING,
334 DESTROYED
335 }
336
337 /**
338 * The back history of all previous (and possibly still
339 * running) activities. It contains HistoryRecord objects.
340 */
341 final ArrayList mHistory = new ArrayList();
342
343 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700344 * Description of a request to start a new activity, which has been held
345 * due to app switches being disabled.
346 */
347 class PendingActivityLaunch {
348 HistoryRecord r;
349 HistoryRecord sourceRecord;
350 Uri[] grantedUriPermissions;
351 int grantedMode;
352 boolean onlyIfNeeded;
353 }
354
355 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
356 = new ArrayList<PendingActivityLaunch>();
357
358 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 * List of all active broadcasts that are to be executed immediately
360 * (without waiting for another broadcast to finish). Currently this only
361 * contains broadcasts to registered receivers, to avoid spinning up
362 * a bunch of processes to execute IntentReceiver components.
363 */
364 final ArrayList<BroadcastRecord> mParallelBroadcasts
365 = new ArrayList<BroadcastRecord>();
366
367 /**
368 * List of all active broadcasts that are to be executed one at a time.
369 * The object at the top of the list is the currently activity broadcasts;
370 * those after it are waiting for the top to finish..
371 */
372 final ArrayList<BroadcastRecord> mOrderedBroadcasts
373 = new ArrayList<BroadcastRecord>();
374
375 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800376 * Historical data of past broadcasts, for debugging.
377 */
378 static final int MAX_BROADCAST_HISTORY = 100;
379 final BroadcastRecord[] mBroadcastHistory
380 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
381
382 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 * Set when we current have a BROADCAST_INTENT_MSG in flight.
384 */
385 boolean mBroadcastsScheduled = false;
386
387 /**
388 * Set to indicate whether to issue an onUserLeaving callback when a
389 * newly launched activity is being brought in front of us.
390 */
391 boolean mUserLeaving = false;
392
393 /**
394 * When we are in the process of pausing an activity, before starting the
395 * next one, this variable holds the activity that is currently being paused.
396 */
397 HistoryRecord mPausingActivity = null;
398
399 /**
400 * Current activity that is resumed, or null if there is none.
401 */
402 HistoryRecord mResumedActivity = null;
403
404 /**
405 * Activity we have told the window manager to have key focus.
406 */
407 HistoryRecord mFocusedActivity = null;
408
409 /**
410 * This is the last activity that we put into the paused state. This is
411 * used to determine if we need to do an activity transition while sleeping,
412 * when we normally hold the top activity paused.
413 */
414 HistoryRecord mLastPausedActivity = null;
415
416 /**
417 * List of activities that are waiting for a new activity
418 * to become visible before completing whatever operation they are
419 * supposed to do.
420 */
421 final ArrayList mWaitingVisibleActivities = new ArrayList();
422
423 /**
424 * List of activities that are ready to be stopped, but waiting
425 * for the next activity to settle down before doing so. It contains
426 * HistoryRecord objects.
427 */
428 final ArrayList<HistoryRecord> mStoppingActivities
429 = new ArrayList<HistoryRecord>();
430
431 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700432 * Animations that for the current transition have requested not to
433 * be considered for the transition animation.
434 */
435 final ArrayList<HistoryRecord> mNoAnimActivities
436 = new ArrayList<HistoryRecord>();
437
438 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 * List of intents that were used to start the most recent tasks.
440 */
441 final ArrayList<TaskRecord> mRecentTasks
442 = new ArrayList<TaskRecord>();
443
444 /**
445 * List of activities that are ready to be finished, but waiting
446 * for the previous activity to settle down before doing so. It contains
447 * HistoryRecord objects.
448 */
449 final ArrayList mFinishingActivities = new ArrayList();
450
451 /**
452 * All of the applications we currently have running organized by name.
453 * The keys are strings of the application package name (as
454 * returned by the package manager), and the keys are ApplicationRecord
455 * objects.
456 */
457 final ProcessMap<ProcessRecord> mProcessNames
458 = new ProcessMap<ProcessRecord>();
459
460 /**
461 * The last time that various processes have crashed.
462 */
463 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
464
465 /**
466 * Set of applications that we consider to be bad, and will reject
467 * incoming broadcasts from (which the user has no control over).
468 * Processes are added to this set when they have crashed twice within
469 * a minimum amount of time; they are removed from it when they are
470 * later restarted (hopefully due to some user action). The value is the
471 * time it was added to the list.
472 */
473 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
474
475 /**
476 * All of the processes we currently have running organized by pid.
477 * The keys are the pid running the application.
478 *
479 * <p>NOTE: This object is protected by its own lock, NOT the global
480 * activity manager lock!
481 */
482 final SparseArray<ProcessRecord> mPidsSelfLocked
483 = new SparseArray<ProcessRecord>();
484
485 /**
486 * All of the processes that have been forced to be foreground. The key
487 * is the pid of the caller who requested it (we hold a death
488 * link on it).
489 */
490 abstract class ForegroundToken implements IBinder.DeathRecipient {
491 int pid;
492 IBinder token;
493 }
494 final SparseArray<ForegroundToken> mForegroundProcesses
495 = new SparseArray<ForegroundToken>();
496
497 /**
498 * List of records for processes that someone had tried to start before the
499 * system was ready. We don't start them at that point, but ensure they
500 * are started by the time booting is complete.
501 */
502 final ArrayList<ProcessRecord> mProcessesOnHold
503 = new ArrayList<ProcessRecord>();
504
505 /**
506 * List of records for processes that we have started and are waiting
507 * for them to call back. This is really only needed when running in
508 * single processes mode, in which case we do not have a unique pid for
509 * each process.
510 */
511 final ArrayList<ProcessRecord> mStartingProcesses
512 = new ArrayList<ProcessRecord>();
513
514 /**
515 * List of persistent applications that are in the process
516 * of being started.
517 */
518 final ArrayList<ProcessRecord> mPersistentStartingProcesses
519 = new ArrayList<ProcessRecord>();
520
521 /**
522 * Processes that are being forcibly torn down.
523 */
524 final ArrayList<ProcessRecord> mRemovedProcesses
525 = new ArrayList<ProcessRecord>();
526
527 /**
528 * List of running applications, sorted by recent usage.
529 * The first entry in the list is the least recently used.
530 * It contains ApplicationRecord objects. This list does NOT include
531 * any persistent application records (since we never want to exit them).
532 */
533 final ArrayList<ProcessRecord> mLRUProcesses
534 = new ArrayList<ProcessRecord>();
535
536 /**
537 * List of processes that should gc as soon as things are idle.
538 */
539 final ArrayList<ProcessRecord> mProcessesToGc
540 = new ArrayList<ProcessRecord>();
541
542 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800543 * This is the process holding what we currently consider to be
544 * the "home" activity.
545 */
546 private ProcessRecord mHomeProcess;
547
548 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 * List of running activities, sorted by recent usage.
550 * The first entry in the list is the least recently used.
551 * It contains HistoryRecord objects.
552 */
553 private final ArrayList mLRUActivities = new ArrayList();
554
555 /**
556 * Set of PendingResultRecord objects that are currently active.
557 */
558 final HashSet mPendingResultRecords = new HashSet();
559
560 /**
561 * Set of IntentSenderRecord objects that are currently active.
562 */
563 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
564 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
565
566 /**
567 * Intent broadcast that we have tried to start, but are
568 * waiting for its application's process to be created. We only
569 * need one (instead of a list) because we always process broadcasts
570 * one at a time, so no others can be started while waiting for this
571 * one.
572 */
573 BroadcastRecord mPendingBroadcast = null;
574
575 /**
576 * Keeps track of all IIntentReceivers that have been registered for
577 * broadcasts. Hash keys are the receiver IBinder, hash value is
578 * a ReceiverList.
579 */
580 final HashMap mRegisteredReceivers = new HashMap();
581
582 /**
583 * Resolver for broadcast intents to registered receivers.
584 * Holds BroadcastFilter (subclass of IntentFilter).
585 */
586 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
587 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
588 @Override
589 protected boolean allowFilterResult(
590 BroadcastFilter filter, List<BroadcastFilter> dest) {
591 IBinder target = filter.receiverList.receiver.asBinder();
592 for (int i=dest.size()-1; i>=0; i--) {
593 if (dest.get(i).receiverList.receiver.asBinder() == target) {
594 return false;
595 }
596 }
597 return true;
598 }
599 };
600
601 /**
602 * State of all active sticky broadcasts. Keys are the action of the
603 * sticky Intent, values are an ArrayList of all broadcasted intents with
604 * that action (which should usually be one).
605 */
606 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
607 new HashMap<String, ArrayList<Intent>>();
608
609 /**
610 * All currently running services.
611 */
612 final HashMap<ComponentName, ServiceRecord> mServices =
613 new HashMap<ComponentName, ServiceRecord>();
614
615 /**
616 * All currently running services indexed by the Intent used to start them.
617 */
618 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
619 new HashMap<Intent.FilterComparison, ServiceRecord>();
620
621 /**
622 * All currently bound service connections. Keys are the IBinder of
623 * the client's IServiceConnection.
624 */
625 final HashMap<IBinder, ConnectionRecord> mServiceConnections
626 = new HashMap<IBinder, ConnectionRecord>();
627
628 /**
629 * List of services that we have been asked to start,
630 * but haven't yet been able to. It is used to hold start requests
631 * while waiting for their corresponding application thread to get
632 * going.
633 */
634 final ArrayList<ServiceRecord> mPendingServices
635 = new ArrayList<ServiceRecord>();
636
637 /**
638 * List of services that are scheduled to restart following a crash.
639 */
640 final ArrayList<ServiceRecord> mRestartingServices
641 = new ArrayList<ServiceRecord>();
642
643 /**
644 * List of services that are in the process of being stopped.
645 */
646 final ArrayList<ServiceRecord> mStoppingServices
647 = new ArrayList<ServiceRecord>();
648
649 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700650 * Backup/restore process management
651 */
652 String mBackupAppName = null;
653 BackupRecord mBackupTarget = null;
654
655 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 * List of PendingThumbnailsRecord objects of clients who are still
657 * waiting to receive all of the thumbnails for a task.
658 */
659 final ArrayList mPendingThumbnails = new ArrayList();
660
661 /**
662 * List of HistoryRecord objects that have been finished and must
663 * still report back to a pending thumbnail receiver.
664 */
665 final ArrayList mCancelledThumbnails = new ArrayList();
666
667 /**
668 * All of the currently running global content providers. Keys are a
669 * string containing the provider name and values are a
670 * ContentProviderRecord object containing the data about it. Note
671 * that a single provider may be published under multiple names, so
672 * there may be multiple entries here for a single one in mProvidersByClass.
673 */
674 final HashMap mProvidersByName = new HashMap();
675
676 /**
677 * All of the currently running global content providers. Keys are a
678 * string containing the provider's implementation class and values are a
679 * ContentProviderRecord object containing the data about it.
680 */
681 final HashMap mProvidersByClass = new HashMap();
682
683 /**
684 * List of content providers who have clients waiting for them. The
685 * application is currently being launched and the provider will be
686 * removed from this list once it is published.
687 */
688 final ArrayList mLaunchingProviders = new ArrayList();
689
690 /**
691 * Global set of specific Uri permissions that have been granted.
692 */
693 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
694 = new SparseArray<HashMap<Uri, UriPermission>>();
695
696 /**
697 * Thread-local storage used to carry caller permissions over through
698 * indirect content-provider access.
699 * @see #ActivityManagerService.openContentUri()
700 */
701 private class Identity {
702 public int pid;
703 public int uid;
704
705 Identity(int _pid, int _uid) {
706 pid = _pid;
707 uid = _uid;
708 }
709 }
710 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
711
712 /**
713 * All information we have collected about the runtime performance of
714 * any user id that can impact battery performance.
715 */
716 final BatteryStatsService mBatteryStatsService;
717
718 /**
719 * information about component usage
720 */
721 final UsageStatsService mUsageStatsService;
722
723 /**
724 * Current configuration information. HistoryRecord objects are given
725 * a reference to this object to indicate which configuration they are
726 * currently running in, so this object must be kept immutable.
727 */
728 Configuration mConfiguration = new Configuration();
729
730 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700731 * Hardware-reported OpenGLES version.
732 */
733 final int GL_ES_VERSION;
734
735 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 * List of initialization arguments to pass to all processes when binding applications to them.
737 * For example, references to the commonly used services.
738 */
739 HashMap<String, IBinder> mAppBindArgs;
740
741 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700742 * Temporary to avoid allocations. Protected by main lock.
743 */
744 final StringBuilder mStringBuilder = new StringBuilder(256);
745
746 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 * Used to control how we initialize the service.
748 */
749 boolean mStartRunning = false;
750 ComponentName mTopComponent;
751 String mTopAction;
752 String mTopData;
753 boolean mSystemReady = false;
754 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700755 boolean mWaitingUpdate = false;
756 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757
758 Context mContext;
759
760 int mFactoryTest;
761
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700762 boolean mCheckedForSetup;
763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700765 * The time at which we will allow normal application switches again,
766 * after a call to {@link #stopAppSwitches()}.
767 */
768 long mAppSwitchesAllowedTime;
769
770 /**
771 * This is set to true after the first switch after mAppSwitchesAllowedTime
772 * is set; any switches after that will clear the time.
773 */
774 boolean mDidAppSwitch;
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Set while we are wanting to sleep, to prevent any
778 * activities from being started/resumed.
779 */
780 boolean mSleeping = false;
781
782 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700783 * Set if we are shutting down the system, similar to sleeping.
784 */
785 boolean mShuttingDown = false;
786
787 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 * Set when the system is going to sleep, until we have
789 * successfully paused the current activity and released our wake lock.
790 * At that point the system is allowed to actually sleep.
791 */
792 PowerManager.WakeLock mGoingToSleep;
793
794 /**
795 * We don't want to allow the device to go to sleep while in the process
796 * of launching an activity. This is primarily to allow alarm intent
797 * receivers to launch an activity and get that to run before the device
798 * goes back to sleep.
799 */
800 PowerManager.WakeLock mLaunchingActivity;
801
802 /**
803 * Task identifier that activities are currently being started
804 * in. Incremented each time a new task is created.
805 * todo: Replace this with a TokenSpace class that generates non-repeating
806 * integers that won't wrap.
807 */
808 int mCurTask = 1;
809
810 /**
811 * Current sequence id for oom_adj computation traversal.
812 */
813 int mAdjSeq = 0;
814
815 /**
816 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
817 * is set, indicating the user wants processes started in such a way
818 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
819 * running in each process (thus no pre-initialized process, etc).
820 */
821 boolean mSimpleProcessManagement = false;
822
823 /**
824 * System monitoring: number of processes that died since the last
825 * N procs were started.
826 */
827 int[] mProcDeaths = new int[20];
828
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700829 /**
830 * This is set if we had to do a delayed dexopt of an app before launching
831 * it, to increasing the ANR timeouts in that case.
832 */
833 boolean mDidDexOpt;
834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 String mDebugApp = null;
836 boolean mWaitForDebugger = false;
837 boolean mDebugTransient = false;
838 String mOrigDebugApp = null;
839 boolean mOrigWaitForDebugger = false;
840 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700841 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700843 final RemoteCallbackList<IActivityWatcher> mWatchers
844 = new RemoteCallbackList<IActivityWatcher>();
845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 /**
847 * Callback of last caller to {@link #requestPss}.
848 */
849 Runnable mRequestPssCallback;
850
851 /**
852 * Remaining processes for which we are waiting results from the last
853 * call to {@link #requestPss}.
854 */
855 final ArrayList<ProcessRecord> mRequestPssList
856 = new ArrayList<ProcessRecord>();
857
858 /**
859 * Runtime statistics collection thread. This object's lock is used to
860 * protect all related state.
861 */
862 final Thread mProcessStatsThread;
863
864 /**
865 * Used to collect process stats when showing not responding dialog.
866 * Protected by mProcessStatsThread.
867 */
868 final ProcessStats mProcessStats = new ProcessStats(
869 MONITOR_THREAD_CPU_USAGE);
870 long mLastCpuTime = 0;
871 long mLastWriteTime = 0;
872
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700873 long mInitialStartTime = 0;
874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 /**
876 * Set to true after the system has finished booting.
877 */
878 boolean mBooted = false;
879
880 int mProcessLimit = 0;
881
882 WindowManagerService mWindowManager;
883
884 static ActivityManagerService mSelf;
885 static ActivityThread mSystemThread;
886
887 private final class AppDeathRecipient implements IBinder.DeathRecipient {
888 final ProcessRecord mApp;
889 final int mPid;
890 final IApplicationThread mAppThread;
891
892 AppDeathRecipient(ProcessRecord app, int pid,
893 IApplicationThread thread) {
894 if (localLOGV) Log.v(
895 TAG, "New death recipient " + this
896 + " for thread " + thread.asBinder());
897 mApp = app;
898 mPid = pid;
899 mAppThread = thread;
900 }
901
902 public void binderDied() {
903 if (localLOGV) Log.v(
904 TAG, "Death received in " + this
905 + " for thread " + mAppThread.asBinder());
906 removeRequestedPss(mApp);
907 synchronized(ActivityManagerService.this) {
908 appDiedLocked(mApp, mPid, mAppThread);
909 }
910 }
911 }
912
913 static final int SHOW_ERROR_MSG = 1;
914 static final int SHOW_NOT_RESPONDING_MSG = 2;
915 static final int SHOW_FACTORY_ERROR_MSG = 3;
916 static final int UPDATE_CONFIGURATION_MSG = 4;
917 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
918 static final int WAIT_FOR_DEBUGGER_MSG = 6;
919 static final int BROADCAST_INTENT_MSG = 7;
920 static final int BROADCAST_TIMEOUT_MSG = 8;
921 static final int PAUSE_TIMEOUT_MSG = 9;
922 static final int IDLE_TIMEOUT_MSG = 10;
923 static final int IDLE_NOW_MSG = 11;
924 static final int SERVICE_TIMEOUT_MSG = 12;
925 static final int UPDATE_TIME_ZONE = 13;
926 static final int SHOW_UID_ERROR_MSG = 14;
927 static final int IM_FEELING_LUCKY_MSG = 15;
928 static final int LAUNCH_TIMEOUT_MSG = 16;
929 static final int DESTROY_TIMEOUT_MSG = 17;
930 static final int SERVICE_ERROR_MSG = 18;
931 static final int RESUME_TOP_ACTIVITY_MSG = 19;
932 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700933 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700934 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935
936 AlertDialog mUidAlert;
937
938 final Handler mHandler = new Handler() {
939 //public Handler() {
940 // if (localLOGV) Log.v(TAG, "Handler started!");
941 //}
942
943 public void handleMessage(Message msg) {
944 switch (msg.what) {
945 case SHOW_ERROR_MSG: {
946 HashMap data = (HashMap) msg.obj;
947 byte[] crashData = (byte[])data.get("crashData");
948 if (crashData != null) {
949 // This needs to be *un*synchronized to avoid deadlock.
950 ContentResolver resolver = mContext.getContentResolver();
951 Checkin.reportCrash(resolver, crashData);
952 }
953 synchronized (ActivityManagerService.this) {
954 ProcessRecord proc = (ProcessRecord)data.get("app");
955 if (proc != null && proc.crashDialog != null) {
956 Log.e(TAG, "App already has crash dialog: " + proc);
957 return;
958 }
959 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700960 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 Dialog d = new AppErrorDialog(
962 mContext, res, proc,
963 (Integer)data.get("flags"),
964 (String)data.get("shortMsg"),
965 (String)data.get("longMsg"));
966 d.show();
967 proc.crashDialog = d;
968 } else {
969 // The device is asleep, so just pretend that the user
970 // saw a crash dialog and hit "force quit".
971 res.set(0);
972 }
973 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700974
975 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 } break;
977 case SHOW_NOT_RESPONDING_MSG: {
978 synchronized (ActivityManagerService.this) {
979 HashMap data = (HashMap) msg.obj;
980 ProcessRecord proc = (ProcessRecord)data.get("app");
981 if (proc != null && proc.anrDialog != null) {
982 Log.e(TAG, "App already has anr dialog: " + proc);
983 return;
984 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800985
986 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
987 null, null, 0, null, null, null,
988 false, false, MY_PID, Process.SYSTEM_UID);
989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
991 mContext, proc, (HistoryRecord)data.get("activity"));
992 d.show();
993 proc.anrDialog = d;
994 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700995
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700996 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 } break;
998 case SHOW_FACTORY_ERROR_MSG: {
999 Dialog d = new FactoryErrorDialog(
1000 mContext, msg.getData().getCharSequence("msg"));
1001 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001002 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 } break;
1004 case UPDATE_CONFIGURATION_MSG: {
1005 final ContentResolver resolver = mContext.getContentResolver();
1006 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1007 } break;
1008 case GC_BACKGROUND_PROCESSES_MSG: {
1009 synchronized (ActivityManagerService.this) {
1010 performAppGcsIfAppropriateLocked();
1011 }
1012 } break;
1013 case WAIT_FOR_DEBUGGER_MSG: {
1014 synchronized (ActivityManagerService.this) {
1015 ProcessRecord app = (ProcessRecord)msg.obj;
1016 if (msg.arg1 != 0) {
1017 if (!app.waitedForDebugger) {
1018 Dialog d = new AppWaitingForDebuggerDialog(
1019 ActivityManagerService.this,
1020 mContext, app);
1021 app.waitDialog = d;
1022 app.waitedForDebugger = true;
1023 d.show();
1024 }
1025 } else {
1026 if (app.waitDialog != null) {
1027 app.waitDialog.dismiss();
1028 app.waitDialog = null;
1029 }
1030 }
1031 }
1032 } break;
1033 case BROADCAST_INTENT_MSG: {
1034 if (DEBUG_BROADCAST) Log.v(
1035 TAG, "Received BROADCAST_INTENT_MSG");
1036 processNextBroadcast(true);
1037 } break;
1038 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001039 if (mDidDexOpt) {
1040 mDidDexOpt = false;
1041 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1042 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1043 return;
1044 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 broadcastTimeout();
1046 } break;
1047 case PAUSE_TIMEOUT_MSG: {
1048 IBinder token = (IBinder)msg.obj;
1049 // We don't at this point know if the activity is fullscreen,
1050 // so we need to be conservative and assume it isn't.
1051 Log.w(TAG, "Activity pause timeout for " + token);
1052 activityPaused(token, null, true);
1053 } break;
1054 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001055 if (mDidDexOpt) {
1056 mDidDexOpt = false;
1057 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1058 nmsg.obj = msg.obj;
1059 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1060 return;
1061 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 // We don't at this point know if the activity is fullscreen,
1063 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001064 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001066 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 } break;
1068 case DESTROY_TIMEOUT_MSG: {
1069 IBinder token = (IBinder)msg.obj;
1070 // We don't at this point know if the activity is fullscreen,
1071 // so we need to be conservative and assume it isn't.
1072 Log.w(TAG, "Activity destroy timeout for " + token);
1073 activityDestroyed(token);
1074 } break;
1075 case IDLE_NOW_MSG: {
1076 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001077 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 } break;
1079 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001080 if (mDidDexOpt) {
1081 mDidDexOpt = false;
1082 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1083 nmsg.obj = msg.obj;
1084 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1085 return;
1086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 serviceTimeout((ProcessRecord)msg.obj);
1088 } break;
1089 case UPDATE_TIME_ZONE: {
1090 synchronized (ActivityManagerService.this) {
1091 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1092 ProcessRecord r = mLRUProcesses.get(i);
1093 if (r.thread != null) {
1094 try {
1095 r.thread.updateTimeZone();
1096 } catch (RemoteException ex) {
1097 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1098 }
1099 }
1100 }
1101 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001102 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 case SHOW_UID_ERROR_MSG: {
1104 // XXX This is a temporary dialog, no need to localize.
1105 AlertDialog d = new BaseErrorDialog(mContext);
1106 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1107 d.setCancelable(false);
1108 d.setTitle("System UIDs Inconsistent");
1109 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1110 d.setButton("I'm Feeling Lucky",
1111 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1112 mUidAlert = d;
1113 d.show();
1114 } break;
1115 case IM_FEELING_LUCKY_MSG: {
1116 if (mUidAlert != null) {
1117 mUidAlert.dismiss();
1118 mUidAlert = null;
1119 }
1120 } break;
1121 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001122 if (mDidDexOpt) {
1123 mDidDexOpt = false;
1124 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1125 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1126 return;
1127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 synchronized (ActivityManagerService.this) {
1129 if (mLaunchingActivity.isHeld()) {
1130 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1131 mLaunchingActivity.release();
1132 }
1133 }
1134 } break;
1135 case SERVICE_ERROR_MSG: {
1136 ServiceRecord srv = (ServiceRecord)msg.obj;
1137 // This needs to be *un*synchronized to avoid deadlock.
1138 Checkin.logEvent(mContext.getContentResolver(),
1139 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1140 srv.name.toShortString());
1141 } break;
1142 case RESUME_TOP_ACTIVITY_MSG: {
1143 synchronized (ActivityManagerService.this) {
1144 resumeTopActivityLocked(null);
1145 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001146 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001148 if (mDidDexOpt) {
1149 mDidDexOpt = false;
1150 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1151 nmsg.obj = msg.obj;
1152 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1153 return;
1154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 ProcessRecord app = (ProcessRecord)msg.obj;
1156 synchronized (ActivityManagerService.this) {
1157 processStartTimedOutLocked(app);
1158 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001159 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001160 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1161 synchronized (ActivityManagerService.this) {
1162 doPendingActivityLaunchesLocked(true);
1163 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001164 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001165 case KILL_APPLICATION_MSG: {
1166 synchronized (ActivityManagerService.this) {
1167 int uid = msg.arg1;
1168 boolean restart = (msg.arg2 == 1);
1169 String pkg = (String) msg.obj;
1170 uninstallPackageLocked(pkg, uid, restart);
1171 }
1172 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 }
1174 }
1175 };
1176
1177 public static void setSystemProcess() {
1178 try {
1179 ActivityManagerService m = mSelf;
1180
1181 ServiceManager.addService("activity", m);
1182 ServiceManager.addService("meminfo", new MemBinder(m));
1183 if (MONITOR_CPU_USAGE) {
1184 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1185 }
1186 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1187 ServiceManager.addService("activity.services", new ServicesBinder(m));
1188 ServiceManager.addService("activity.senders", new SendersBinder(m));
1189 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1190 ServiceManager.addService("permission", new PermissionController(m));
1191
1192 ApplicationInfo info =
1193 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001194 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001195 mSystemThread.installSystemApplicationInfo(info);
1196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001197 synchronized (mSelf) {
1198 ProcessRecord app = mSelf.newProcessRecordLocked(
1199 mSystemThread.getApplicationThread(), info,
1200 info.processName);
1201 app.persistent = true;
1202 app.pid = Process.myPid();
1203 app.maxAdj = SYSTEM_ADJ;
1204 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1205 synchronized (mSelf.mPidsSelfLocked) {
1206 mSelf.mPidsSelfLocked.put(app.pid, app);
1207 }
1208 mSelf.updateLRUListLocked(app, true);
1209 }
1210 } catch (PackageManager.NameNotFoundException e) {
1211 throw new RuntimeException(
1212 "Unable to find android system package", e);
1213 }
1214 }
1215
1216 public void setWindowManager(WindowManagerService wm) {
1217 mWindowManager = wm;
1218 }
1219
1220 public static final Context main(int factoryTest) {
1221 AThread thr = new AThread();
1222 thr.start();
1223
1224 synchronized (thr) {
1225 while (thr.mService == null) {
1226 try {
1227 thr.wait();
1228 } catch (InterruptedException e) {
1229 }
1230 }
1231 }
1232
1233 ActivityManagerService m = thr.mService;
1234 mSelf = m;
1235 ActivityThread at = ActivityThread.systemMain();
1236 mSystemThread = at;
1237 Context context = at.getSystemContext();
1238 m.mContext = context;
1239 m.mFactoryTest = factoryTest;
1240 PowerManager pm =
1241 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1242 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1243 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1244 m.mLaunchingActivity.setReferenceCounted(false);
1245
1246 m.mBatteryStatsService.publish(context);
1247 m.mUsageStatsService.publish(context);
1248
1249 synchronized (thr) {
1250 thr.mReady = true;
1251 thr.notifyAll();
1252 }
1253
1254 m.startRunning(null, null, null, null);
1255
1256 return context;
1257 }
1258
1259 public static ActivityManagerService self() {
1260 return mSelf;
1261 }
1262
1263 static class AThread extends Thread {
1264 ActivityManagerService mService;
1265 boolean mReady = false;
1266
1267 public AThread() {
1268 super("ActivityManager");
1269 }
1270
1271 public void run() {
1272 Looper.prepare();
1273
1274 android.os.Process.setThreadPriority(
1275 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1276
1277 ActivityManagerService m = new ActivityManagerService();
1278
1279 synchronized (this) {
1280 mService = m;
1281 notifyAll();
1282 }
1283
1284 synchronized (this) {
1285 while (!mReady) {
1286 try {
1287 wait();
1288 } catch (InterruptedException e) {
1289 }
1290 }
1291 }
1292
1293 Looper.loop();
1294 }
1295 }
1296
1297 static class BroadcastsBinder extends Binder {
1298 ActivityManagerService mActivityManagerService;
1299 BroadcastsBinder(ActivityManagerService activityManagerService) {
1300 mActivityManagerService = activityManagerService;
1301 }
1302
1303 @Override
1304 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1305 mActivityManagerService.dumpBroadcasts(pw);
1306 }
1307 }
1308
1309 static class ServicesBinder extends Binder {
1310 ActivityManagerService mActivityManagerService;
1311 ServicesBinder(ActivityManagerService activityManagerService) {
1312 mActivityManagerService = activityManagerService;
1313 }
1314
1315 @Override
1316 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1317 mActivityManagerService.dumpServices(pw);
1318 }
1319 }
1320
1321 static class SendersBinder extends Binder {
1322 ActivityManagerService mActivityManagerService;
1323 SendersBinder(ActivityManagerService activityManagerService) {
1324 mActivityManagerService = activityManagerService;
1325 }
1326
1327 @Override
1328 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1329 mActivityManagerService.dumpSenders(pw);
1330 }
1331 }
1332
1333 static class ProvidersBinder extends Binder {
1334 ActivityManagerService mActivityManagerService;
1335 ProvidersBinder(ActivityManagerService activityManagerService) {
1336 mActivityManagerService = activityManagerService;
1337 }
1338
1339 @Override
1340 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1341 mActivityManagerService.dumpProviders(pw);
1342 }
1343 }
1344
1345 static class MemBinder extends Binder {
1346 ActivityManagerService mActivityManagerService;
1347 MemBinder(ActivityManagerService activityManagerService) {
1348 mActivityManagerService = activityManagerService;
1349 }
1350
1351 @Override
1352 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1353 ActivityManagerService service = mActivityManagerService;
1354 ArrayList<ProcessRecord> procs;
1355 synchronized (mActivityManagerService) {
1356 if (args != null && args.length > 0
1357 && args[0].charAt(0) != '-') {
1358 procs = new ArrayList<ProcessRecord>();
1359 int pid = -1;
1360 try {
1361 pid = Integer.parseInt(args[0]);
1362 } catch (NumberFormatException e) {
1363
1364 }
1365 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1366 ProcessRecord proc = service.mLRUProcesses.get(i);
1367 if (proc.pid == pid) {
1368 procs.add(proc);
1369 } else if (proc.processName.equals(args[0])) {
1370 procs.add(proc);
1371 }
1372 }
1373 if (procs.size() <= 0) {
1374 pw.println("No process found for: " + args[0]);
1375 return;
1376 }
1377 } else {
1378 procs = service.mLRUProcesses;
1379 }
1380 }
1381 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1382 }
1383 }
1384
1385 static class CpuBinder extends Binder {
1386 ActivityManagerService mActivityManagerService;
1387 CpuBinder(ActivityManagerService activityManagerService) {
1388 mActivityManagerService = activityManagerService;
1389 }
1390
1391 @Override
1392 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1393 synchronized (mActivityManagerService.mProcessStatsThread) {
1394 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1395 }
1396 }
1397 }
1398
1399 private ActivityManagerService() {
1400 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1401 if (v != null && Integer.getInteger(v) != 0) {
1402 mSimpleProcessManagement = true;
1403 }
1404 v = System.getenv("ANDROID_DEBUG_APP");
1405 if (v != null) {
1406 mSimpleProcessManagement = true;
1407 }
1408
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001409 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 MY_PID = Process.myPid();
1412
1413 File dataDir = Environment.getDataDirectory();
1414 File systemDir = new File(dataDir, "system");
1415 systemDir.mkdirs();
1416 mBatteryStatsService = new BatteryStatsService(new File(
1417 systemDir, "batterystats.bin").toString());
1418 mBatteryStatsService.getActiveStatistics().readLocked();
1419 mBatteryStatsService.getActiveStatistics().writeLocked();
1420
1421 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001422 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423
Jack Palevichb90d28c2009-07-22 15:35:24 -07001424 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1425 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 mConfiguration.makeDefault();
1428 mProcessStats.init();
1429
1430 // Add ourself to the Watchdog monitors.
1431 Watchdog.getInstance().addMonitor(this);
1432
1433 // These values are set in system/rootdir/init.rc on startup.
1434 FOREGROUND_APP_ADJ =
1435 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1436 VISIBLE_APP_ADJ =
1437 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1438 SECONDARY_SERVER_ADJ =
1439 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001440 BACKUP_APP_ADJ =
1441 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001442 HOME_APP_ADJ =
1443 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 HIDDEN_APP_MIN_ADJ =
1445 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1446 CONTENT_PROVIDER_ADJ =
1447 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1448 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1449 EMPTY_APP_ADJ =
1450 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1451 FOREGROUND_APP_MEM =
1452 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1453 VISIBLE_APP_MEM =
1454 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1455 SECONDARY_SERVER_MEM =
1456 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001457 BACKUP_APP_MEM =
1458 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001459 HOME_APP_MEM =
1460 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 HIDDEN_APP_MEM =
1462 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1463 EMPTY_APP_MEM =
1464 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1465
1466 mProcessStatsThread = new Thread("ProcessStats") {
1467 public void run() {
1468 while (true) {
1469 try {
1470 try {
1471 synchronized(this) {
1472 final long now = SystemClock.uptimeMillis();
1473 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1474 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1475 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1476 // + ", write delay=" + nextWriteDelay);
1477 if (nextWriteDelay < nextCpuDelay) {
1478 nextCpuDelay = nextWriteDelay;
1479 }
1480 if (nextCpuDelay > 0) {
1481 this.wait(nextCpuDelay);
1482 }
1483 }
1484 } catch (InterruptedException e) {
1485 }
1486
1487 updateCpuStatsNow();
1488 } catch (Exception e) {
1489 Log.e(TAG, "Unexpected exception collecting process stats", e);
1490 }
1491 }
1492 }
1493 };
1494 mProcessStatsThread.start();
1495 }
1496
1497 @Override
1498 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1499 throws RemoteException {
1500 try {
1501 return super.onTransact(code, data, reply, flags);
1502 } catch (RuntimeException e) {
1503 // The activity manager only throws security exceptions, so let's
1504 // log all others.
1505 if (!(e instanceof SecurityException)) {
1506 Log.e(TAG, "Activity Manager Crash", e);
1507 }
1508 throw e;
1509 }
1510 }
1511
1512 void updateCpuStats() {
1513 synchronized (mProcessStatsThread) {
1514 final long now = SystemClock.uptimeMillis();
1515 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1516 mProcessStatsThread.notify();
1517 }
1518 }
1519 }
1520
1521 void updateCpuStatsNow() {
1522 synchronized (mProcessStatsThread) {
1523 final long now = SystemClock.uptimeMillis();
1524 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 if (MONITOR_CPU_USAGE &&
1527 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1528 mLastCpuTime = now;
1529 haveNewCpuStats = true;
1530 mProcessStats.update();
1531 //Log.i(TAG, mProcessStats.printCurrentState());
1532 //Log.i(TAG, "Total CPU usage: "
1533 // + mProcessStats.getTotalCpuPercent() + "%");
1534
1535 // Log the cpu usage if the property is set.
1536 if ("true".equals(SystemProperties.get("events.cpu"))) {
1537 int user = mProcessStats.getLastUserTime();
1538 int system = mProcessStats.getLastSystemTime();
1539 int iowait = mProcessStats.getLastIoWaitTime();
1540 int irq = mProcessStats.getLastIrqTime();
1541 int softIrq = mProcessStats.getLastSoftIrqTime();
1542 int idle = mProcessStats.getLastIdleTime();
1543
1544 int total = user + system + iowait + irq + softIrq + idle;
1545 if (total == 0) total = 1;
1546
Doug Zongker2bec3d42009-12-04 12:52:44 -08001547 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 ((user+system+iowait+irq+softIrq) * 100) / total,
1549 (user * 100) / total,
1550 (system * 100) / total,
1551 (iowait * 100) / total,
1552 (irq * 100) / total,
1553 (softIrq * 100) / total);
1554 }
1555 }
1556
Amith Yamasanie43530a2009-08-21 13:11:37 -07001557 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001558 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001559 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 synchronized(mPidsSelfLocked) {
1561 if (haveNewCpuStats) {
1562 if (mBatteryStatsService.isOnBattery()) {
1563 final int N = mProcessStats.countWorkingStats();
1564 for (int i=0; i<N; i++) {
1565 ProcessStats.Stats st
1566 = mProcessStats.getWorkingStats(i);
1567 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1568 if (pr != null) {
1569 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1570 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001571 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001572 } else {
1573 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001574 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001575 if (ps != null) {
1576 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001577 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
1580 }
1581 }
1582 }
1583 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1586 mLastWriteTime = now;
1587 mBatteryStatsService.getActiveStatistics().writeLocked();
1588 }
1589 }
1590 }
1591 }
1592
1593 /**
1594 * Initialize the application bind args. These are passed to each
1595 * process when the bindApplication() IPC is sent to the process. They're
1596 * lazily setup to make sure the services are running when they're asked for.
1597 */
1598 private HashMap<String, IBinder> getCommonServicesLocked() {
1599 if (mAppBindArgs == null) {
1600 mAppBindArgs = new HashMap<String, IBinder>();
1601
1602 // Setup the application init args
1603 mAppBindArgs.put("package", ServiceManager.getService("package"));
1604 mAppBindArgs.put("window", ServiceManager.getService("window"));
1605 mAppBindArgs.put(Context.ALARM_SERVICE,
1606 ServiceManager.getService(Context.ALARM_SERVICE));
1607 }
1608 return mAppBindArgs;
1609 }
1610
1611 private final void setFocusedActivityLocked(HistoryRecord r) {
1612 if (mFocusedActivity != r) {
1613 mFocusedActivity = r;
1614 mWindowManager.setFocusedApp(r, true);
1615 }
1616 }
1617
1618 private final void updateLRUListLocked(ProcessRecord app,
1619 boolean oomAdj) {
1620 // put it on the LRU to keep track of when it should be exited.
1621 int lrui = mLRUProcesses.indexOf(app);
1622 if (lrui >= 0) mLRUProcesses.remove(lrui);
1623 mLRUProcesses.add(app);
1624 //Log.i(TAG, "Putting proc to front: " + app.processName);
1625 if (oomAdj) {
1626 updateOomAdjLocked();
1627 }
1628 }
1629
1630 private final boolean updateLRUListLocked(HistoryRecord r) {
1631 final boolean hadit = mLRUActivities.remove(r);
1632 mLRUActivities.add(r);
1633 return hadit;
1634 }
1635
1636 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1637 int i = mHistory.size()-1;
1638 while (i >= 0) {
1639 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1640 if (!r.finishing && r != notTop) {
1641 return r;
1642 }
1643 i--;
1644 }
1645 return null;
1646 }
1647
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001648 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1649 int i = mHistory.size()-1;
1650 while (i >= 0) {
1651 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1652 if (!r.finishing && !r.delayedResume && r != notTop) {
1653 return r;
1654 }
1655 i--;
1656 }
1657 return null;
1658 }
1659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 /**
1661 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001662 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 *
1664 * @param token If non-null, any history records matching this token will be skipped.
1665 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1666 *
1667 * @return Returns the HistoryRecord of the next activity on the stack.
1668 */
1669 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1670 int i = mHistory.size()-1;
1671 while (i >= 0) {
1672 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1673 // Note: the taskId check depends on real taskId fields being non-zero
1674 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1675 return r;
1676 }
1677 i--;
1678 }
1679 return null;
1680 }
1681
1682 private final ProcessRecord getProcessRecordLocked(
1683 String processName, int uid) {
1684 if (uid == Process.SYSTEM_UID) {
1685 // The system gets to run in any process. If there are multiple
1686 // processes with the same uid, just pick the first (this
1687 // should never happen).
1688 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1689 processName);
1690 return procs != null ? procs.valueAt(0) : null;
1691 }
1692 ProcessRecord proc = mProcessNames.get(processName, uid);
1693 return proc;
1694 }
1695
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001696 private void ensurePackageDexOpt(String packageName) {
1697 IPackageManager pm = ActivityThread.getPackageManager();
1698 try {
1699 if (pm.performDexOpt(packageName)) {
1700 mDidDexOpt = true;
1701 }
1702 } catch (RemoteException e) {
1703 }
1704 }
1705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 private boolean isNextTransitionForward() {
1707 int transit = mWindowManager.getPendingAppTransition();
1708 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1709 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1710 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1711 }
1712
1713 private final boolean realStartActivityLocked(HistoryRecord r,
1714 ProcessRecord app, boolean andResume, boolean checkConfig)
1715 throws RemoteException {
1716
1717 r.startFreezingScreenLocked(app, 0);
1718 mWindowManager.setAppVisibility(r, true);
1719
1720 // Have the window manager re-evaluate the orientation of
1721 // the screen based on the new activity order. Note that
1722 // as a result of this, it can call back into the activity
1723 // manager with a new orientation. We don't care about that,
1724 // because the activity is not currently running so we are
1725 // just restarting it anyway.
1726 if (checkConfig) {
1727 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001728 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 r.mayFreezeScreenLocked(app) ? r : null);
1730 updateConfigurationLocked(config, r);
1731 }
1732
1733 r.app = app;
1734
1735 if (localLOGV) Log.v(TAG, "Launching: " + r);
1736
1737 int idx = app.activities.indexOf(r);
1738 if (idx < 0) {
1739 app.activities.add(r);
1740 }
1741 updateLRUListLocked(app, true);
1742
1743 try {
1744 if (app.thread == null) {
1745 throw new RemoteException();
1746 }
1747 List<ResultInfo> results = null;
1748 List<Intent> newIntents = null;
1749 if (andResume) {
1750 results = r.results;
1751 newIntents = r.newIntents;
1752 }
1753 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1754 + " icicle=" + r.icicle
1755 + " with results=" + results + " newIntents=" + newIntents
1756 + " andResume=" + andResume);
1757 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001758 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 System.identityHashCode(r),
1760 r.task.taskId, r.shortComponentName);
1761 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001762 if (r.isHomeActivity) {
1763 mHomeProcess = app;
1764 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001765 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001767 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 r.info, r.icicle, results, newIntents, !andResume,
1769 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 } catch (RemoteException e) {
1771 if (r.launchFailed) {
1772 // This is the second time we failed -- finish activity
1773 // and give up.
1774 Log.e(TAG, "Second failure launching "
1775 + r.intent.getComponent().flattenToShortString()
1776 + ", giving up", e);
1777 appDiedLocked(app, app.pid, app.thread);
1778 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1779 "2nd-crash");
1780 return false;
1781 }
1782
1783 // This is the first time we failed -- restart process and
1784 // retry.
1785 app.activities.remove(r);
1786 throw e;
1787 }
1788
1789 r.launchFailed = false;
1790 if (updateLRUListLocked(r)) {
1791 Log.w(TAG, "Activity " + r
1792 + " being launched, but already in LRU list");
1793 }
1794
1795 if (andResume) {
1796 // As part of the process of launching, ActivityThread also performs
1797 // a resume.
1798 r.state = ActivityState.RESUMED;
1799 r.icicle = null;
1800 r.haveState = false;
1801 r.stopped = false;
1802 mResumedActivity = r;
1803 r.task.touchActiveTime();
1804 completeResumeLocked(r);
1805 pauseIfSleepingLocked();
1806 } else {
1807 // This activity is not starting in the resumed state... which
1808 // should look like we asked it to pause+stop (but remain visible),
1809 // and it has done so and reported back the current icicle and
1810 // other state.
1811 r.state = ActivityState.STOPPED;
1812 r.stopped = true;
1813 }
1814
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001815 // Launch the new version setup screen if needed. We do this -after-
1816 // launching the initial activity (that is, home), so that it can have
1817 // a chance to initialize itself while in the background, making the
1818 // switch back to it faster and look better.
1819 startSetupActivityLocked();
1820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 return true;
1822 }
1823
1824 private final void startSpecificActivityLocked(HistoryRecord r,
1825 boolean andResume, boolean checkConfig) {
1826 // Is this activity's application already running?
1827 ProcessRecord app = getProcessRecordLocked(r.processName,
1828 r.info.applicationInfo.uid);
1829
1830 if (r.startTime == 0) {
1831 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001832 if (mInitialStartTime == 0) {
1833 mInitialStartTime = r.startTime;
1834 }
1835 } else if (mInitialStartTime == 0) {
1836 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 }
1838
1839 if (app != null && app.thread != null) {
1840 try {
1841 realStartActivityLocked(r, app, andResume, checkConfig);
1842 return;
1843 } catch (RemoteException e) {
1844 Log.w(TAG, "Exception when starting activity "
1845 + r.intent.getComponent().flattenToShortString(), e);
1846 }
1847
1848 // If a dead object exception was thrown -- fall through to
1849 // restart the application.
1850 }
1851
1852 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001853 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 }
1855
1856 private final ProcessRecord startProcessLocked(String processName,
1857 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001858 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1860 // We don't have to do anything more if:
1861 // (1) There is an existing application record; and
1862 // (2) The caller doesn't think it is dead, OR there is no thread
1863 // object attached to it so we know it couldn't have crashed; and
1864 // (3) There is a pid assigned to it, so it is either starting or
1865 // already running.
1866 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1867 + " app=" + app + " knownToBeDead=" + knownToBeDead
1868 + " thread=" + (app != null ? app.thread : null)
1869 + " pid=" + (app != null ? app.pid : -1));
1870 if (app != null &&
1871 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1872 return app;
1873 }
1874
1875 String hostingNameStr = hostingName != null
1876 ? hostingName.flattenToShortString() : null;
1877
1878 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1879 // If we are in the background, then check to see if this process
1880 // is bad. If so, we will just silently fail.
1881 if (mBadProcesses.get(info.processName, info.uid) != null) {
1882 return null;
1883 }
1884 } else {
1885 // When the user is explicitly starting a process, then clear its
1886 // crash count so that we won't make it bad until they see at
1887 // least one crash dialog again, and make the process good again
1888 // if it had been bad.
1889 mProcessCrashTimes.remove(info.processName, info.uid);
1890 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001891 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892 info.processName);
1893 mBadProcesses.remove(info.processName, info.uid);
1894 if (app != null) {
1895 app.bad = false;
1896 }
1897 }
1898 }
1899
1900 if (app == null) {
1901 app = newProcessRecordLocked(null, info, processName);
1902 mProcessNames.put(processName, info.uid, app);
1903 } else {
1904 // If this is a new package in the process, add the package to the list
1905 app.addPackage(info.packageName);
1906 }
1907
1908 // If the system is not ready yet, then hold off on starting this
1909 // process until it is.
1910 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001911 && !isAllowedWhileBooting(info)
1912 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 if (!mProcessesOnHold.contains(app)) {
1914 mProcessesOnHold.add(app);
1915 }
1916 return app;
1917 }
1918
1919 startProcessLocked(app, hostingType, hostingNameStr);
1920 return (app.pid != 0) ? app : null;
1921 }
1922
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001923 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1924 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1925 }
1926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 private final void startProcessLocked(ProcessRecord app,
1928 String hostingType, String hostingNameStr) {
1929 if (app.pid > 0 && app.pid != MY_PID) {
1930 synchronized (mPidsSelfLocked) {
1931 mPidsSelfLocked.remove(app.pid);
1932 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1933 }
1934 app.pid = 0;
1935 }
1936
1937 mProcessesOnHold.remove(app);
1938
1939 updateCpuStats();
1940
1941 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1942 mProcDeaths[0] = 0;
1943
1944 try {
1945 int uid = app.info.uid;
1946 int[] gids = null;
1947 try {
1948 gids = mContext.getPackageManager().getPackageGids(
1949 app.info.packageName);
1950 } catch (PackageManager.NameNotFoundException e) {
1951 Log.w(TAG, "Unable to retrieve gids", e);
1952 }
1953 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1954 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1955 && mTopComponent != null
1956 && app.processName.equals(mTopComponent.getPackageName())) {
1957 uid = 0;
1958 }
1959 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1960 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1961 uid = 0;
1962 }
1963 }
1964 int debugFlags = 0;
1965 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1966 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1967 }
1968 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1969 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1970 }
1971 if ("1".equals(SystemProperties.get("debug.assert"))) {
1972 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1973 }
1974 int pid = Process.start("android.app.ActivityThread",
1975 mSimpleProcessManagement ? app.processName : null, uid, uid,
1976 gids, debugFlags, null);
1977 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1978 synchronized (bs) {
1979 if (bs.isOnBattery()) {
1980 app.batteryStats.incStartsLocked();
1981 }
1982 }
1983
Doug Zongker2bec3d42009-12-04 12:52:44 -08001984 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001985 app.processName, hostingType,
1986 hostingNameStr != null ? hostingNameStr : "");
1987
1988 if (app.persistent) {
1989 Watchdog.getInstance().processStarted(app, app.processName, pid);
1990 }
1991
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001992 StringBuilder buf = mStringBuilder;
1993 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 buf.append("Start proc ");
1995 buf.append(app.processName);
1996 buf.append(" for ");
1997 buf.append(hostingType);
1998 if (hostingNameStr != null) {
1999 buf.append(" ");
2000 buf.append(hostingNameStr);
2001 }
2002 buf.append(": pid=");
2003 buf.append(pid);
2004 buf.append(" uid=");
2005 buf.append(uid);
2006 buf.append(" gids={");
2007 if (gids != null) {
2008 for (int gi=0; gi<gids.length; gi++) {
2009 if (gi != 0) buf.append(", ");
2010 buf.append(gids[gi]);
2011
2012 }
2013 }
2014 buf.append("}");
2015 Log.i(TAG, buf.toString());
2016 if (pid == 0 || pid == MY_PID) {
2017 // Processes are being emulated with threads.
2018 app.pid = MY_PID;
2019 app.removed = false;
2020 mStartingProcesses.add(app);
2021 } else if (pid > 0) {
2022 app.pid = pid;
2023 app.removed = false;
2024 synchronized (mPidsSelfLocked) {
2025 this.mPidsSelfLocked.put(pid, app);
2026 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2027 msg.obj = app;
2028 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2029 }
2030 } else {
2031 app.pid = 0;
2032 RuntimeException e = new RuntimeException(
2033 "Failure starting process " + app.processName
2034 + ": returned pid=" + pid);
2035 Log.e(TAG, e.getMessage(), e);
2036 }
2037 } catch (RuntimeException e) {
2038 // XXX do better error recovery.
2039 app.pid = 0;
2040 Log.e(TAG, "Failure starting process " + app.processName, e);
2041 }
2042 }
2043
2044 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2045 if (mPausingActivity != null) {
2046 RuntimeException e = new RuntimeException();
2047 Log.e(TAG, "Trying to pause when pause is already pending for "
2048 + mPausingActivity, e);
2049 }
2050 HistoryRecord prev = mResumedActivity;
2051 if (prev == null) {
2052 RuntimeException e = new RuntimeException();
2053 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2054 resumeTopActivityLocked(null);
2055 return;
2056 }
2057 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2058 mResumedActivity = null;
2059 mPausingActivity = prev;
2060 mLastPausedActivity = prev;
2061 prev.state = ActivityState.PAUSING;
2062 prev.task.touchActiveTime();
2063
2064 updateCpuStats();
2065
2066 if (prev.app != null && prev.app.thread != null) {
2067 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2068 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002069 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 System.identityHashCode(prev),
2071 prev.shortComponentName);
2072 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2073 prev.configChangeFlags);
2074 updateUsageStats(prev, false);
2075 } catch (Exception e) {
2076 // Ignore exception, if process died other code will cleanup.
2077 Log.w(TAG, "Exception thrown during pause", e);
2078 mPausingActivity = null;
2079 mLastPausedActivity = null;
2080 }
2081 } else {
2082 mPausingActivity = null;
2083 mLastPausedActivity = null;
2084 }
2085
2086 // If we are not going to sleep, we want to ensure the device is
2087 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002088 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 mLaunchingActivity.acquire();
2090 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2091 // To be safe, don't allow the wake lock to be held for too long.
2092 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2093 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2094 }
2095 }
2096
2097
2098 if (mPausingActivity != null) {
2099 // Have the window manager pause its key dispatching until the new
2100 // activity has started. If we're pausing the activity just because
2101 // the screen is being turned off and the UI is sleeping, don't interrupt
2102 // key dispatch; the same activity will pick it up again on wakeup.
2103 if (!uiSleeping) {
2104 prev.pauseKeyDispatchingLocked();
2105 } else {
2106 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2107 }
2108
2109 // Schedule a pause timeout in case the app doesn't respond.
2110 // We don't give it much time because this directly impacts the
2111 // responsiveness seen by the user.
2112 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2113 msg.obj = prev;
2114 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2115 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2116 } else {
2117 // This activity failed to schedule the
2118 // pause, so just treat it as being paused now.
2119 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2120 resumeTopActivityLocked(null);
2121 }
2122 }
2123
2124 private final void completePauseLocked() {
2125 HistoryRecord prev = mPausingActivity;
2126 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2127
2128 if (prev != null) {
2129 if (prev.finishing) {
2130 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2131 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2132 } else if (prev.app != null) {
2133 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2134 if (prev.waitingVisible) {
2135 prev.waitingVisible = false;
2136 mWaitingVisibleActivities.remove(prev);
2137 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2138 TAG, "Complete pause, no longer waiting: " + prev);
2139 }
2140 if (prev.configDestroy) {
2141 // The previous is being paused because the configuration
2142 // is changing, which means it is actually stopping...
2143 // To juggle the fact that we are also starting a new
2144 // instance right now, we need to first completely stop
2145 // the current instance before starting the new one.
2146 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2147 destroyActivityLocked(prev, true);
2148 } else {
2149 mStoppingActivities.add(prev);
2150 if (mStoppingActivities.size() > 3) {
2151 // If we already have a few activities waiting to stop,
2152 // then give up on things going idle and start clearing
2153 // them out.
2154 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2155 Message msg = Message.obtain();
2156 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2157 mHandler.sendMessage(msg);
2158 }
2159 }
2160 } else {
2161 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2162 prev = null;
2163 }
2164 mPausingActivity = null;
2165 }
2166
Dianne Hackborn55280a92009-05-07 15:53:46 -07002167 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002168 resumeTopActivityLocked(prev);
2169 } else {
2170 if (mGoingToSleep.isHeld()) {
2171 mGoingToSleep.release();
2172 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002173 if (mShuttingDown) {
2174 notifyAll();
2175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002176 }
2177
2178 if (prev != null) {
2179 prev.resumeKeyDispatchingLocked();
2180 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002181
2182 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2183 long diff = 0;
2184 synchronized (mProcessStatsThread) {
2185 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2186 }
2187 if (diff > 0) {
2188 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2189 synchronized (bsi) {
2190 BatteryStatsImpl.Uid.Proc ps =
2191 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2192 prev.info.packageName);
2193 if (ps != null) {
2194 ps.addForegroundTimeLocked(diff);
2195 }
2196 }
2197 }
2198 }
2199 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 }
2201
2202 /**
2203 * Once we know that we have asked an application to put an activity in
2204 * the resumed state (either by launching it or explicitly telling it),
2205 * this function updates the rest of our state to match that fact.
2206 */
2207 private final void completeResumeLocked(HistoryRecord next) {
2208 next.idle = false;
2209 next.results = null;
2210 next.newIntents = null;
2211
2212 // schedule an idle timeout in case the app doesn't do it for us.
2213 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2214 msg.obj = next;
2215 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2216
2217 if (false) {
2218 // The activity was never told to pause, so just keep
2219 // things going as-is. To maintain our own state,
2220 // we need to emulate it coming back and saying it is
2221 // idle.
2222 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2223 msg.obj = next;
2224 mHandler.sendMessage(msg);
2225 }
2226
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002227 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002229 next.thumbnail = null;
2230 setFocusedActivityLocked(next);
2231 next.resumeKeyDispatchingLocked();
2232 ensureActivitiesVisibleLocked(null, 0);
2233 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002234 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002235
2236 // Mark the point when the activity is resuming
2237 // TODO: To be more accurate, the mark should be before the onCreate,
2238 // not after the onResume. But for subsequent starts, onResume is fine.
2239 if (next.app != null) {
2240 synchronized (mProcessStatsThread) {
2241 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2242 }
2243 } else {
2244 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2245 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002246 }
2247
2248 /**
2249 * Make sure that all activities that need to be visible (that is, they
2250 * currently can be seen by the user) actually are.
2251 */
2252 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2253 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2254 if (DEBUG_VISBILITY) Log.v(
2255 TAG, "ensureActivitiesVisible behind " + top
2256 + " configChanges=0x" + Integer.toHexString(configChanges));
2257
2258 // If the top activity is not fullscreen, then we need to
2259 // make sure any activities under it are now visible.
2260 final int count = mHistory.size();
2261 int i = count-1;
2262 while (mHistory.get(i) != top) {
2263 i--;
2264 }
2265 HistoryRecord r;
2266 boolean behindFullscreen = false;
2267 for (; i>=0; i--) {
2268 r = (HistoryRecord)mHistory.get(i);
2269 if (DEBUG_VISBILITY) Log.v(
2270 TAG, "Make visible? " + r + " finishing=" + r.finishing
2271 + " state=" + r.state);
2272 if (r.finishing) {
2273 continue;
2274 }
2275
2276 final boolean doThisProcess = onlyThisProcess == null
2277 || onlyThisProcess.equals(r.processName);
2278
2279 // First: if this is not the current activity being started, make
2280 // sure it matches the current configuration.
2281 if (r != starting && doThisProcess) {
2282 ensureActivityConfigurationLocked(r, 0);
2283 }
2284
2285 if (r.app == null || r.app.thread == null) {
2286 if (onlyThisProcess == null
2287 || onlyThisProcess.equals(r.processName)) {
2288 // This activity needs to be visible, but isn't even
2289 // running... get it started, but don't resume it
2290 // at this point.
2291 if (DEBUG_VISBILITY) Log.v(
2292 TAG, "Start and freeze screen for " + r);
2293 if (r != starting) {
2294 r.startFreezingScreenLocked(r.app, configChanges);
2295 }
2296 if (!r.visible) {
2297 if (DEBUG_VISBILITY) Log.v(
2298 TAG, "Starting and making visible: " + r);
2299 mWindowManager.setAppVisibility(r, true);
2300 }
2301 if (r != starting) {
2302 startSpecificActivityLocked(r, false, false);
2303 }
2304 }
2305
2306 } else if (r.visible) {
2307 // If this activity is already visible, then there is nothing
2308 // else to do here.
2309 if (DEBUG_VISBILITY) Log.v(
2310 TAG, "Skipping: already visible at " + r);
2311 r.stopFreezingScreenLocked(false);
2312
2313 } else if (onlyThisProcess == null) {
2314 // This activity is not currently visible, but is running.
2315 // Tell it to become visible.
2316 r.visible = true;
2317 if (r.state != ActivityState.RESUMED && r != starting) {
2318 // If this activity is paused, tell it
2319 // to now show its window.
2320 if (DEBUG_VISBILITY) Log.v(
2321 TAG, "Making visible and scheduling visibility: " + r);
2322 try {
2323 mWindowManager.setAppVisibility(r, true);
2324 r.app.thread.scheduleWindowVisibility(r, true);
2325 r.stopFreezingScreenLocked(false);
2326 } catch (Exception e) {
2327 // Just skip on any failure; we'll make it
2328 // visible when it next restarts.
2329 Log.w(TAG, "Exception thrown making visibile: "
2330 + r.intent.getComponent(), e);
2331 }
2332 }
2333 }
2334
2335 // Aggregate current change flags.
2336 configChanges |= r.configChangeFlags;
2337
2338 if (r.fullscreen) {
2339 // At this point, nothing else needs to be shown
2340 if (DEBUG_VISBILITY) Log.v(
2341 TAG, "Stopping: fullscreen at " + r);
2342 behindFullscreen = true;
2343 i--;
2344 break;
2345 }
2346 }
2347
2348 // Now for any activities that aren't visible to the user, make
2349 // sure they no longer are keeping the screen frozen.
2350 while (i >= 0) {
2351 r = (HistoryRecord)mHistory.get(i);
2352 if (DEBUG_VISBILITY) Log.v(
2353 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2354 + " state=" + r.state
2355 + " behindFullscreen=" + behindFullscreen);
2356 if (!r.finishing) {
2357 if (behindFullscreen) {
2358 if (r.visible) {
2359 if (DEBUG_VISBILITY) Log.v(
2360 TAG, "Making invisible: " + r);
2361 r.visible = false;
2362 try {
2363 mWindowManager.setAppVisibility(r, false);
2364 if ((r.state == ActivityState.STOPPING
2365 || r.state == ActivityState.STOPPED)
2366 && r.app != null && r.app.thread != null) {
2367 if (DEBUG_VISBILITY) Log.v(
2368 TAG, "Scheduling invisibility: " + r);
2369 r.app.thread.scheduleWindowVisibility(r, false);
2370 }
2371 } catch (Exception e) {
2372 // Just skip on any failure; we'll make it
2373 // visible when it next restarts.
2374 Log.w(TAG, "Exception thrown making hidden: "
2375 + r.intent.getComponent(), e);
2376 }
2377 } else {
2378 if (DEBUG_VISBILITY) Log.v(
2379 TAG, "Already invisible: " + r);
2380 }
2381 } else if (r.fullscreen) {
2382 if (DEBUG_VISBILITY) Log.v(
2383 TAG, "Now behindFullscreen: " + r);
2384 behindFullscreen = true;
2385 }
2386 }
2387 i--;
2388 }
2389 }
2390
2391 /**
2392 * Version of ensureActivitiesVisible that can easily be called anywhere.
2393 */
2394 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2395 int configChanges) {
2396 HistoryRecord r = topRunningActivityLocked(null);
2397 if (r != null) {
2398 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2399 }
2400 }
2401
2402 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2403 if (resumed) {
2404 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2405 } else {
2406 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2407 }
2408 }
2409
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002410 private boolean startHomeActivityLocked() {
2411 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2412 && mTopAction == null) {
2413 // We are running in factory test mode, but unable to find
2414 // the factory test app, so just sit around displaying the
2415 // error message and don't try to start anything.
2416 return false;
2417 }
2418 Intent intent = new Intent(
2419 mTopAction,
2420 mTopData != null ? Uri.parse(mTopData) : null);
2421 intent.setComponent(mTopComponent);
2422 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2423 intent.addCategory(Intent.CATEGORY_HOME);
2424 }
2425 ActivityInfo aInfo =
2426 intent.resolveActivityInfo(mContext.getPackageManager(),
2427 STOCK_PM_FLAGS);
2428 if (aInfo != null) {
2429 intent.setComponent(new ComponentName(
2430 aInfo.applicationInfo.packageName, aInfo.name));
2431 // Don't do this if the home app is currently being
2432 // instrumented.
2433 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2434 aInfo.applicationInfo.uid);
2435 if (app == null || app.instrumentationClass == null) {
2436 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2437 startActivityLocked(null, intent, null, null, 0, aInfo,
2438 null, null, 0, 0, 0, false, false);
2439 }
2440 }
2441
2442
2443 return true;
2444 }
2445
2446 /**
2447 * Starts the "new version setup screen" if appropriate.
2448 */
2449 private void startSetupActivityLocked() {
2450 // Only do this once per boot.
2451 if (mCheckedForSetup) {
2452 return;
2453 }
2454
2455 // We will show this screen if the current one is a different
2456 // version than the last one shown, and we are not running in
2457 // low-level factory test mode.
2458 final ContentResolver resolver = mContext.getContentResolver();
2459 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2460 Settings.Secure.getInt(resolver,
2461 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2462 mCheckedForSetup = true;
2463
2464 // See if we should be showing the platform update setup UI.
2465 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2466 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2467 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2468
2469 // We don't allow third party apps to replace this.
2470 ResolveInfo ri = null;
2471 for (int i=0; ris != null && i<ris.size(); i++) {
2472 if ((ris.get(i).activityInfo.applicationInfo.flags
2473 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2474 ri = ris.get(i);
2475 break;
2476 }
2477 }
2478
2479 if (ri != null) {
2480 String vers = ri.activityInfo.metaData != null
2481 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2482 : null;
2483 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2484 vers = ri.activityInfo.applicationInfo.metaData.getString(
2485 Intent.METADATA_SETUP_VERSION);
2486 }
2487 String lastVers = Settings.Secure.getString(
2488 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2489 if (vers != null && !vers.equals(lastVers)) {
2490 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2491 intent.setComponent(new ComponentName(
2492 ri.activityInfo.packageName, ri.activityInfo.name));
2493 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2494 null, null, 0, 0, 0, false, false);
2495 }
2496 }
2497 }
2498 }
2499
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002500 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002501 //Log.i(TAG, "**** REPORT RESUME: " + r);
2502
2503 final int identHash = System.identityHashCode(r);
2504 updateUsageStats(r, true);
2505
2506 int i = mWatchers.beginBroadcast();
2507 while (i > 0) {
2508 i--;
2509 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2510 if (w != null) {
2511 try {
2512 w.activityResuming(identHash);
2513 } catch (RemoteException e) {
2514 }
2515 }
2516 }
2517 mWatchers.finishBroadcast();
2518 }
2519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002520 /**
2521 * Ensure that the top activity in the stack is resumed.
2522 *
2523 * @param prev The previously resumed activity, for when in the process
2524 * of pausing; can be null to call from elsewhere.
2525 *
2526 * @return Returns true if something is being resumed, or false if
2527 * nothing happened.
2528 */
2529 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2530 // Find the first activity that is not finishing.
2531 HistoryRecord next = topRunningActivityLocked(null);
2532
2533 // Remember how we'll process this pause/resume situation, and ensure
2534 // that the state is reset however we wind up proceeding.
2535 final boolean userLeaving = mUserLeaving;
2536 mUserLeaving = false;
2537
2538 if (next == null) {
2539 // There are no more activities! Let's just start up the
2540 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002541 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 }
2543
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002544 next.delayedResume = false;
2545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 // If the top activity is the resumed one, nothing to do.
2547 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2548 // Make sure we have executed any pending transitions, since there
2549 // should be nothing left to do at this point.
2550 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002551 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002552 return false;
2553 }
2554
2555 // If we are sleeping, and there is no resumed activity, and the top
2556 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002557 if ((mSleeping || mShuttingDown)
2558 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 // Make sure we have executed any pending transitions, since there
2560 // should be nothing left to do at this point.
2561 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002562 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002563 return false;
2564 }
2565
2566 // The activity may be waiting for stop, but that is no longer
2567 // appropriate for it.
2568 mStoppingActivities.remove(next);
2569 mWaitingVisibleActivities.remove(next);
2570
2571 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2572
2573 // If we are currently pausing an activity, then don't do anything
2574 // until that is done.
2575 if (mPausingActivity != null) {
2576 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2577 return false;
2578 }
2579
2580 // We need to start pausing the current activity so the top one
2581 // can be resumed...
2582 if (mResumedActivity != null) {
2583 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2584 startPausingLocked(userLeaving, false);
2585 return true;
2586 }
2587
2588 if (prev != null && prev != next) {
2589 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2590 prev.waitingVisible = true;
2591 mWaitingVisibleActivities.add(prev);
2592 if (DEBUG_SWITCH) Log.v(
2593 TAG, "Resuming top, waiting visible to hide: " + prev);
2594 } else {
2595 // The next activity is already visible, so hide the previous
2596 // activity's windows right now so we can show the new one ASAP.
2597 // We only do this if the previous is finishing, which should mean
2598 // it is on top of the one being resumed so hiding it quickly
2599 // is good. Otherwise, we want to do the normal route of allowing
2600 // the resumed activity to be shown so we can decide if the
2601 // previous should actually be hidden depending on whether the
2602 // new one is found to be full-screen or not.
2603 if (prev.finishing) {
2604 mWindowManager.setAppVisibility(prev, false);
2605 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2606 + prev + ", waitingVisible="
2607 + (prev != null ? prev.waitingVisible : null)
2608 + ", nowVisible=" + next.nowVisible);
2609 } else {
2610 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2611 + prev + ", waitingVisible="
2612 + (prev != null ? prev.waitingVisible : null)
2613 + ", nowVisible=" + next.nowVisible);
2614 }
2615 }
2616 }
2617
2618 // We are starting up the next activity, so tell the window manager
2619 // that the previous one will be hidden soon. This way it can know
2620 // to ignore it when computing the desired screen orientation.
2621 if (prev != null) {
2622 if (prev.finishing) {
2623 if (DEBUG_TRANSITION) Log.v(TAG,
2624 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002625 if (mNoAnimActivities.contains(prev)) {
2626 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2627 } else {
2628 mWindowManager.prepareAppTransition(prev.task == next.task
2629 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2630 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002632 mWindowManager.setAppWillBeHidden(prev);
2633 mWindowManager.setAppVisibility(prev, false);
2634 } else {
2635 if (DEBUG_TRANSITION) Log.v(TAG,
2636 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002637 if (mNoAnimActivities.contains(next)) {
2638 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2639 } else {
2640 mWindowManager.prepareAppTransition(prev.task == next.task
2641 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2642 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 }
2645 if (false) {
2646 mWindowManager.setAppWillBeHidden(prev);
2647 mWindowManager.setAppVisibility(prev, false);
2648 }
2649 } else if (mHistory.size() > 1) {
2650 if (DEBUG_TRANSITION) Log.v(TAG,
2651 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002652 if (mNoAnimActivities.contains(next)) {
2653 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2654 } else {
2655 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 }
2658
2659 if (next.app != null && next.app.thread != null) {
2660 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2661
2662 // This activity is now becoming visible.
2663 mWindowManager.setAppVisibility(next, true);
2664
2665 HistoryRecord lastResumedActivity = mResumedActivity;
2666 ActivityState lastState = next.state;
2667
2668 updateCpuStats();
2669
2670 next.state = ActivityState.RESUMED;
2671 mResumedActivity = next;
2672 next.task.touchActiveTime();
2673 updateLRUListLocked(next.app, true);
2674 updateLRUListLocked(next);
2675
2676 // Have the window manager re-evaluate the orientation of
2677 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002678 boolean updated;
2679 synchronized (this) {
2680 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2681 mConfiguration,
2682 next.mayFreezeScreenLocked(next.app) ? next : null);
2683 if (config != null) {
2684 /*
2685 * Explicitly restore the locale to the one from the
2686 * old configuration, since the one that comes back from
2687 * the window manager has the default (boot) locale.
2688 *
2689 * It looks like previously the locale picker only worked
2690 * by coincidence: usually it would do its setting of
2691 * the locale after the activity transition, so it didn't
2692 * matter that this lost it. With the synchronized
2693 * block now keeping them from happening at the same time,
2694 * this one always would happen second and undo what the
2695 * locale picker had just done.
2696 */
2697 config.locale = mConfiguration.locale;
2698 next.frozenBeforeDestroy = true;
2699 }
2700 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002702 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 // The configuration update wasn't able to keep the existing
2704 // instance of the activity, and instead started a new one.
2705 // We should be all done, but let's just make sure our activity
2706 // is still at the top and schedule another run if something
2707 // weird happened.
2708 HistoryRecord nextNext = topRunningActivityLocked(null);
2709 if (DEBUG_SWITCH) Log.i(TAG,
2710 "Activity config changed during resume: " + next
2711 + ", new next: " + nextNext);
2712 if (nextNext != next) {
2713 // Do over!
2714 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2715 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002716 setFocusedActivityLocked(next);
2717 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002718 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002719 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720 return true;
2721 }
2722
2723 try {
2724 // Deliver all pending results.
2725 ArrayList a = next.results;
2726 if (a != null) {
2727 final int N = a.size();
2728 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002729 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 TAG, "Delivering results to " + next
2731 + ": " + a);
2732 next.app.thread.scheduleSendResult(next, a);
2733 }
2734 }
2735
2736 if (next.newIntents != null) {
2737 next.app.thread.scheduleNewIntent(next.newIntents, next);
2738 }
2739
Doug Zongker2bec3d42009-12-04 12:52:44 -08002740 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002741 System.identityHashCode(next),
2742 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002743
2744 next.app.thread.scheduleResumeActivity(next,
2745 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002747 pauseIfSleepingLocked();
2748
2749 } catch (Exception e) {
2750 // Whoops, need to restart this activity!
2751 next.state = lastState;
2752 mResumedActivity = lastResumedActivity;
2753 if (Config.LOGD) Log.d(TAG,
2754 "Restarting because process died: " + next);
2755 if (!next.hasBeenLaunched) {
2756 next.hasBeenLaunched = true;
2757 } else {
2758 if (SHOW_APP_STARTING_ICON) {
2759 mWindowManager.setAppStartingWindow(
2760 next, next.packageName, next.theme,
2761 next.nonLocalizedLabel,
2762 next.labelRes, next.icon, null, true);
2763 }
2764 }
2765 startSpecificActivityLocked(next, true, false);
2766 return true;
2767 }
2768
2769 // From this point on, if something goes wrong there is no way
2770 // to recover the activity.
2771 try {
2772 next.visible = true;
2773 completeResumeLocked(next);
2774 } catch (Exception e) {
2775 // If any exception gets thrown, toss away this
2776 // activity and try the next one.
2777 Log.w(TAG, "Exception thrown during resume of " + next, e);
2778 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2779 "resume-exception");
2780 return true;
2781 }
2782
2783 // Didn't need to use the icicle, and it is now out of date.
2784 next.icicle = null;
2785 next.haveState = false;
2786 next.stopped = false;
2787
2788 } else {
2789 // Whoops, need to restart this activity!
2790 if (!next.hasBeenLaunched) {
2791 next.hasBeenLaunched = true;
2792 } else {
2793 if (SHOW_APP_STARTING_ICON) {
2794 mWindowManager.setAppStartingWindow(
2795 next, next.packageName, next.theme,
2796 next.nonLocalizedLabel,
2797 next.labelRes, next.icon, null, true);
2798 }
2799 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2800 }
2801 startSpecificActivityLocked(next, true, true);
2802 }
2803
2804 return true;
2805 }
2806
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002807 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2808 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002809 final int NH = mHistory.size();
2810
2811 int addPos = -1;
2812
2813 if (!newTask) {
2814 // If starting in an existing task, find where that is...
2815 HistoryRecord next = null;
2816 boolean startIt = true;
2817 for (int i = NH-1; i >= 0; i--) {
2818 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2819 if (p.finishing) {
2820 continue;
2821 }
2822 if (p.task == r.task) {
2823 // Here it is! Now, if this is not yet visible to the
2824 // user, then just add it without starting; it will
2825 // get started when the user navigates back to it.
2826 addPos = i+1;
2827 if (!startIt) {
2828 mHistory.add(addPos, r);
2829 r.inHistory = true;
2830 r.task.numActivities++;
2831 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2832 r.info.screenOrientation, r.fullscreen);
2833 if (VALIDATE_TOKENS) {
2834 mWindowManager.validateAppTokens(mHistory);
2835 }
2836 return;
2837 }
2838 break;
2839 }
2840 if (p.fullscreen) {
2841 startIt = false;
2842 }
2843 next = p;
2844 }
2845 }
2846
2847 // Place a new activity at top of stack, so it is next to interact
2848 // with the user.
2849 if (addPos < 0) {
2850 addPos = mHistory.size();
2851 }
2852
2853 // If we are not placing the new activity frontmost, we do not want
2854 // to deliver the onUserLeaving callback to the actual frontmost
2855 // activity
2856 if (addPos < NH) {
2857 mUserLeaving = false;
2858 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2859 }
2860
2861 // Slot the activity into the history stack and proceed
2862 mHistory.add(addPos, r);
2863 r.inHistory = true;
2864 r.frontOfTask = newTask;
2865 r.task.numActivities++;
2866 if (NH > 0) {
2867 // We want to show the starting preview window if we are
2868 // switching to a new task, or the next activity's process is
2869 // not currently running.
2870 boolean showStartingIcon = newTask;
2871 ProcessRecord proc = r.app;
2872 if (proc == null) {
2873 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2874 }
2875 if (proc == null || proc.thread == null) {
2876 showStartingIcon = true;
2877 }
2878 if (DEBUG_TRANSITION) Log.v(TAG,
2879 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002880 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2881 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2882 mNoAnimActivities.add(r);
2883 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2884 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2885 mNoAnimActivities.remove(r);
2886 } else {
2887 mWindowManager.prepareAppTransition(newTask
2888 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2889 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2890 mNoAnimActivities.remove(r);
2891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002892 mWindowManager.addAppToken(
2893 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2894 boolean doShow = true;
2895 if (newTask) {
2896 // Even though this activity is starting fresh, we still need
2897 // to reset it to make sure we apply affinities to move any
2898 // existing activities from other tasks in to it.
2899 // If the caller has requested that the target task be
2900 // reset, then do so.
2901 if ((r.intent.getFlags()
2902 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2903 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002904 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002905 }
2906 }
2907 if (SHOW_APP_STARTING_ICON && doShow) {
2908 // Figure out if we are transitioning from another activity that is
2909 // "has the same starting icon" as the next one. This allows the
2910 // window manager to keep the previous window it had previously
2911 // created, if it still had one.
2912 HistoryRecord prev = mResumedActivity;
2913 if (prev != null) {
2914 // We don't want to reuse the previous starting preview if:
2915 // (1) The current activity is in a different task.
2916 if (prev.task != r.task) prev = null;
2917 // (2) The current activity is already displayed.
2918 else if (prev.nowVisible) prev = null;
2919 }
2920 mWindowManager.setAppStartingWindow(
2921 r, r.packageName, r.theme, r.nonLocalizedLabel,
2922 r.labelRes, r.icon, prev, showStartingIcon);
2923 }
2924 } else {
2925 // If this is the first activity, don't do any fancy animations,
2926 // because there is nothing for it to animate on top of.
2927 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2928 r.info.screenOrientation, r.fullscreen);
2929 }
2930 if (VALIDATE_TOKENS) {
2931 mWindowManager.validateAppTokens(mHistory);
2932 }
2933
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002934 if (doResume) {
2935 resumeTopActivityLocked(null);
2936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002937 }
2938
2939 /**
2940 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002941 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2942 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002943 * an instance of that activity in the stack and, if found, finish all
2944 * activities on top of it and return the instance.
2945 *
2946 * @param newR Description of the new activity being started.
2947 * @return Returns the old activity that should be continue to be used,
2948 * or null if none was found.
2949 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002950 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002951 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002953
2954 // First find the requested task.
2955 while (i > 0) {
2956 i--;
2957 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2958 if (r.task.taskId == taskId) {
2959 i++;
2960 break;
2961 }
2962 }
2963
2964 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002965 while (i > 0) {
2966 i--;
2967 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2968 if (r.finishing) {
2969 continue;
2970 }
2971 if (r.task.taskId != taskId) {
2972 return null;
2973 }
2974 if (r.realActivity.equals(newR.realActivity)) {
2975 // Here it is! Now finish everything in front...
2976 HistoryRecord ret = r;
2977 if (doClear) {
2978 while (i < (mHistory.size()-1)) {
2979 i++;
2980 r = (HistoryRecord)mHistory.get(i);
2981 if (r.finishing) {
2982 continue;
2983 }
2984 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2985 null, "clear")) {
2986 i--;
2987 }
2988 }
2989 }
2990
2991 // Finally, if this is a normal launch mode (that is, not
2992 // expecting onNewIntent()), then we will finish the current
2993 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002994 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2995 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002996 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002997 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 if (index >= 0) {
2999 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3000 null, "clear");
3001 }
3002 return null;
3003 }
3004 }
3005
3006 return ret;
3007 }
3008 }
3009
3010 return null;
3011 }
3012
3013 /**
3014 * Find the activity in the history stack within the given task. Returns
3015 * the index within the history at which it's found, or < 0 if not found.
3016 */
3017 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3018 int i = mHistory.size();
3019 while (i > 0) {
3020 i--;
3021 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3022 if (candidate.task.taskId != task) {
3023 break;
3024 }
3025 if (candidate.realActivity.equals(r.realActivity)) {
3026 return i;
3027 }
3028 }
3029
3030 return -1;
3031 }
3032
3033 /**
3034 * Reorder the history stack so that the activity at the given index is
3035 * brought to the front.
3036 */
3037 private final HistoryRecord moveActivityToFrontLocked(int where) {
3038 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3039 int top = mHistory.size();
3040 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3041 mHistory.add(top, newTop);
3042 oldTop.frontOfTask = false;
3043 newTop.frontOfTask = true;
3044 return newTop;
3045 }
3046
3047 /**
3048 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3049 * method will be called at the proper time.
3050 */
3051 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3052 boolean sent = false;
3053 if (r.state == ActivityState.RESUMED
3054 && r.app != null && r.app.thread != null) {
3055 try {
3056 ArrayList<Intent> ar = new ArrayList<Intent>();
3057 ar.add(new Intent(intent));
3058 r.app.thread.scheduleNewIntent(ar, r);
3059 sent = true;
3060 } catch (Exception e) {
3061 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3062 }
3063 }
3064 if (!sent) {
3065 r.addNewIntentLocked(new Intent(intent));
3066 }
3067 }
3068
3069 private final void logStartActivity(int tag, HistoryRecord r,
3070 TaskRecord task) {
3071 EventLog.writeEvent(tag,
3072 System.identityHashCode(r), task.taskId,
3073 r.shortComponentName, r.intent.getAction(),
3074 r.intent.getType(), r.intent.getDataString(),
3075 r.intent.getFlags());
3076 }
3077
3078 private final int startActivityLocked(IApplicationThread caller,
3079 Intent intent, String resolvedType,
3080 Uri[] grantedUriPermissions,
3081 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3082 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003083 int callingPid, int callingUid, boolean onlyIfNeeded,
3084 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003085 Log.i(TAG, "Starting activity: " + intent);
3086
3087 HistoryRecord sourceRecord = null;
3088 HistoryRecord resultRecord = null;
3089 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003090 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003091 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3093 if (index >= 0) {
3094 sourceRecord = (HistoryRecord)mHistory.get(index);
3095 if (requestCode >= 0 && !sourceRecord.finishing) {
3096 resultRecord = sourceRecord;
3097 }
3098 }
3099 }
3100
3101 int launchFlags = intent.getFlags();
3102
3103 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3104 && sourceRecord != null) {
3105 // Transfer the result target from the source activity to the new
3106 // one being started, including any failures.
3107 if (requestCode >= 0) {
3108 return START_FORWARD_AND_REQUEST_CONFLICT;
3109 }
3110 resultRecord = sourceRecord.resultTo;
3111 resultWho = sourceRecord.resultWho;
3112 requestCode = sourceRecord.requestCode;
3113 sourceRecord.resultTo = null;
3114 if (resultRecord != null) {
3115 resultRecord.removeResultsLocked(
3116 sourceRecord, resultWho, requestCode);
3117 }
3118 }
3119
3120 int err = START_SUCCESS;
3121
3122 if (intent.getComponent() == null) {
3123 // We couldn't find a class that can handle the given Intent.
3124 // That's the end of that!
3125 err = START_INTENT_NOT_RESOLVED;
3126 }
3127
3128 if (err == START_SUCCESS && aInfo == null) {
3129 // We couldn't find the specific class specified in the Intent.
3130 // Also the end of the line.
3131 err = START_CLASS_NOT_FOUND;
3132 }
3133
3134 ProcessRecord callerApp = null;
3135 if (err == START_SUCCESS && caller != null) {
3136 callerApp = getRecordForAppLocked(caller);
3137 if (callerApp != null) {
3138 callingPid = callerApp.pid;
3139 callingUid = callerApp.info.uid;
3140 } else {
3141 Log.w(TAG, "Unable to find app for caller " + caller
3142 + " (pid=" + callingPid + ") when starting: "
3143 + intent.toString());
3144 err = START_PERMISSION_DENIED;
3145 }
3146 }
3147
3148 if (err != START_SUCCESS) {
3149 if (resultRecord != null) {
3150 sendActivityResultLocked(-1,
3151 resultRecord, resultWho, requestCode,
3152 Activity.RESULT_CANCELED, null);
3153 }
3154 return err;
3155 }
3156
3157 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3158 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3159 if (perm != PackageManager.PERMISSION_GRANTED) {
3160 if (resultRecord != null) {
3161 sendActivityResultLocked(-1,
3162 resultRecord, resultWho, requestCode,
3163 Activity.RESULT_CANCELED, null);
3164 }
3165 String msg = "Permission Denial: starting " + intent.toString()
3166 + " from " + callerApp + " (pid=" + callingPid
3167 + ", uid=" + callingUid + ")"
3168 + " requires " + aInfo.permission;
3169 Log.w(TAG, msg);
3170 throw new SecurityException(msg);
3171 }
3172
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003173 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003174 boolean abort = false;
3175 try {
3176 // The Intent we give to the watcher has the extra data
3177 // stripped off, since it can contain private information.
3178 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003179 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003180 aInfo.applicationInfo.packageName);
3181 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003182 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 }
3184
3185 if (abort) {
3186 if (resultRecord != null) {
3187 sendActivityResultLocked(-1,
3188 resultRecord, resultWho, requestCode,
3189 Activity.RESULT_CANCELED, null);
3190 }
3191 // We pretend to the caller that it was really started, but
3192 // they will just get a cancel result.
3193 return START_SUCCESS;
3194 }
3195 }
3196
3197 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3198 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003199 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003201 if (mResumedActivity == null
3202 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3203 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3204 PendingActivityLaunch pal = new PendingActivityLaunch();
3205 pal.r = r;
3206 pal.sourceRecord = sourceRecord;
3207 pal.grantedUriPermissions = grantedUriPermissions;
3208 pal.grantedMode = grantedMode;
3209 pal.onlyIfNeeded = onlyIfNeeded;
3210 mPendingActivityLaunches.add(pal);
3211 return START_SWITCHES_CANCELED;
3212 }
3213 }
3214
3215 if (mDidAppSwitch) {
3216 // This is the second allowed switch since we stopped switches,
3217 // so now just generally allow switches. Use case: user presses
3218 // home (switches disabled, switch to home, mDidAppSwitch now true);
3219 // user taps a home icon (coming from home so allowed, we hit here
3220 // and now allow anyone to switch again).
3221 mAppSwitchesAllowedTime = 0;
3222 } else {
3223 mDidAppSwitch = true;
3224 }
3225
3226 doPendingActivityLaunchesLocked(false);
3227
3228 return startActivityUncheckedLocked(r, sourceRecord,
3229 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3230 }
3231
3232 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3233 final int N = mPendingActivityLaunches.size();
3234 if (N <= 0) {
3235 return;
3236 }
3237 for (int i=0; i<N; i++) {
3238 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3239 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3240 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3241 doResume && i == (N-1));
3242 }
3243 mPendingActivityLaunches.clear();
3244 }
3245
3246 private final int startActivityUncheckedLocked(HistoryRecord r,
3247 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3248 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3249 final Intent intent = r.intent;
3250 final int callingUid = r.launchedFromUid;
3251
3252 int launchFlags = intent.getFlags();
3253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 // We'll invoke onUserLeaving before onPause only if the launching
3255 // activity did not explicitly state that this is an automated launch.
3256 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3257 if (DEBUG_USER_LEAVING) Log.v(TAG,
3258 "startActivity() => mUserLeaving=" + mUserLeaving);
3259
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003260 // If the caller has asked not to resume at this point, we make note
3261 // of this in the record so that we can skip it when trying to find
3262 // the top running activity.
3263 if (!doResume) {
3264 r.delayedResume = true;
3265 }
3266
3267 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3268 != 0 ? r : null;
3269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003270 // If the onlyIfNeeded flag is set, then we can do this if the activity
3271 // being launched is the same as the one making the call... or, as
3272 // a special case, if we do not know the caller then we count the
3273 // current top activity as the caller.
3274 if (onlyIfNeeded) {
3275 HistoryRecord checkedCaller = sourceRecord;
3276 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003277 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003278 }
3279 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3280 // Caller is not the same as launcher, so always needed.
3281 onlyIfNeeded = false;
3282 }
3283 }
3284
3285 if (grantedUriPermissions != null && callingUid > 0) {
3286 for (int i=0; i<grantedUriPermissions.length; i++) {
3287 grantUriPermissionLocked(callingUid, r.packageName,
3288 grantedUriPermissions[i], grantedMode, r);
3289 }
3290 }
3291
3292 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3293 intent, r);
3294
3295 if (sourceRecord == null) {
3296 // This activity is not being started from another... in this
3297 // case we -always- start a new task.
3298 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3299 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3300 + intent);
3301 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3302 }
3303 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3304 // The original activity who is starting us is running as a single
3305 // instance... this new activity it is starting must go on its
3306 // own task.
3307 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3308 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3309 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3310 // The activity being started is a single instance... it always
3311 // gets launched into its own task.
3312 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3313 }
3314
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003315 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 // For whatever reason this activity is being launched into a new
3317 // task... yet the caller has requested a result back. Well, that
3318 // is pretty messed up, so instead immediately send back a cancel
3319 // and let the new task continue launched as normal without a
3320 // dependency on its originator.
3321 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3322 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003323 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 Activity.RESULT_CANCELED, null);
3325 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 }
3327
3328 boolean addingToTask = false;
3329 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3330 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3331 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3332 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3333 // If bring to front is requested, and no result is requested, and
3334 // we can find a task that was started with this same
3335 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003336 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003337 // See if there is a task to bring to the front. If this is
3338 // a SINGLE_INSTANCE activity, there can be one and only one
3339 // instance of it in the history, and it is always in its own
3340 // unique task, so we do a special search.
3341 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3342 ? findTaskLocked(intent, r.info)
3343 : findActivityLocked(intent, r.info);
3344 if (taskTop != null) {
3345 if (taskTop.task.intent == null) {
3346 // This task was started because of movement of
3347 // the activity based on affinity... now that we
3348 // are actually launching it, we can assign the
3349 // base intent.
3350 taskTop.task.setIntent(intent, r.info);
3351 }
3352 // If the target task is not in the front, then we need
3353 // to bring it to the front... except... well, with
3354 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3355 // to have the same behavior as if a new instance was
3356 // being started, which means not bringing it to the front
3357 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003358 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 if (curTop.task != taskTop.task) {
3360 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3361 boolean callerAtFront = sourceRecord == null
3362 || curTop.task == sourceRecord.task;
3363 if (callerAtFront) {
3364 // We really do want to push this one into the
3365 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003366 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 }
3368 }
3369 // If the caller has requested that the target task be
3370 // reset, then do so.
3371 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3372 taskTop = resetTaskIfNeededLocked(taskTop, r);
3373 }
3374 if (onlyIfNeeded) {
3375 // We don't need to start a new activity, and
3376 // the client said not to do anything if that
3377 // is the case, so this is it! And for paranoia, make
3378 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003379 if (doResume) {
3380 resumeTopActivityLocked(null);
3381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382 return START_RETURN_INTENT_TO_CALLER;
3383 }
3384 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3385 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3386 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3387 // In this situation we want to remove all activities
3388 // from the task up to the one being started. In most
3389 // cases this means we are resetting the task to its
3390 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003391 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003392 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 if (top != null) {
3394 if (top.frontOfTask) {
3395 // Activity aliases may mean we use different
3396 // intents for the top activity, so make sure
3397 // the task now has the identity of the new
3398 // intent.
3399 top.task.setIntent(r.intent, r.info);
3400 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003401 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 deliverNewIntentLocked(top, r.intent);
3403 } else {
3404 // A special case: we need to
3405 // start the activity because it is not currently
3406 // running, and the caller has asked to clear the
3407 // current task to have this activity at the top.
3408 addingToTask = true;
3409 // Now pretend like this activity is being started
3410 // by the top of its task, so it is put in the
3411 // right place.
3412 sourceRecord = taskTop;
3413 }
3414 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3415 // In this case the top activity on the task is the
3416 // same as the one being launched, so we take that
3417 // as a request to bring the task to the foreground.
3418 // If the top activity in the task is the root
3419 // activity, deliver this new intent to it if it
3420 // desires.
3421 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3422 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003423 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 if (taskTop.frontOfTask) {
3425 taskTop.task.setIntent(r.intent, r.info);
3426 }
3427 deliverNewIntentLocked(taskTop, r.intent);
3428 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3429 // In this case we are launching the root activity
3430 // of the task, but with a different intent. We
3431 // should start a new instance on top.
3432 addingToTask = true;
3433 sourceRecord = taskTop;
3434 }
3435 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3436 // In this case an activity is being launched in to an
3437 // existing task, without resetting that task. This
3438 // is typically the situation of launching an activity
3439 // from a notification or shortcut. We want to place
3440 // the new activity on top of the current task.
3441 addingToTask = true;
3442 sourceRecord = taskTop;
3443 } else if (!taskTop.task.rootWasReset) {
3444 // In this case we are launching in to an existing task
3445 // that has not yet been started from its front door.
3446 // The current task has been brought to the front.
3447 // Ideally, we'd probably like to place this new task
3448 // at the bottom of its stack, but that's a little hard
3449 // to do with the current organization of the code so
3450 // for now we'll just drop it.
3451 taskTop.task.setIntent(r.intent, r.info);
3452 }
3453 if (!addingToTask) {
3454 // We didn't do anything... but it was needed (a.k.a., client
3455 // don't use that intent!) And for paranoia, make
3456 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003457 if (doResume) {
3458 resumeTopActivityLocked(null);
3459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 return START_TASK_TO_FRONT;
3461 }
3462 }
3463 }
3464 }
3465
3466 //String uri = r.intent.toURI();
3467 //Intent intent2 = new Intent(uri);
3468 //Log.i(TAG, "Given intent: " + r.intent);
3469 //Log.i(TAG, "URI is: " + uri);
3470 //Log.i(TAG, "To intent: " + intent2);
3471
3472 if (r.packageName != null) {
3473 // If the activity being launched is the same as the one currently
3474 // at the top, then we need to check if it should only be launched
3475 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003476 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3477 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 if (top.realActivity.equals(r.realActivity)) {
3479 if (top.app != null && top.app.thread != null) {
3480 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3481 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3482 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003483 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 // For paranoia, make sure we have correctly
3485 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003486 if (doResume) {
3487 resumeTopActivityLocked(null);
3488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 if (onlyIfNeeded) {
3490 // We don't need to start a new activity, and
3491 // the client said not to do anything if that
3492 // is the case, so this is it!
3493 return START_RETURN_INTENT_TO_CALLER;
3494 }
3495 deliverNewIntentLocked(top, r.intent);
3496 return START_DELIVERED_TO_TOP;
3497 }
3498 }
3499 }
3500 }
3501
3502 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003503 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003505 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 Activity.RESULT_CANCELED, null);
3507 }
3508 return START_CLASS_NOT_FOUND;
3509 }
3510
3511 boolean newTask = false;
3512
3513 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003514 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3516 // todo: should do better management of integers.
3517 mCurTask++;
3518 if (mCurTask <= 0) {
3519 mCurTask = 1;
3520 }
3521 r.task = new TaskRecord(mCurTask, r.info, intent,
3522 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3523 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3524 + " in new task " + r.task);
3525 newTask = true;
3526 addRecentTask(r.task);
3527
3528 } else if (sourceRecord != null) {
3529 if (!addingToTask &&
3530 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3531 // In this case, we are adding the activity to an existing
3532 // task, but the caller has asked to clear that task if the
3533 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003534 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003535 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003536 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003537 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 deliverNewIntentLocked(top, r.intent);
3539 // For paranoia, make sure we have correctly
3540 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003541 if (doResume) {
3542 resumeTopActivityLocked(null);
3543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003544 return START_DELIVERED_TO_TOP;
3545 }
3546 } else if (!addingToTask &&
3547 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3548 // In this case, we are launching an activity in our own task
3549 // that may already be running somewhere in the history, and
3550 // we want to shuffle it to the front of the stack if so.
3551 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3552 if (where >= 0) {
3553 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003554 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003556 if (doResume) {
3557 resumeTopActivityLocked(null);
3558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003559 return START_DELIVERED_TO_TOP;
3560 }
3561 }
3562 // An existing activity is starting this new activity, so we want
3563 // to keep the new one in the same task as the one that is starting
3564 // it.
3565 r.task = sourceRecord.task;
3566 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3567 + " in existing task " + r.task);
3568
3569 } else {
3570 // This not being started from an existing activity, and not part
3571 // of a new task... just put it in the top task, though these days
3572 // this case should never happen.
3573 final int N = mHistory.size();
3574 HistoryRecord prev =
3575 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3576 r.task = prev != null
3577 ? prev.task
3578 : new TaskRecord(mCurTask, r.info, intent,
3579 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3580 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3581 + " in new guessed " + r.task);
3582 }
3583 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003584 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003585 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003586 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003587 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588 return START_SUCCESS;
3589 }
3590
3591 public final int startActivity(IApplicationThread caller,
3592 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3593 int grantedMode, IBinder resultTo,
3594 String resultWho, int requestCode, boolean onlyIfNeeded,
3595 boolean debug) {
3596 // Refuse possible leaked file descriptors
3597 if (intent != null && intent.hasFileDescriptors()) {
3598 throw new IllegalArgumentException("File descriptors passed in Intent");
3599 }
3600
The Android Open Source Project4df24232009-03-05 14:34:35 -08003601 final boolean componentSpecified = intent.getComponent() != null;
3602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003603 // Don't modify the client's object!
3604 intent = new Intent(intent);
3605
3606 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003607 ActivityInfo aInfo;
3608 try {
3609 ResolveInfo rInfo =
3610 ActivityThread.getPackageManager().resolveIntent(
3611 intent, resolvedType,
3612 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003613 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003614 aInfo = rInfo != null ? rInfo.activityInfo : null;
3615 } catch (RemoteException e) {
3616 aInfo = null;
3617 }
3618
3619 if (aInfo != null) {
3620 // Store the found target back into the intent, because now that
3621 // we have it we never want to do this again. For example, if the
3622 // user navigates back to this point in the history, we should
3623 // always restart the exact same activity.
3624 intent.setComponent(new ComponentName(
3625 aInfo.applicationInfo.packageName, aInfo.name));
3626
3627 // Don't debug things in the system process
3628 if (debug) {
3629 if (!aInfo.processName.equals("system")) {
3630 setDebugApp(aInfo.processName, true, false);
3631 }
3632 }
3633 }
3634
3635 synchronized(this) {
3636 final long origId = Binder.clearCallingIdentity();
3637 int res = startActivityLocked(caller, intent, resolvedType,
3638 grantedUriPermissions, grantedMode, aInfo,
3639 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003640 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 Binder.restoreCallingIdentity(origId);
3642 return res;
3643 }
3644 }
3645
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003646 public int startActivityIntentSender(IApplicationThread caller,
3647 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003648 IBinder resultTo, String resultWho, int requestCode,
3649 int flagsMask, int flagsValues) {
3650 // Refuse possible leaked file descriptors
3651 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3652 throw new IllegalArgumentException("File descriptors passed in Intent");
3653 }
3654
3655 IIntentSender sender = intent.getTarget();
3656 if (!(sender instanceof PendingIntentRecord)) {
3657 throw new IllegalArgumentException("Bad PendingIntent object");
3658 }
3659
3660 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003661
3662 synchronized (this) {
3663 // If this is coming from the currently resumed activity, it is
3664 // effectively saying that app switches are allowed at this point.
3665 if (mResumedActivity != null
3666 && mResumedActivity.info.applicationInfo.uid ==
3667 Binder.getCallingUid()) {
3668 mAppSwitchesAllowedTime = 0;
3669 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003670 }
3671
3672 return pir.sendInner(0, fillInIntent, resolvedType,
3673 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3674 }
3675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003676 public boolean startNextMatchingActivity(IBinder callingActivity,
3677 Intent intent) {
3678 // Refuse possible leaked file descriptors
3679 if (intent != null && intent.hasFileDescriptors() == true) {
3680 throw new IllegalArgumentException("File descriptors passed in Intent");
3681 }
3682
3683 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003684 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003685 if (index < 0) {
3686 return false;
3687 }
3688 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3689 if (r.app == null || r.app.thread == null) {
3690 // The caller is not running... d'oh!
3691 return false;
3692 }
3693 intent = new Intent(intent);
3694 // The caller is not allowed to change the data.
3695 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3696 // And we are resetting to find the next component...
3697 intent.setComponent(null);
3698
3699 ActivityInfo aInfo = null;
3700 try {
3701 List<ResolveInfo> resolves =
3702 ActivityThread.getPackageManager().queryIntentActivities(
3703 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003704 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705
3706 // Look for the original activity in the list...
3707 final int N = resolves != null ? resolves.size() : 0;
3708 for (int i=0; i<N; i++) {
3709 ResolveInfo rInfo = resolves.get(i);
3710 if (rInfo.activityInfo.packageName.equals(r.packageName)
3711 && rInfo.activityInfo.name.equals(r.info.name)) {
3712 // We found the current one... the next matching is
3713 // after it.
3714 i++;
3715 if (i<N) {
3716 aInfo = resolves.get(i).activityInfo;
3717 }
3718 break;
3719 }
3720 }
3721 } catch (RemoteException e) {
3722 }
3723
3724 if (aInfo == null) {
3725 // Nobody who is next!
3726 return false;
3727 }
3728
3729 intent.setComponent(new ComponentName(
3730 aInfo.applicationInfo.packageName, aInfo.name));
3731 intent.setFlags(intent.getFlags()&~(
3732 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3733 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3734 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3735 Intent.FLAG_ACTIVITY_NEW_TASK));
3736
3737 // Okay now we need to start the new activity, replacing the
3738 // currently running activity. This is a little tricky because
3739 // we want to start the new one as if the current one is finished,
3740 // but not finish the current one first so that there is no flicker.
3741 // And thus...
3742 final boolean wasFinishing = r.finishing;
3743 r.finishing = true;
3744
3745 // Propagate reply information over to the new activity.
3746 final HistoryRecord resultTo = r.resultTo;
3747 final String resultWho = r.resultWho;
3748 final int requestCode = r.requestCode;
3749 r.resultTo = null;
3750 if (resultTo != null) {
3751 resultTo.removeResultsLocked(r, resultWho, requestCode);
3752 }
3753
3754 final long origId = Binder.clearCallingIdentity();
3755 // XXX we are not dealing with propagating grantedUriPermissions...
3756 // those are not yet exposed to user code, so there is no need.
3757 int res = startActivityLocked(r.app.thread, intent,
3758 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003759 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003760 Binder.restoreCallingIdentity(origId);
3761
3762 r.finishing = wasFinishing;
3763 if (res != START_SUCCESS) {
3764 return false;
3765 }
3766 return true;
3767 }
3768 }
3769
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003770 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771 Intent intent, String resolvedType, IBinder resultTo,
3772 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003773
3774 // This is so super not safe, that only the system (or okay root)
3775 // can do it.
3776 final int callingUid = Binder.getCallingUid();
3777 if (callingUid != 0 && callingUid != Process.myUid()) {
3778 throw new SecurityException(
3779 "startActivityInPackage only available to the system");
3780 }
3781
The Android Open Source Project4df24232009-03-05 14:34:35 -08003782 final boolean componentSpecified = intent.getComponent() != null;
3783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003784 // Don't modify the client's object!
3785 intent = new Intent(intent);
3786
3787 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003788 ActivityInfo aInfo;
3789 try {
3790 ResolveInfo rInfo =
3791 ActivityThread.getPackageManager().resolveIntent(
3792 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003793 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 aInfo = rInfo != null ? rInfo.activityInfo : null;
3795 } catch (RemoteException e) {
3796 aInfo = null;
3797 }
3798
3799 if (aInfo != null) {
3800 // Store the found target back into the intent, because now that
3801 // we have it we never want to do this again. For example, if the
3802 // user navigates back to this point in the history, we should
3803 // always restart the exact same activity.
3804 intent.setComponent(new ComponentName(
3805 aInfo.applicationInfo.packageName, aInfo.name));
3806 }
3807
3808 synchronized(this) {
3809 return startActivityLocked(null, intent, resolvedType,
3810 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003811 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003812 }
3813 }
3814
3815 private final void addRecentTask(TaskRecord task) {
3816 // Remove any existing entries that are the same kind of task.
3817 int N = mRecentTasks.size();
3818 for (int i=0; i<N; i++) {
3819 TaskRecord tr = mRecentTasks.get(i);
3820 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3821 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3822 mRecentTasks.remove(i);
3823 i--;
3824 N--;
3825 if (task.intent == null) {
3826 // If the new recent task we are adding is not fully
3827 // specified, then replace it with the existing recent task.
3828 task = tr;
3829 }
3830 }
3831 }
3832 if (N >= MAX_RECENT_TASKS) {
3833 mRecentTasks.remove(N-1);
3834 }
3835 mRecentTasks.add(0, task);
3836 }
3837
3838 public void setRequestedOrientation(IBinder token,
3839 int requestedOrientation) {
3840 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003841 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003842 if (index < 0) {
3843 return;
3844 }
3845 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3846 final long origId = Binder.clearCallingIdentity();
3847 mWindowManager.setAppOrientation(r, requestedOrientation);
3848 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003849 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 r.mayFreezeScreenLocked(r.app) ? r : null);
3851 if (config != null) {
3852 r.frozenBeforeDestroy = true;
3853 if (!updateConfigurationLocked(config, r)) {
3854 resumeTopActivityLocked(null);
3855 }
3856 }
3857 Binder.restoreCallingIdentity(origId);
3858 }
3859 }
3860
3861 public int getRequestedOrientation(IBinder token) {
3862 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003863 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003864 if (index < 0) {
3865 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3866 }
3867 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3868 return mWindowManager.getAppOrientation(r);
3869 }
3870 }
3871
3872 private final void stopActivityLocked(HistoryRecord r) {
3873 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3874 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3875 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3876 if (!r.finishing) {
3877 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3878 "no-history");
3879 }
3880 } else if (r.app != null && r.app.thread != null) {
3881 if (mFocusedActivity == r) {
3882 setFocusedActivityLocked(topRunningActivityLocked(null));
3883 }
3884 r.resumeKeyDispatchingLocked();
3885 try {
3886 r.stopped = false;
3887 r.state = ActivityState.STOPPING;
3888 if (DEBUG_VISBILITY) Log.v(
3889 TAG, "Stopping visible=" + r.visible + " for " + r);
3890 if (!r.visible) {
3891 mWindowManager.setAppVisibility(r, false);
3892 }
3893 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3894 } catch (Exception e) {
3895 // Maybe just ignore exceptions here... if the process
3896 // has crashed, our death notification will clean things
3897 // up.
3898 Log.w(TAG, "Exception thrown during pause", e);
3899 // Just in case, assume it to be stopped.
3900 r.stopped = true;
3901 r.state = ActivityState.STOPPED;
3902 if (r.configDestroy) {
3903 destroyActivityLocked(r, true);
3904 }
3905 }
3906 }
3907 }
3908
3909 /**
3910 * @return Returns true if the activity is being finished, false if for
3911 * some reason it is being left as-is.
3912 */
3913 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3914 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003915 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003916 TAG, "Finishing activity: token=" + token
3917 + ", result=" + resultCode + ", data=" + resultData);
3918
Dianne Hackborn75b03852009-06-12 15:43:26 -07003919 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003920 if (index < 0) {
3921 return false;
3922 }
3923 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3924
3925 // Is this the last activity left?
3926 boolean lastActivity = true;
3927 for (int i=mHistory.size()-1; i>=0; i--) {
3928 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3929 if (!p.finishing && p != r) {
3930 lastActivity = false;
3931 break;
3932 }
3933 }
3934
3935 // If this is the last activity, but it is the home activity, then
3936 // just don't finish it.
3937 if (lastActivity) {
3938 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3939 return false;
3940 }
3941 }
3942
3943 finishActivityLocked(r, index, resultCode, resultData, reason);
3944 return true;
3945 }
3946
3947 /**
3948 * @return Returns true if this activity has been removed from the history
3949 * list, or false if it is still in the list and will be removed later.
3950 */
3951 private final boolean finishActivityLocked(HistoryRecord r, int index,
3952 int resultCode, Intent resultData, String reason) {
3953 if (r.finishing) {
3954 Log.w(TAG, "Duplicate finish request for " + r);
3955 return false;
3956 }
3957
3958 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003959 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003960 System.identityHashCode(r),
3961 r.task.taskId, r.shortComponentName, reason);
3962 r.task.numActivities--;
3963 if (r.frontOfTask && index < (mHistory.size()-1)) {
3964 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3965 if (next.task == r.task) {
3966 next.frontOfTask = true;
3967 }
3968 }
3969
3970 r.pauseKeyDispatchingLocked();
3971 if (mFocusedActivity == r) {
3972 setFocusedActivityLocked(topRunningActivityLocked(null));
3973 }
3974
3975 // send the result
3976 HistoryRecord resultTo = r.resultTo;
3977 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003978 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3979 + " who=" + r.resultWho + " req=" + r.requestCode
3980 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003981 if (r.info.applicationInfo.uid > 0) {
3982 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3983 r.packageName, resultData, r);
3984 }
3985 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3986 resultData);
3987 r.resultTo = null;
3988 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003989 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003990
3991 // Make sure this HistoryRecord is not holding on to other resources,
3992 // because clients have remote IPC references to this object so we
3993 // can't assume that will go away and want to avoid circular IPC refs.
3994 r.results = null;
3995 r.pendingResults = null;
3996 r.newIntents = null;
3997 r.icicle = null;
3998
3999 if (mPendingThumbnails.size() > 0) {
4000 // There are clients waiting to receive thumbnails so, in case
4001 // this is an activity that someone is waiting for, add it
4002 // to the pending list so we can correctly update the clients.
4003 mCancelledThumbnails.add(r);
4004 }
4005
4006 if (mResumedActivity == r) {
4007 boolean endTask = index <= 0
4008 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4009 if (DEBUG_TRANSITION) Log.v(TAG,
4010 "Prepare close transition: finishing " + r);
4011 mWindowManager.prepareAppTransition(endTask
4012 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4013 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4014
4015 // Tell window manager to prepare for this one to be removed.
4016 mWindowManager.setAppVisibility(r, false);
4017
4018 if (mPausingActivity == null) {
4019 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4020 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4021 startPausingLocked(false, false);
4022 }
4023
4024 } else if (r.state != ActivityState.PAUSING) {
4025 // If the activity is PAUSING, we will complete the finish once
4026 // it is done pausing; else we can just directly finish it here.
4027 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4028 return finishCurrentActivityLocked(r, index,
4029 FINISH_AFTER_PAUSE) == null;
4030 } else {
4031 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4032 }
4033
4034 return false;
4035 }
4036
4037 private static final int FINISH_IMMEDIATELY = 0;
4038 private static final int FINISH_AFTER_PAUSE = 1;
4039 private static final int FINISH_AFTER_VISIBLE = 2;
4040
4041 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4042 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004043 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004044 if (index < 0) {
4045 return null;
4046 }
4047
4048 return finishCurrentActivityLocked(r, index, mode);
4049 }
4050
4051 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4052 int index, int mode) {
4053 // First things first: if this activity is currently visible,
4054 // and the resumed activity is not yet visible, then hold off on
4055 // finishing until the resumed one becomes visible.
4056 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4057 if (!mStoppingActivities.contains(r)) {
4058 mStoppingActivities.add(r);
4059 if (mStoppingActivities.size() > 3) {
4060 // If we already have a few activities waiting to stop,
4061 // then give up on things going idle and start clearing
4062 // them out.
4063 Message msg = Message.obtain();
4064 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4065 mHandler.sendMessage(msg);
4066 }
4067 }
4068 r.state = ActivityState.STOPPING;
4069 updateOomAdjLocked();
4070 return r;
4071 }
4072
4073 // make sure the record is cleaned out of other places.
4074 mStoppingActivities.remove(r);
4075 mWaitingVisibleActivities.remove(r);
4076 if (mResumedActivity == r) {
4077 mResumedActivity = null;
4078 }
4079 final ActivityState prevState = r.state;
4080 r.state = ActivityState.FINISHING;
4081
4082 if (mode == FINISH_IMMEDIATELY
4083 || prevState == ActivityState.STOPPED
4084 || prevState == ActivityState.INITIALIZING) {
4085 // If this activity is already stopped, we can just finish
4086 // it right now.
4087 return destroyActivityLocked(r, true) ? null : r;
4088 } else {
4089 // Need to go through the full pause cycle to get this
4090 // activity into the stopped state and then finish it.
4091 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4092 mFinishingActivities.add(r);
4093 resumeTopActivityLocked(null);
4094 }
4095 return r;
4096 }
4097
4098 /**
4099 * This is the internal entry point for handling Activity.finish().
4100 *
4101 * @param token The Binder token referencing the Activity we want to finish.
4102 * @param resultCode Result code, if any, from this Activity.
4103 * @param resultData Result data (Intent), if any, from this Activity.
4104 *
4105 * @result Returns true if the activity successfully finished, or false if it is still running.
4106 */
4107 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4108 // Refuse possible leaked file descriptors
4109 if (resultData != null && resultData.hasFileDescriptors() == true) {
4110 throw new IllegalArgumentException("File descriptors passed in Intent");
4111 }
4112
4113 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004114 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004115 // Find the first activity that is not finishing.
4116 HistoryRecord next = topRunningActivityLocked(token, 0);
4117 if (next != null) {
4118 // ask watcher if this is allowed
4119 boolean resumeOK = true;
4120 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004121 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004122 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004123 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004124 }
4125
4126 if (!resumeOK) {
4127 return false;
4128 }
4129 }
4130 }
4131 final long origId = Binder.clearCallingIdentity();
4132 boolean res = requestFinishActivityLocked(token, resultCode,
4133 resultData, "app-request");
4134 Binder.restoreCallingIdentity(origId);
4135 return res;
4136 }
4137 }
4138
4139 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4140 String resultWho, int requestCode, int resultCode, Intent data) {
4141
4142 if (callingUid > 0) {
4143 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4144 data, r);
4145 }
4146
The Android Open Source Project10592532009-03-18 17:39:46 -07004147 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4148 + " : who=" + resultWho + " req=" + requestCode
4149 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004150 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4151 try {
4152 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4153 list.add(new ResultInfo(resultWho, requestCode,
4154 resultCode, data));
4155 r.app.thread.scheduleSendResult(r, list);
4156 return;
4157 } catch (Exception e) {
4158 Log.w(TAG, "Exception thrown sending result to " + r, e);
4159 }
4160 }
4161
4162 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4163 }
4164
4165 public final void finishSubActivity(IBinder token, String resultWho,
4166 int requestCode) {
4167 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004168 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004169 if (index < 0) {
4170 return;
4171 }
4172 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4173
4174 final long origId = Binder.clearCallingIdentity();
4175
4176 int i;
4177 for (i=mHistory.size()-1; i>=0; i--) {
4178 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4179 if (r.resultTo == self && r.requestCode == requestCode) {
4180 if ((r.resultWho == null && resultWho == null) ||
4181 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4182 finishActivityLocked(r, i,
4183 Activity.RESULT_CANCELED, null, "request-sub");
4184 }
4185 }
4186 }
4187
4188 Binder.restoreCallingIdentity(origId);
4189 }
4190 }
4191
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004192 public void overridePendingTransition(IBinder token, String packageName,
4193 int enterAnim, int exitAnim) {
4194 synchronized(this) {
4195 int index = indexOfTokenLocked(token);
4196 if (index < 0) {
4197 return;
4198 }
4199 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4200
4201 final long origId = Binder.clearCallingIdentity();
4202
4203 if (self.state == ActivityState.RESUMED
4204 || self.state == ActivityState.PAUSING) {
4205 mWindowManager.overridePendingAppTransition(packageName,
4206 enterAnim, exitAnim);
4207 }
4208
4209 Binder.restoreCallingIdentity(origId);
4210 }
4211 }
4212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004213 /**
4214 * Perform clean-up of service connections in an activity record.
4215 */
4216 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4217 // Throw away any services that have been bound by this activity.
4218 if (r.connections != null) {
4219 Iterator<ConnectionRecord> it = r.connections.iterator();
4220 while (it.hasNext()) {
4221 ConnectionRecord c = it.next();
4222 removeConnectionLocked(c, null, r);
4223 }
4224 r.connections = null;
4225 }
4226 }
4227
4228 /**
4229 * Perform the common clean-up of an activity record. This is called both
4230 * as part of destroyActivityLocked() (when destroying the client-side
4231 * representation) and cleaning things up as a result of its hosting
4232 * processing going away, in which case there is no remaining client-side
4233 * state to destroy so only the cleanup here is needed.
4234 */
4235 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4236 if (mResumedActivity == r) {
4237 mResumedActivity = null;
4238 }
4239 if (mFocusedActivity == r) {
4240 mFocusedActivity = null;
4241 }
4242
4243 r.configDestroy = false;
4244 r.frozenBeforeDestroy = false;
4245
4246 // Make sure this record is no longer in the pending finishes list.
4247 // This could happen, for example, if we are trimming activities
4248 // down to the max limit while they are still waiting to finish.
4249 mFinishingActivities.remove(r);
4250 mWaitingVisibleActivities.remove(r);
4251
4252 // Remove any pending results.
4253 if (r.finishing && r.pendingResults != null) {
4254 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4255 PendingIntentRecord rec = apr.get();
4256 if (rec != null) {
4257 cancelIntentSenderLocked(rec, false);
4258 }
4259 }
4260 r.pendingResults = null;
4261 }
4262
4263 if (cleanServices) {
4264 cleanUpActivityServicesLocked(r);
4265 }
4266
4267 if (mPendingThumbnails.size() > 0) {
4268 // There are clients waiting to receive thumbnails so, in case
4269 // this is an activity that someone is waiting for, add it
4270 // to the pending list so we can correctly update the clients.
4271 mCancelledThumbnails.add(r);
4272 }
4273
4274 // Get rid of any pending idle timeouts.
4275 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4276 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4277 }
4278
4279 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4280 if (r.state != ActivityState.DESTROYED) {
4281 mHistory.remove(r);
4282 r.inHistory = false;
4283 r.state = ActivityState.DESTROYED;
4284 mWindowManager.removeAppToken(r);
4285 if (VALIDATE_TOKENS) {
4286 mWindowManager.validateAppTokens(mHistory);
4287 }
4288 cleanUpActivityServicesLocked(r);
4289 removeActivityUriPermissionsLocked(r);
4290 }
4291 }
4292
4293 /**
4294 * Destroy the current CLIENT SIDE instance of an activity. This may be
4295 * called both when actually finishing an activity, or when performing
4296 * a configuration switch where we destroy the current client-side object
4297 * but then create a new client-side object for this same HistoryRecord.
4298 */
4299 private final boolean destroyActivityLocked(HistoryRecord r,
4300 boolean removeFromApp) {
4301 if (DEBUG_SWITCH) Log.v(
4302 TAG, "Removing activity: token=" + r
4303 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004304 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004305 System.identityHashCode(r),
4306 r.task.taskId, r.shortComponentName);
4307
4308 boolean removedFromHistory = false;
4309
4310 cleanUpActivityLocked(r, false);
4311
4312 if (r.app != null) {
4313 if (removeFromApp) {
4314 int idx = r.app.activities.indexOf(r);
4315 if (idx >= 0) {
4316 r.app.activities.remove(idx);
4317 }
4318 if (r.persistent) {
4319 decPersistentCountLocked(r.app);
4320 }
4321 }
4322
4323 boolean skipDestroy = false;
4324
4325 try {
4326 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4327 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4328 r.configChangeFlags);
4329 } catch (Exception e) {
4330 // We can just ignore exceptions here... if the process
4331 // has crashed, our death notification will clean things
4332 // up.
4333 //Log.w(TAG, "Exception thrown during finish", e);
4334 if (r.finishing) {
4335 removeActivityFromHistoryLocked(r);
4336 removedFromHistory = true;
4337 skipDestroy = true;
4338 }
4339 }
4340
4341 r.app = null;
4342 r.nowVisible = false;
4343
4344 if (r.finishing && !skipDestroy) {
4345 r.state = ActivityState.DESTROYING;
4346 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4347 msg.obj = r;
4348 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4349 } else {
4350 r.state = ActivityState.DESTROYED;
4351 }
4352 } else {
4353 // remove this record from the history.
4354 if (r.finishing) {
4355 removeActivityFromHistoryLocked(r);
4356 removedFromHistory = true;
4357 } else {
4358 r.state = ActivityState.DESTROYED;
4359 }
4360 }
4361
4362 r.configChangeFlags = 0;
4363
4364 if (!mLRUActivities.remove(r)) {
4365 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4366 }
4367
4368 return removedFromHistory;
4369 }
4370
4371 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4372 ProcessRecord app)
4373 {
4374 int i = list.size();
4375 if (localLOGV) Log.v(
4376 TAG, "Removing app " + app + " from list " + list
4377 + " with " + i + " entries");
4378 while (i > 0) {
4379 i--;
4380 HistoryRecord r = (HistoryRecord)list.get(i);
4381 if (localLOGV) Log.v(
4382 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4383 if (r.app == app) {
4384 if (localLOGV) Log.v(TAG, "Removing this entry!");
4385 list.remove(i);
4386 }
4387 }
4388 }
4389
4390 /**
4391 * Main function for removing an existing process from the activity manager
4392 * as a result of that process going away. Clears out all connections
4393 * to the process.
4394 */
4395 private final void handleAppDiedLocked(ProcessRecord app,
4396 boolean restarting) {
4397 cleanUpApplicationRecordLocked(app, restarting, -1);
4398 if (!restarting) {
4399 mLRUProcesses.remove(app);
4400 }
4401
4402 // Just in case...
4403 if (mPausingActivity != null && mPausingActivity.app == app) {
4404 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4405 mPausingActivity = null;
4406 }
4407 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4408 mLastPausedActivity = null;
4409 }
4410
4411 // Remove this application's activities from active lists.
4412 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4413 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4414 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4415 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4416
4417 boolean atTop = true;
4418 boolean hasVisibleActivities = false;
4419
4420 // Clean out the history list.
4421 int i = mHistory.size();
4422 if (localLOGV) Log.v(
4423 TAG, "Removing app " + app + " from history with " + i + " entries");
4424 while (i > 0) {
4425 i--;
4426 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4427 if (localLOGV) Log.v(
4428 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4429 if (r.app == app) {
4430 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4431 if (localLOGV) Log.v(
4432 TAG, "Removing this entry! frozen=" + r.haveState
4433 + " finishing=" + r.finishing);
4434 mHistory.remove(i);
4435
4436 r.inHistory = false;
4437 mWindowManager.removeAppToken(r);
4438 if (VALIDATE_TOKENS) {
4439 mWindowManager.validateAppTokens(mHistory);
4440 }
4441 removeActivityUriPermissionsLocked(r);
4442
4443 } else {
4444 // We have the current state for this activity, so
4445 // it can be restarted later when needed.
4446 if (localLOGV) Log.v(
4447 TAG, "Keeping entry, setting app to null");
4448 if (r.visible) {
4449 hasVisibleActivities = true;
4450 }
4451 r.app = null;
4452 r.nowVisible = false;
4453 if (!r.haveState) {
4454 r.icicle = null;
4455 }
4456 }
4457
4458 cleanUpActivityLocked(r, true);
4459 r.state = ActivityState.STOPPED;
4460 }
4461 atTop = false;
4462 }
4463
4464 app.activities.clear();
4465
4466 if (app.instrumentationClass != null) {
4467 Log.w(TAG, "Crash of app " + app.processName
4468 + " running instrumentation " + app.instrumentationClass);
4469 Bundle info = new Bundle();
4470 info.putString("shortMsg", "Process crashed.");
4471 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4472 }
4473
4474 if (!restarting) {
4475 if (!resumeTopActivityLocked(null)) {
4476 // If there was nothing to resume, and we are not already
4477 // restarting this process, but there is a visible activity that
4478 // is hosted by the process... then make sure all visible
4479 // activities are running, taking care of restarting this
4480 // process.
4481 if (hasVisibleActivities) {
4482 ensureActivitiesVisibleLocked(null, 0);
4483 }
4484 }
4485 }
4486 }
4487
4488 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4489 IBinder threadBinder = thread.asBinder();
4490
4491 // Find the application record.
4492 int count = mLRUProcesses.size();
4493 int i;
4494 for (i=0; i<count; i++) {
4495 ProcessRecord rec = mLRUProcesses.get(i);
4496 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4497 return i;
4498 }
4499 }
4500 return -1;
4501 }
4502
4503 private final ProcessRecord getRecordForAppLocked(
4504 IApplicationThread thread) {
4505 if (thread == null) {
4506 return null;
4507 }
4508
4509 int appIndex = getLRURecordIndexForAppLocked(thread);
4510 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4511 }
4512
4513 private final void appDiedLocked(ProcessRecord app, int pid,
4514 IApplicationThread thread) {
4515
4516 mProcDeaths[0]++;
4517
4518 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4519 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4520 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004521 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004522 if (localLOGV) Log.v(
4523 TAG, "Dying app: " + app + ", pid: " + pid
4524 + ", thread: " + thread.asBinder());
4525 boolean doLowMem = app.instrumentationClass == null;
4526 handleAppDiedLocked(app, false);
4527
4528 if (doLowMem) {
4529 // If there are no longer any background processes running,
4530 // and the app that died was not running instrumentation,
4531 // then tell everyone we are now low on memory.
4532 boolean haveBg = false;
4533 int count = mLRUProcesses.size();
4534 int i;
4535 for (i=0; i<count; i++) {
4536 ProcessRecord rec = mLRUProcesses.get(i);
4537 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4538 haveBg = true;
4539 break;
4540 }
4541 }
4542
4543 if (!haveBg) {
4544 Log.i(TAG, "Low Memory: No more background processes.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004545 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004546 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004547 for (i=0; i<count; i++) {
4548 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004549 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004550 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4551 // The low memory report is overriding any current
4552 // state for a GC request. Make sure to do
4553 // visible/foreground processes first.
4554 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4555 rec.lastRequestedGc = 0;
4556 } else {
4557 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004558 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004559 rec.reportLowMemory = true;
4560 rec.lastLowMemory = now;
4561 mProcessesToGc.remove(rec);
4562 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004563 }
4564 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004565 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004566 }
4567 }
4568 } else if (Config.LOGD) {
4569 Log.d(TAG, "Received spurious death notification for thread "
4570 + thread.asBinder());
4571 }
4572 }
4573
4574 final String readFile(String filename) {
4575 try {
4576 FileInputStream fs = new FileInputStream(filename);
4577 byte[] inp = new byte[8192];
4578 int size = fs.read(inp);
4579 fs.close();
4580 return new String(inp, 0, 0, size);
4581 } catch (java.io.IOException e) {
4582 }
4583 return "";
4584 }
4585
4586 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004587 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004588 if (app.notResponding || app.crashing) {
4589 return;
4590 }
4591
4592 // Log the ANR to the event log.
Doug Zongker2bec3d42009-12-04 12:52:44 -08004593 EventLog.writeEvent(EventLogTags.ANR, app.pid, app.processName, annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004594
4595 // If we are on a secure build and the application is not interesting to the user (it is
4596 // not visible or in the background), just kill it instead of displaying a dialog.
4597 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4598 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4599 Process.killProcess(app.pid);
4600 return;
4601 }
4602
4603 // DeviceMonitor.start();
4604
4605 String processInfo = null;
4606 if (MONITOR_CPU_USAGE) {
4607 updateCpuStatsNow();
4608 synchronized (mProcessStatsThread) {
4609 processInfo = mProcessStats.printCurrentState();
4610 }
4611 }
4612
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004613 StringBuilder info = mStringBuilder;
4614 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004615 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004616 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004617 if (reportedActivity != null && reportedActivity.app != null) {
4618 info.append(" (last in ");
4619 info.append(reportedActivity.app.processName);
4620 info.append(")");
4621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004622 if (annotation != null) {
4623 info.append("\nAnnotation: ");
4624 info.append(annotation);
4625 }
4626 if (MONITOR_CPU_USAGE) {
4627 info.append("\nCPU usage:\n");
4628 info.append(processInfo);
4629 }
4630 Log.i(TAG, info.toString());
4631
4632 // The application is not responding. Dump as many thread traces as we can.
4633 boolean fileDump = prepareTraceFile(true);
4634 if (!fileDump) {
4635 // Dumping traces to the log, just dump the process that isn't responding so
4636 // we don't overflow the log
4637 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4638 } else {
4639 // Dumping traces to a file so dump all active processes we know about
4640 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004641 // First, these are the most important processes.
4642 final int[] imppids = new int[3];
4643 int i=0;
4644 imppids[0] = app.pid;
4645 i++;
4646 if (reportedActivity != null && reportedActivity.app != null
4647 && reportedActivity.app.thread != null
4648 && reportedActivity.app.pid != app.pid) {
4649 imppids[i] = reportedActivity.app.pid;
4650 i++;
4651 }
4652 imppids[i] = Process.myPid();
4653 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4654 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4655 synchronized (this) {
4656 try {
4657 wait(200);
4658 } catch (InterruptedException e) {
4659 }
4660 }
4661 }
4662 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004663 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004664 boolean done = false;
4665 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4666 if (imppids[j] == r.pid) {
4667 done = true;
4668 break;
4669 }
4670 }
4671 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004673 synchronized (this) {
4674 try {
4675 wait(200);
4676 } catch (InterruptedException e) {
4677 }
4678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004679 }
4680 }
4681 }
4682 }
4683
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004684 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004686 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004687 app.pid, info.toString());
4688 if (res != 0) {
4689 if (res < 0) {
4690 // wait until the SIGQUIT has had a chance to process before killing the
4691 // process.
4692 try {
4693 wait(2000);
4694 } catch (InterruptedException e) {
4695 }
4696
4697 Process.killProcess(app.pid);
4698 return;
4699 }
4700 }
4701 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004702 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004703 }
4704 }
4705
4706 makeAppNotRespondingLocked(app,
4707 activity != null ? activity.shortComponentName : null,
4708 annotation != null ? "ANR " + annotation : "ANR",
4709 info.toString(), null);
4710 Message msg = Message.obtain();
4711 HashMap map = new HashMap();
4712 msg.what = SHOW_NOT_RESPONDING_MSG;
4713 msg.obj = map;
4714 map.put("app", app);
4715 if (activity != null) {
4716 map.put("activity", activity);
4717 }
4718
4719 mHandler.sendMessage(msg);
4720 return;
4721 }
4722
4723 /**
4724 * If a stack trace file has been configured, prepare the filesystem
4725 * by creating the directory if it doesn't exist and optionally
4726 * removing the old trace file.
4727 *
4728 * @param removeExisting If set, the existing trace file will be removed.
4729 * @return Returns true if the trace file preparations succeeded
4730 */
4731 public static boolean prepareTraceFile(boolean removeExisting) {
4732 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4733 boolean fileReady = false;
4734 if (!TextUtils.isEmpty(tracesPath)) {
4735 File f = new File(tracesPath);
4736 if (!f.exists()) {
4737 // Ensure the enclosing directory exists
4738 File dir = f.getParentFile();
4739 if (!dir.exists()) {
4740 fileReady = dir.mkdirs();
4741 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004742 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004743 } else if (dir.isDirectory()) {
4744 fileReady = true;
4745 }
4746 } else if (removeExisting) {
4747 // Remove the previous traces file, so we don't fill the disk.
4748 // The VM will recreate it
4749 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4750 fileReady = f.delete();
4751 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004752
4753 if (removeExisting) {
4754 try {
4755 f.createNewFile();
4756 FileUtils.setPermissions(f.getAbsolutePath(),
4757 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4758 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4759 fileReady = true;
4760 } catch (IOException e) {
4761 Log.w(TAG, "Unable to make ANR traces file", e);
4762 }
4763 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004764 }
4765
4766 return fileReady;
4767 }
4768
4769
4770 private final void decPersistentCountLocked(ProcessRecord app)
4771 {
4772 app.persistentActivities--;
4773 if (app.persistentActivities > 0) {
4774 // Still more of 'em...
4775 return;
4776 }
4777 if (app.persistent) {
4778 // Ah, but the application itself is persistent. Whatever!
4779 return;
4780 }
4781
4782 // App is no longer persistent... make sure it and the ones
4783 // following it in the LRU list have the correc oom_adj.
4784 updateOomAdjLocked();
4785 }
4786
4787 public void setPersistent(IBinder token, boolean isPersistent) {
4788 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4789 != PackageManager.PERMISSION_GRANTED) {
4790 String msg = "Permission Denial: setPersistent() from pid="
4791 + Binder.getCallingPid()
4792 + ", uid=" + Binder.getCallingUid()
4793 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4794 Log.w(TAG, msg);
4795 throw new SecurityException(msg);
4796 }
4797
4798 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004799 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004800 if (index < 0) {
4801 return;
4802 }
4803 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4804 ProcessRecord app = r.app;
4805
4806 if (localLOGV) Log.v(
4807 TAG, "Setting persistence " + isPersistent + ": " + r);
4808
4809 if (isPersistent) {
4810 if (r.persistent) {
4811 // Okay okay, I heard you already!
4812 if (localLOGV) Log.v(TAG, "Already persistent!");
4813 return;
4814 }
4815 r.persistent = true;
4816 app.persistentActivities++;
4817 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4818 if (app.persistentActivities > 1) {
4819 // We aren't the first...
4820 if (localLOGV) Log.v(TAG, "Not the first!");
4821 return;
4822 }
4823 if (app.persistent) {
4824 // This would be redundant.
4825 if (localLOGV) Log.v(TAG, "App is persistent!");
4826 return;
4827 }
4828
4829 // App is now persistent... make sure it and the ones
4830 // following it now have the correct oom_adj.
4831 final long origId = Binder.clearCallingIdentity();
4832 updateOomAdjLocked();
4833 Binder.restoreCallingIdentity(origId);
4834
4835 } else {
4836 if (!r.persistent) {
4837 // Okay okay, I heard you already!
4838 return;
4839 }
4840 r.persistent = false;
4841 final long origId = Binder.clearCallingIdentity();
4842 decPersistentCountLocked(app);
4843 Binder.restoreCallingIdentity(origId);
4844
4845 }
4846 }
4847 }
4848
4849 public boolean clearApplicationUserData(final String packageName,
4850 final IPackageDataObserver observer) {
4851 int uid = Binder.getCallingUid();
4852 int pid = Binder.getCallingPid();
4853 long callingId = Binder.clearCallingIdentity();
4854 try {
4855 IPackageManager pm = ActivityThread.getPackageManager();
4856 int pkgUid = -1;
4857 synchronized(this) {
4858 try {
4859 pkgUid = pm.getPackageUid(packageName);
4860 } catch (RemoteException e) {
4861 }
4862 if (pkgUid == -1) {
4863 Log.w(TAG, "Invalid packageName:" + packageName);
4864 return false;
4865 }
4866 if (uid == pkgUid || checkComponentPermission(
4867 android.Manifest.permission.CLEAR_APP_USER_DATA,
4868 pid, uid, -1)
4869 == PackageManager.PERMISSION_GRANTED) {
4870 restartPackageLocked(packageName, pkgUid);
4871 } else {
4872 throw new SecurityException(pid+" does not have permission:"+
4873 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4874 "for process:"+packageName);
4875 }
4876 }
4877
4878 try {
4879 //clear application user data
4880 pm.clearApplicationUserData(packageName, observer);
4881 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4882 Uri.fromParts("package", packageName, null));
4883 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4884 broadcastIntentLocked(null, null, intent,
4885 null, null, 0, null, null, null,
4886 false, false, MY_PID, Process.SYSTEM_UID);
4887 } catch (RemoteException e) {
4888 }
4889 } finally {
4890 Binder.restoreCallingIdentity(callingId);
4891 }
4892 return true;
4893 }
4894
4895 public void restartPackage(final String packageName) {
4896 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4897 != PackageManager.PERMISSION_GRANTED) {
4898 String msg = "Permission Denial: restartPackage() from pid="
4899 + Binder.getCallingPid()
4900 + ", uid=" + Binder.getCallingUid()
4901 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4902 Log.w(TAG, msg);
4903 throw new SecurityException(msg);
4904 }
4905
4906 long callingId = Binder.clearCallingIdentity();
4907 try {
4908 IPackageManager pm = ActivityThread.getPackageManager();
4909 int pkgUid = -1;
4910 synchronized(this) {
4911 try {
4912 pkgUid = pm.getPackageUid(packageName);
4913 } catch (RemoteException e) {
4914 }
4915 if (pkgUid == -1) {
4916 Log.w(TAG, "Invalid packageName: " + packageName);
4917 return;
4918 }
4919 restartPackageLocked(packageName, pkgUid);
4920 }
4921 } finally {
4922 Binder.restoreCallingIdentity(callingId);
4923 }
4924 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004925
4926 /*
4927 * The pkg name and uid have to be specified.
4928 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4929 */
4930 public void killApplicationWithUid(String pkg, int uid) {
4931 if (pkg == null) {
4932 return;
4933 }
4934 // Make sure the uid is valid.
4935 if (uid < 0) {
4936 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4937 return;
4938 }
4939 int callerUid = Binder.getCallingUid();
4940 // Only the system server can kill an application
4941 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004942 // Post an aysnc message to kill the application
4943 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4944 msg.arg1 = uid;
4945 msg.arg2 = 0;
4946 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004947 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004948 } else {
4949 throw new SecurityException(callerUid + " cannot kill pkg: " +
4950 pkg);
4951 }
4952 }
4953
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004954 public void closeSystemDialogs(String reason) {
4955 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4956 if (reason != null) {
4957 intent.putExtra("reason", reason);
4958 }
4959
4960 final int uid = Binder.getCallingUid();
4961 final long origId = Binder.clearCallingIdentity();
4962 synchronized (this) {
4963 int i = mWatchers.beginBroadcast();
4964 while (i > 0) {
4965 i--;
4966 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4967 if (w != null) {
4968 try {
4969 w.closingSystemDialogs(reason);
4970 } catch (RemoteException e) {
4971 }
4972 }
4973 }
4974 mWatchers.finishBroadcast();
4975
Dianne Hackbornffa42482009-09-23 22:20:11 -07004976 mWindowManager.closeSystemDialogs(reason);
4977
4978 for (i=mHistory.size()-1; i>=0; i--) {
4979 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4980 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4981 finishActivityLocked(r, i,
4982 Activity.RESULT_CANCELED, null, "close-sys");
4983 }
4984 }
4985
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004986 broadcastIntentLocked(null, null, intent, null,
4987 null, 0, null, null, null, false, false, -1, uid);
4988 }
4989 Binder.restoreCallingIdentity(origId);
4990 }
4991
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004992 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004993 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004994 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4995 for (int i=pids.length-1; i>=0; i--) {
4996 infos[i] = new Debug.MemoryInfo();
4997 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004998 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004999 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005000 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005001
5002 public void killApplicationProcess(String processName, int uid) {
5003 if (processName == null) {
5004 return;
5005 }
5006
5007 int callerUid = Binder.getCallingUid();
5008 // Only the system server can kill an application
5009 if (callerUid == Process.SYSTEM_UID) {
5010 synchronized (this) {
5011 ProcessRecord app = getProcessRecordLocked(processName, uid);
5012 if (app != null) {
5013 try {
5014 app.thread.scheduleSuicide();
5015 } catch (RemoteException e) {
5016 // If the other end already died, then our work here is done.
5017 }
5018 } else {
5019 Log.w(TAG, "Process/uid not found attempting kill of "
5020 + processName + " / " + uid);
5021 }
5022 }
5023 } else {
5024 throw new SecurityException(callerUid + " cannot kill app process: " +
5025 processName);
5026 }
5027 }
5028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005029 private void restartPackageLocked(final String packageName, int uid) {
5030 uninstallPackageLocked(packageName, uid, false);
5031 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5032 Uri.fromParts("package", packageName, null));
5033 intent.putExtra(Intent.EXTRA_UID, uid);
5034 broadcastIntentLocked(null, null, intent,
5035 null, null, 0, null, null, null,
5036 false, false, MY_PID, Process.SYSTEM_UID);
5037 }
5038
5039 private final void uninstallPackageLocked(String name, int uid,
5040 boolean callerWillRestart) {
5041 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5042
5043 int i, N;
5044
5045 final String procNamePrefix = name + ":";
5046 if (uid < 0) {
5047 try {
5048 uid = ActivityThread.getPackageManager().getPackageUid(name);
5049 } catch (RemoteException e) {
5050 }
5051 }
5052
5053 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5054 while (badApps.hasNext()) {
5055 SparseArray<Long> ba = badApps.next();
5056 if (ba.get(uid) != null) {
5057 badApps.remove();
5058 }
5059 }
5060
5061 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5062
5063 // Remove all processes this package may have touched: all with the
5064 // same UID (except for the system or root user), and all whose name
5065 // matches the package name.
5066 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5067 final int NA = apps.size();
5068 for (int ia=0; ia<NA; ia++) {
5069 ProcessRecord app = apps.valueAt(ia);
5070 if (app.removed) {
5071 procs.add(app);
5072 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5073 || app.processName.equals(name)
5074 || app.processName.startsWith(procNamePrefix)) {
5075 app.removed = true;
5076 procs.add(app);
5077 }
5078 }
5079 }
5080
5081 N = procs.size();
5082 for (i=0; i<N; i++) {
5083 removeProcessLocked(procs.get(i), callerWillRestart);
5084 }
5085
5086 for (i=mHistory.size()-1; i>=0; i--) {
5087 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5088 if (r.packageName.equals(name)) {
5089 if (Config.LOGD) Log.d(
5090 TAG, " Force finishing activity "
5091 + r.intent.getComponent().flattenToShortString());
5092 if (r.app != null) {
5093 r.app.removed = true;
5094 }
5095 r.app = null;
5096 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5097 }
5098 }
5099
5100 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5101 for (ServiceRecord service : mServices.values()) {
5102 if (service.packageName.equals(name)) {
5103 if (service.app != null) {
5104 service.app.removed = true;
5105 }
5106 service.app = null;
5107 services.add(service);
5108 }
5109 }
5110
5111 N = services.size();
5112 for (i=0; i<N; i++) {
5113 bringDownServiceLocked(services.get(i), true);
5114 }
5115
5116 resumeTopActivityLocked(null);
5117 }
5118
5119 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5120 final String name = app.processName;
5121 final int uid = app.info.uid;
5122 if (Config.LOGD) Log.d(
5123 TAG, "Force removing process " + app + " (" + name
5124 + "/" + uid + ")");
5125
5126 mProcessNames.remove(name, uid);
5127 boolean needRestart = false;
5128 if (app.pid > 0 && app.pid != MY_PID) {
5129 int pid = app.pid;
5130 synchronized (mPidsSelfLocked) {
5131 mPidsSelfLocked.remove(pid);
5132 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5133 }
5134 handleAppDiedLocked(app, true);
5135 mLRUProcesses.remove(app);
5136 Process.killProcess(pid);
5137
5138 if (app.persistent) {
5139 if (!callerWillRestart) {
5140 addAppLocked(app.info);
5141 } else {
5142 needRestart = true;
5143 }
5144 }
5145 } else {
5146 mRemovedProcesses.add(app);
5147 }
5148
5149 return needRestart;
5150 }
5151
5152 private final void processStartTimedOutLocked(ProcessRecord app) {
5153 final int pid = app.pid;
5154 boolean gone = false;
5155 synchronized (mPidsSelfLocked) {
5156 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5157 if (knownApp != null && knownApp.thread == null) {
5158 mPidsSelfLocked.remove(pid);
5159 gone = true;
5160 }
5161 }
5162
5163 if (gone) {
5164 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005165 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005166 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005167 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005168 // Take care of any launching providers waiting for this process.
5169 checkAppInLaunchingProvidersLocked(app, true);
5170 // Take care of any services that are waiting for the process.
5171 for (int i=0; i<mPendingServices.size(); i++) {
5172 ServiceRecord sr = mPendingServices.get(i);
5173 if (app.info.uid == sr.appInfo.uid
5174 && app.processName.equals(sr.processName)) {
5175 Log.w(TAG, "Forcing bringing down service: " + sr);
5176 mPendingServices.remove(i);
5177 i--;
5178 bringDownServiceLocked(sr, true);
5179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005180 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005181 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005182 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5183 Log.w(TAG, "Unattached app died before backup, skipping");
5184 try {
5185 IBackupManager bm = IBackupManager.Stub.asInterface(
5186 ServiceManager.getService(Context.BACKUP_SERVICE));
5187 bm.agentDisconnected(app.info.packageName);
5188 } catch (RemoteException e) {
5189 // Can't happen; the backup manager is local
5190 }
5191 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005192 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5193 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5194 mPendingBroadcast = null;
5195 scheduleBroadcastsLocked();
5196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005197 } else {
5198 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5199 }
5200 }
5201
5202 private final boolean attachApplicationLocked(IApplicationThread thread,
5203 int pid) {
5204
5205 // Find the application record that is being attached... either via
5206 // the pid if we are running in multiple processes, or just pull the
5207 // next app record if we are emulating process with anonymous threads.
5208 ProcessRecord app;
5209 if (pid != MY_PID && pid >= 0) {
5210 synchronized (mPidsSelfLocked) {
5211 app = mPidsSelfLocked.get(pid);
5212 }
5213 } else if (mStartingProcesses.size() > 0) {
5214 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005215 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005216 } else {
5217 app = null;
5218 }
5219
5220 if (app == null) {
5221 Log.w(TAG, "No pending application record for pid " + pid
5222 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005223 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005224 if (pid > 0 && pid != MY_PID) {
5225 Process.killProcess(pid);
5226 } else {
5227 try {
5228 thread.scheduleExit();
5229 } catch (Exception e) {
5230 // Ignore exceptions.
5231 }
5232 }
5233 return false;
5234 }
5235
5236 // If this application record is still attached to a previous
5237 // process, clean it up now.
5238 if (app.thread != null) {
5239 handleAppDiedLocked(app, true);
5240 }
5241
5242 // Tell the process all about itself.
5243
5244 if (localLOGV) Log.v(
5245 TAG, "Binding process pid " + pid + " to record " + app);
5246
5247 String processName = app.processName;
5248 try {
5249 thread.asBinder().linkToDeath(new AppDeathRecipient(
5250 app, pid, thread), 0);
5251 } catch (RemoteException e) {
5252 app.resetPackageList();
5253 startProcessLocked(app, "link fail", processName);
5254 return false;
5255 }
5256
Doug Zongker2bec3d42009-12-04 12:52:44 -08005257 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005258
5259 app.thread = thread;
5260 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005261 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5262 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005263 app.forcingToForeground = null;
5264 app.foregroundServices = false;
5265 app.debugging = false;
5266
5267 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5268
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005269 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5270 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005271
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005272 if (!normalMode) {
5273 Log.i(TAG, "Launching preboot mode app: " + app);
5274 }
5275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005276 if (localLOGV) Log.v(
5277 TAG, "New app record " + app
5278 + " thread=" + thread.asBinder() + " pid=" + pid);
5279 try {
5280 int testMode = IApplicationThread.DEBUG_OFF;
5281 if (mDebugApp != null && mDebugApp.equals(processName)) {
5282 testMode = mWaitForDebugger
5283 ? IApplicationThread.DEBUG_WAIT
5284 : IApplicationThread.DEBUG_ON;
5285 app.debugging = true;
5286 if (mDebugTransient) {
5287 mDebugApp = mOrigDebugApp;
5288 mWaitForDebugger = mOrigWaitForDebugger;
5289 }
5290 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005291
Christopher Tate181fafa2009-05-14 11:12:14 -07005292 // If the app is being launched for restore or full backup, set it up specially
5293 boolean isRestrictedBackupMode = false;
5294 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5295 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5296 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5297 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005298
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005299 ensurePackageDexOpt(app.instrumentationInfo != null
5300 ? app.instrumentationInfo.packageName
5301 : app.info.packageName);
5302 if (app.instrumentationClass != null) {
5303 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005304 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005305 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5306 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005307 thread.bindApplication(processName, app.instrumentationInfo != null
5308 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309 app.instrumentationClass, app.instrumentationProfileFile,
5310 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005311 isRestrictedBackupMode || !normalMode,
5312 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005313 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005314 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005315 } catch (Exception e) {
5316 // todo: Yikes! What should we do? For now we will try to
5317 // start another process, but that could easily get us in
5318 // an infinite loop of restarting processes...
5319 Log.w(TAG, "Exception thrown during bind!", e);
5320
5321 app.resetPackageList();
5322 startProcessLocked(app, "bind fail", processName);
5323 return false;
5324 }
5325
5326 // Remove this record from the list of starting applications.
5327 mPersistentStartingProcesses.remove(app);
5328 mProcessesOnHold.remove(app);
5329
5330 boolean badApp = false;
5331 boolean didSomething = false;
5332
5333 // See if the top visible activity is waiting to run in this process...
5334 HistoryRecord hr = topRunningActivityLocked(null);
5335 if (hr != null) {
5336 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5337 && processName.equals(hr.processName)) {
5338 try {
5339 if (realStartActivityLocked(hr, app, true, true)) {
5340 didSomething = true;
5341 }
5342 } catch (Exception e) {
5343 Log.w(TAG, "Exception in new application when starting activity "
5344 + hr.intent.getComponent().flattenToShortString(), e);
5345 badApp = true;
5346 }
5347 } else {
5348 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5349 }
5350 }
5351
5352 // Find any services that should be running in this process...
5353 if (!badApp && mPendingServices.size() > 0) {
5354 ServiceRecord sr = null;
5355 try {
5356 for (int i=0; i<mPendingServices.size(); i++) {
5357 sr = mPendingServices.get(i);
5358 if (app.info.uid != sr.appInfo.uid
5359 || !processName.equals(sr.processName)) {
5360 continue;
5361 }
5362
5363 mPendingServices.remove(i);
5364 i--;
5365 realStartServiceLocked(sr, app);
5366 didSomething = true;
5367 }
5368 } catch (Exception e) {
5369 Log.w(TAG, "Exception in new application when starting service "
5370 + sr.shortName, e);
5371 badApp = true;
5372 }
5373 }
5374
5375 // Check if the next broadcast receiver is in this process...
5376 BroadcastRecord br = mPendingBroadcast;
5377 if (!badApp && br != null && br.curApp == app) {
5378 try {
5379 mPendingBroadcast = null;
5380 processCurBroadcastLocked(br, app);
5381 didSomething = true;
5382 } catch (Exception e) {
5383 Log.w(TAG, "Exception in new application when starting receiver "
5384 + br.curComponent.flattenToShortString(), e);
5385 badApp = true;
5386 logBroadcastReceiverDiscard(br);
5387 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5388 br.resultExtras, br.resultAbort, true);
5389 scheduleBroadcastsLocked();
5390 }
5391 }
5392
Christopher Tate181fafa2009-05-14 11:12:14 -07005393 // Check whether the next backup agent is in this process...
5394 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5395 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005396 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005397 try {
5398 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5399 } catch (Exception e) {
5400 Log.w(TAG, "Exception scheduling backup agent creation: ");
5401 e.printStackTrace();
5402 }
5403 }
5404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005405 if (badApp) {
5406 // todo: Also need to kill application to deal with all
5407 // kinds of exceptions.
5408 handleAppDiedLocked(app, false);
5409 return false;
5410 }
5411
5412 if (!didSomething) {
5413 updateOomAdjLocked();
5414 }
5415
5416 return true;
5417 }
5418
5419 public final void attachApplication(IApplicationThread thread) {
5420 synchronized (this) {
5421 int callingPid = Binder.getCallingPid();
5422 final long origId = Binder.clearCallingIdentity();
5423 attachApplicationLocked(thread, callingPid);
5424 Binder.restoreCallingIdentity(origId);
5425 }
5426 }
5427
Dianne Hackborne88846e2009-09-30 21:34:25 -07005428 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005429 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005430 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005431 Binder.restoreCallingIdentity(origId);
5432 }
5433
5434 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5435 boolean remove) {
5436 int N = mStoppingActivities.size();
5437 if (N <= 0) return null;
5438
5439 ArrayList<HistoryRecord> stops = null;
5440
5441 final boolean nowVisible = mResumedActivity != null
5442 && mResumedActivity.nowVisible
5443 && !mResumedActivity.waitingVisible;
5444 for (int i=0; i<N; i++) {
5445 HistoryRecord s = mStoppingActivities.get(i);
5446 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5447 + nowVisible + " waitingVisible=" + s.waitingVisible
5448 + " finishing=" + s.finishing);
5449 if (s.waitingVisible && nowVisible) {
5450 mWaitingVisibleActivities.remove(s);
5451 s.waitingVisible = false;
5452 if (s.finishing) {
5453 // If this activity is finishing, it is sitting on top of
5454 // everyone else but we now know it is no longer needed...
5455 // so get rid of it. Otherwise, we need to go through the
5456 // normal flow and hide it once we determine that it is
5457 // hidden by the activities in front of it.
5458 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5459 mWindowManager.setAppVisibility(s, false);
5460 }
5461 }
5462 if (!s.waitingVisible && remove) {
5463 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5464 if (stops == null) {
5465 stops = new ArrayList<HistoryRecord>();
5466 }
5467 stops.add(s);
5468 mStoppingActivities.remove(i);
5469 N--;
5470 i--;
5471 }
5472 }
5473
5474 return stops;
5475 }
5476
5477 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005478 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005479 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 mWindowManager.enableScreenAfterBoot();
5481 }
5482
Dianne Hackborne88846e2009-09-30 21:34:25 -07005483 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5484 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005485 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5486
5487 ArrayList<HistoryRecord> stops = null;
5488 ArrayList<HistoryRecord> finishes = null;
5489 ArrayList<HistoryRecord> thumbnails = null;
5490 int NS = 0;
5491 int NF = 0;
5492 int NT = 0;
5493 IApplicationThread sendThumbnail = null;
5494 boolean booting = false;
5495 boolean enableScreen = false;
5496
5497 synchronized (this) {
5498 if (token != null) {
5499 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5500 }
5501
5502 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005503 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005504 if (index >= 0) {
5505 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5506
Dianne Hackborne88846e2009-09-30 21:34:25 -07005507 // This is a hack to semi-deal with a race condition
5508 // in the client where it can be constructed with a
5509 // newer configuration from when we asked it to launch.
5510 // We'll update with whatever configuration it now says
5511 // it used to launch.
5512 if (config != null) {
5513 r.configuration = config;
5514 }
5515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005516 // No longer need to keep the device awake.
5517 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5518 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5519 mLaunchingActivity.release();
5520 }
5521
5522 // We are now idle. If someone is waiting for a thumbnail from
5523 // us, we can now deliver.
5524 r.idle = true;
5525 scheduleAppGcsLocked();
5526 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5527 sendThumbnail = r.app.thread;
5528 r.thumbnailNeeded = false;
5529 }
5530
5531 // If this activity is fullscreen, set up to hide those under it.
5532
5533 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5534 ensureActivitiesVisibleLocked(null, 0);
5535
5536 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5537 if (!mBooted && !fromTimeout) {
5538 mBooted = true;
5539 enableScreen = true;
5540 }
5541 }
5542
5543 // Atomically retrieve all of the other things to do.
5544 stops = processStoppingActivitiesLocked(true);
5545 NS = stops != null ? stops.size() : 0;
5546 if ((NF=mFinishingActivities.size()) > 0) {
5547 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5548 mFinishingActivities.clear();
5549 }
5550 if ((NT=mCancelledThumbnails.size()) > 0) {
5551 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5552 mCancelledThumbnails.clear();
5553 }
5554
5555 booting = mBooting;
5556 mBooting = false;
5557 }
5558
5559 int i;
5560
5561 // Send thumbnail if requested.
5562 if (sendThumbnail != null) {
5563 try {
5564 sendThumbnail.requestThumbnail(token);
5565 } catch (Exception e) {
5566 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5567 sendPendingThumbnail(null, token, null, null, true);
5568 }
5569 }
5570
5571 // Stop any activities that are scheduled to do so but have been
5572 // waiting for the next one to start.
5573 for (i=0; i<NS; i++) {
5574 HistoryRecord r = (HistoryRecord)stops.get(i);
5575 synchronized (this) {
5576 if (r.finishing) {
5577 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5578 } else {
5579 stopActivityLocked(r);
5580 }
5581 }
5582 }
5583
5584 // Finish any activities that are scheduled to do so but have been
5585 // waiting for the next one to start.
5586 for (i=0; i<NF; i++) {
5587 HistoryRecord r = (HistoryRecord)finishes.get(i);
5588 synchronized (this) {
5589 destroyActivityLocked(r, true);
5590 }
5591 }
5592
5593 // Report back to any thumbnail receivers.
5594 for (i=0; i<NT; i++) {
5595 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5596 sendPendingThumbnail(r, null, null, null, true);
5597 }
5598
5599 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005600 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005601 }
5602
5603 trimApplications();
5604 //dump();
5605 //mWindowManager.dump();
5606
5607 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005608 enableScreenAfterBoot();
5609 }
5610 }
5611
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005612 final void finishBooting() {
5613 // Ensure that any processes we had put on hold are now started
5614 // up.
5615 final int NP = mProcessesOnHold.size();
5616 if (NP > 0) {
5617 ArrayList<ProcessRecord> procs =
5618 new ArrayList<ProcessRecord>(mProcessesOnHold);
5619 for (int ip=0; ip<NP; ip++) {
5620 this.startProcessLocked(procs.get(ip), "on-hold", null);
5621 }
5622 }
5623 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5624 // Tell anyone interested that we are done booting!
5625 synchronized (this) {
5626 broadcastIntentLocked(null, null,
5627 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5628 null, null, 0, null, null,
5629 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5630 false, false, MY_PID, Process.SYSTEM_UID);
5631 }
5632 }
5633 }
5634
5635 final void ensureBootCompleted() {
5636 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005637 boolean enableScreen;
5638 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005639 booting = mBooting;
5640 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005641 enableScreen = !mBooted;
5642 mBooted = true;
5643 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005644
5645 if (booting) {
5646 finishBooting();
5647 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005648
5649 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005650 enableScreenAfterBoot();
5651 }
5652 }
5653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005654 public final void activityPaused(IBinder token, Bundle icicle) {
5655 // Refuse possible leaked file descriptors
5656 if (icicle != null && icicle.hasFileDescriptors()) {
5657 throw new IllegalArgumentException("File descriptors passed in Bundle");
5658 }
5659
5660 final long origId = Binder.clearCallingIdentity();
5661 activityPaused(token, icicle, false);
5662 Binder.restoreCallingIdentity(origId);
5663 }
5664
5665 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5666 if (DEBUG_PAUSE) Log.v(
5667 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5668 + ", timeout=" + timeout);
5669
5670 HistoryRecord r = null;
5671
5672 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005673 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005674 if (index >= 0) {
5675 r = (HistoryRecord)mHistory.get(index);
5676 if (!timeout) {
5677 r.icicle = icicle;
5678 r.haveState = true;
5679 }
5680 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5681 if (mPausingActivity == r) {
5682 r.state = ActivityState.PAUSED;
5683 completePauseLocked();
5684 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005685 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005686 System.identityHashCode(r), r.shortComponentName,
5687 mPausingActivity != null
5688 ? mPausingActivity.shortComponentName : "(none)");
5689 }
5690 }
5691 }
5692 }
5693
5694 public final void activityStopped(IBinder token, Bitmap thumbnail,
5695 CharSequence description) {
5696 if (localLOGV) Log.v(
5697 TAG, "Activity stopped: token=" + token);
5698
5699 HistoryRecord r = null;
5700
5701 final long origId = Binder.clearCallingIdentity();
5702
5703 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005704 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005705 if (index >= 0) {
5706 r = (HistoryRecord)mHistory.get(index);
5707 r.thumbnail = thumbnail;
5708 r.description = description;
5709 r.stopped = true;
5710 r.state = ActivityState.STOPPED;
5711 if (!r.finishing) {
5712 if (r.configDestroy) {
5713 destroyActivityLocked(r, true);
5714 resumeTopActivityLocked(null);
5715 }
5716 }
5717 }
5718 }
5719
5720 if (r != null) {
5721 sendPendingThumbnail(r, null, null, null, false);
5722 }
5723
5724 trimApplications();
5725
5726 Binder.restoreCallingIdentity(origId);
5727 }
5728
5729 public final void activityDestroyed(IBinder token) {
5730 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5731 synchronized (this) {
5732 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5733
Dianne Hackborn75b03852009-06-12 15:43:26 -07005734 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005735 if (index >= 0) {
5736 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5737 if (r.state == ActivityState.DESTROYING) {
5738 final long origId = Binder.clearCallingIdentity();
5739 removeActivityFromHistoryLocked(r);
5740 Binder.restoreCallingIdentity(origId);
5741 }
5742 }
5743 }
5744 }
5745
5746 public String getCallingPackage(IBinder token) {
5747 synchronized (this) {
5748 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005749 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005750 }
5751 }
5752
5753 public ComponentName getCallingActivity(IBinder token) {
5754 synchronized (this) {
5755 HistoryRecord r = getCallingRecordLocked(token);
5756 return r != null ? r.intent.getComponent() : null;
5757 }
5758 }
5759
5760 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005761 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005762 if (index >= 0) {
5763 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5764 if (r != null) {
5765 return r.resultTo;
5766 }
5767 }
5768 return null;
5769 }
5770
5771 public ComponentName getActivityClassForToken(IBinder token) {
5772 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005773 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005774 if (index >= 0) {
5775 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5776 return r.intent.getComponent();
5777 }
5778 return null;
5779 }
5780 }
5781
5782 public String getPackageForToken(IBinder token) {
5783 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005784 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005785 if (index >= 0) {
5786 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5787 return r.packageName;
5788 }
5789 return null;
5790 }
5791 }
5792
5793 public IIntentSender getIntentSender(int type,
5794 String packageName, IBinder token, String resultWho,
5795 int requestCode, Intent intent, String resolvedType, int flags) {
5796 // Refuse possible leaked file descriptors
5797 if (intent != null && intent.hasFileDescriptors() == true) {
5798 throw new IllegalArgumentException("File descriptors passed in Intent");
5799 }
5800
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005801 if (type == INTENT_SENDER_BROADCAST) {
5802 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5803 throw new IllegalArgumentException(
5804 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5805 }
5806 }
5807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005808 synchronized(this) {
5809 int callingUid = Binder.getCallingUid();
5810 try {
5811 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5812 Process.supportsProcesses()) {
5813 int uid = ActivityThread.getPackageManager()
5814 .getPackageUid(packageName);
5815 if (uid != Binder.getCallingUid()) {
5816 String msg = "Permission Denial: getIntentSender() from pid="
5817 + Binder.getCallingPid()
5818 + ", uid=" + Binder.getCallingUid()
5819 + ", (need uid=" + uid + ")"
5820 + " is not allowed to send as package " + packageName;
5821 Log.w(TAG, msg);
5822 throw new SecurityException(msg);
5823 }
5824 }
5825 } catch (RemoteException e) {
5826 throw new SecurityException(e);
5827 }
5828 HistoryRecord activity = null;
5829 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005830 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005831 if (index < 0) {
5832 return null;
5833 }
5834 activity = (HistoryRecord)mHistory.get(index);
5835 if (activity.finishing) {
5836 return null;
5837 }
5838 }
5839
5840 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5841 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5842 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5843 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5844 |PendingIntent.FLAG_UPDATE_CURRENT);
5845
5846 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5847 type, packageName, activity, resultWho,
5848 requestCode, intent, resolvedType, flags);
5849 WeakReference<PendingIntentRecord> ref;
5850 ref = mIntentSenderRecords.get(key);
5851 PendingIntentRecord rec = ref != null ? ref.get() : null;
5852 if (rec != null) {
5853 if (!cancelCurrent) {
5854 if (updateCurrent) {
5855 rec.key.requestIntent.replaceExtras(intent);
5856 }
5857 return rec;
5858 }
5859 rec.canceled = true;
5860 mIntentSenderRecords.remove(key);
5861 }
5862 if (noCreate) {
5863 return rec;
5864 }
5865 rec = new PendingIntentRecord(this, key, callingUid);
5866 mIntentSenderRecords.put(key, rec.ref);
5867 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5868 if (activity.pendingResults == null) {
5869 activity.pendingResults
5870 = new HashSet<WeakReference<PendingIntentRecord>>();
5871 }
5872 activity.pendingResults.add(rec.ref);
5873 }
5874 return rec;
5875 }
5876 }
5877
5878 public void cancelIntentSender(IIntentSender sender) {
5879 if (!(sender instanceof PendingIntentRecord)) {
5880 return;
5881 }
5882 synchronized(this) {
5883 PendingIntentRecord rec = (PendingIntentRecord)sender;
5884 try {
5885 int uid = ActivityThread.getPackageManager()
5886 .getPackageUid(rec.key.packageName);
5887 if (uid != Binder.getCallingUid()) {
5888 String msg = "Permission Denial: cancelIntentSender() from pid="
5889 + Binder.getCallingPid()
5890 + ", uid=" + Binder.getCallingUid()
5891 + " is not allowed to cancel packges "
5892 + rec.key.packageName;
5893 Log.w(TAG, msg);
5894 throw new SecurityException(msg);
5895 }
5896 } catch (RemoteException e) {
5897 throw new SecurityException(e);
5898 }
5899 cancelIntentSenderLocked(rec, true);
5900 }
5901 }
5902
5903 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5904 rec.canceled = true;
5905 mIntentSenderRecords.remove(rec.key);
5906 if (cleanActivity && rec.key.activity != null) {
5907 rec.key.activity.pendingResults.remove(rec.ref);
5908 }
5909 }
5910
5911 public String getPackageForIntentSender(IIntentSender pendingResult) {
5912 if (!(pendingResult instanceof PendingIntentRecord)) {
5913 return null;
5914 }
5915 synchronized(this) {
5916 try {
5917 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5918 return res.key.packageName;
5919 } catch (ClassCastException e) {
5920 }
5921 }
5922 return null;
5923 }
5924
5925 public void setProcessLimit(int max) {
5926 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5927 "setProcessLimit()");
5928 mProcessLimit = max;
5929 }
5930
5931 public int getProcessLimit() {
5932 return mProcessLimit;
5933 }
5934
5935 void foregroundTokenDied(ForegroundToken token) {
5936 synchronized (ActivityManagerService.this) {
5937 synchronized (mPidsSelfLocked) {
5938 ForegroundToken cur
5939 = mForegroundProcesses.get(token.pid);
5940 if (cur != token) {
5941 return;
5942 }
5943 mForegroundProcesses.remove(token.pid);
5944 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5945 if (pr == null) {
5946 return;
5947 }
5948 pr.forcingToForeground = null;
5949 pr.foregroundServices = false;
5950 }
5951 updateOomAdjLocked();
5952 }
5953 }
5954
5955 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5956 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5957 "setProcessForeground()");
5958 synchronized(this) {
5959 boolean changed = false;
5960
5961 synchronized (mPidsSelfLocked) {
5962 ProcessRecord pr = mPidsSelfLocked.get(pid);
5963 if (pr == null) {
5964 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5965 return;
5966 }
5967 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5968 if (oldToken != null) {
5969 oldToken.token.unlinkToDeath(oldToken, 0);
5970 mForegroundProcesses.remove(pid);
5971 pr.forcingToForeground = null;
5972 changed = true;
5973 }
5974 if (isForeground && token != null) {
5975 ForegroundToken newToken = new ForegroundToken() {
5976 public void binderDied() {
5977 foregroundTokenDied(this);
5978 }
5979 };
5980 newToken.pid = pid;
5981 newToken.token = token;
5982 try {
5983 token.linkToDeath(newToken, 0);
5984 mForegroundProcesses.put(pid, newToken);
5985 pr.forcingToForeground = token;
5986 changed = true;
5987 } catch (RemoteException e) {
5988 // If the process died while doing this, we will later
5989 // do the cleanup with the process death link.
5990 }
5991 }
5992 }
5993
5994 if (changed) {
5995 updateOomAdjLocked();
5996 }
5997 }
5998 }
5999
6000 // =========================================================
6001 // PERMISSIONS
6002 // =========================================================
6003
6004 static class PermissionController extends IPermissionController.Stub {
6005 ActivityManagerService mActivityManagerService;
6006 PermissionController(ActivityManagerService activityManagerService) {
6007 mActivityManagerService = activityManagerService;
6008 }
6009
6010 public boolean checkPermission(String permission, int pid, int uid) {
6011 return mActivityManagerService.checkPermission(permission, pid,
6012 uid) == PackageManager.PERMISSION_GRANTED;
6013 }
6014 }
6015
6016 /**
6017 * This can be called with or without the global lock held.
6018 */
6019 int checkComponentPermission(String permission, int pid, int uid,
6020 int reqUid) {
6021 // We might be performing an operation on behalf of an indirect binder
6022 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6023 // client identity accordingly before proceeding.
6024 Identity tlsIdentity = sCallerIdentity.get();
6025 if (tlsIdentity != null) {
6026 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6027 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6028 uid = tlsIdentity.uid;
6029 pid = tlsIdentity.pid;
6030 }
6031
6032 // Root, system server and our own process get to do everything.
6033 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6034 !Process.supportsProcesses()) {
6035 return PackageManager.PERMISSION_GRANTED;
6036 }
6037 // If the target requires a specific UID, always fail for others.
6038 if (reqUid >= 0 && uid != reqUid) {
6039 return PackageManager.PERMISSION_DENIED;
6040 }
6041 if (permission == null) {
6042 return PackageManager.PERMISSION_GRANTED;
6043 }
6044 try {
6045 return ActivityThread.getPackageManager()
6046 .checkUidPermission(permission, uid);
6047 } catch (RemoteException e) {
6048 // Should never happen, but if it does... deny!
6049 Log.e(TAG, "PackageManager is dead?!?", e);
6050 }
6051 return PackageManager.PERMISSION_DENIED;
6052 }
6053
6054 /**
6055 * As the only public entry point for permissions checking, this method
6056 * can enforce the semantic that requesting a check on a null global
6057 * permission is automatically denied. (Internally a null permission
6058 * string is used when calling {@link #checkComponentPermission} in cases
6059 * when only uid-based security is needed.)
6060 *
6061 * This can be called with or without the global lock held.
6062 */
6063 public int checkPermission(String permission, int pid, int uid) {
6064 if (permission == null) {
6065 return PackageManager.PERMISSION_DENIED;
6066 }
6067 return checkComponentPermission(permission, pid, uid, -1);
6068 }
6069
6070 /**
6071 * Binder IPC calls go through the public entry point.
6072 * This can be called with or without the global lock held.
6073 */
6074 int checkCallingPermission(String permission) {
6075 return checkPermission(permission,
6076 Binder.getCallingPid(),
6077 Binder.getCallingUid());
6078 }
6079
6080 /**
6081 * This can be called with or without the global lock held.
6082 */
6083 void enforceCallingPermission(String permission, String func) {
6084 if (checkCallingPermission(permission)
6085 == PackageManager.PERMISSION_GRANTED) {
6086 return;
6087 }
6088
6089 String msg = "Permission Denial: " + func + " from pid="
6090 + Binder.getCallingPid()
6091 + ", uid=" + Binder.getCallingUid()
6092 + " requires " + permission;
6093 Log.w(TAG, msg);
6094 throw new SecurityException(msg);
6095 }
6096
6097 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6098 ProviderInfo pi, int uid, int modeFlags) {
6099 try {
6100 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6101 if ((pi.readPermission != null) &&
6102 (pm.checkUidPermission(pi.readPermission, uid)
6103 != PackageManager.PERMISSION_GRANTED)) {
6104 return false;
6105 }
6106 }
6107 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6108 if ((pi.writePermission != null) &&
6109 (pm.checkUidPermission(pi.writePermission, uid)
6110 != PackageManager.PERMISSION_GRANTED)) {
6111 return false;
6112 }
6113 }
6114 return true;
6115 } catch (RemoteException e) {
6116 return false;
6117 }
6118 }
6119
6120 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6121 int modeFlags) {
6122 // Root gets to do everything.
6123 if (uid == 0 || !Process.supportsProcesses()) {
6124 return true;
6125 }
6126 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6127 if (perms == null) return false;
6128 UriPermission perm = perms.get(uri);
6129 if (perm == null) return false;
6130 return (modeFlags&perm.modeFlags) == modeFlags;
6131 }
6132
6133 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6134 // Another redirected-binder-call permissions check as in
6135 // {@link checkComponentPermission}.
6136 Identity tlsIdentity = sCallerIdentity.get();
6137 if (tlsIdentity != null) {
6138 uid = tlsIdentity.uid;
6139 pid = tlsIdentity.pid;
6140 }
6141
6142 // Our own process gets to do everything.
6143 if (pid == MY_PID) {
6144 return PackageManager.PERMISSION_GRANTED;
6145 }
6146 synchronized(this) {
6147 return checkUriPermissionLocked(uri, uid, modeFlags)
6148 ? PackageManager.PERMISSION_GRANTED
6149 : PackageManager.PERMISSION_DENIED;
6150 }
6151 }
6152
6153 private void grantUriPermissionLocked(int callingUid,
6154 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6155 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6156 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6157 if (modeFlags == 0) {
6158 return;
6159 }
6160
6161 final IPackageManager pm = ActivityThread.getPackageManager();
6162
6163 // If this is not a content: uri, we can't do anything with it.
6164 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6165 return;
6166 }
6167
6168 String name = uri.getAuthority();
6169 ProviderInfo pi = null;
6170 ContentProviderRecord cpr
6171 = (ContentProviderRecord)mProvidersByName.get(name);
6172 if (cpr != null) {
6173 pi = cpr.info;
6174 } else {
6175 try {
6176 pi = pm.resolveContentProvider(name,
6177 PackageManager.GET_URI_PERMISSION_PATTERNS);
6178 } catch (RemoteException ex) {
6179 }
6180 }
6181 if (pi == null) {
6182 Log.w(TAG, "No content provider found for: " + name);
6183 return;
6184 }
6185
6186 int targetUid;
6187 try {
6188 targetUid = pm.getPackageUid(targetPkg);
6189 if (targetUid < 0) {
6190 return;
6191 }
6192 } catch (RemoteException ex) {
6193 return;
6194 }
6195
6196 // First... does the target actually need this permission?
6197 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6198 // No need to grant the target this permission.
6199 return;
6200 }
6201
6202 // Second... maybe someone else has already granted the
6203 // permission?
6204 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6205 // No need to grant the target this permission.
6206 return;
6207 }
6208
6209 // Third... is the provider allowing granting of URI permissions?
6210 if (!pi.grantUriPermissions) {
6211 throw new SecurityException("Provider " + pi.packageName
6212 + "/" + pi.name
6213 + " does not allow granting of Uri permissions (uri "
6214 + uri + ")");
6215 }
6216 if (pi.uriPermissionPatterns != null) {
6217 final int N = pi.uriPermissionPatterns.length;
6218 boolean allowed = false;
6219 for (int i=0; i<N; i++) {
6220 if (pi.uriPermissionPatterns[i] != null
6221 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6222 allowed = true;
6223 break;
6224 }
6225 }
6226 if (!allowed) {
6227 throw new SecurityException("Provider " + pi.packageName
6228 + "/" + pi.name
6229 + " does not allow granting of permission to path of Uri "
6230 + uri);
6231 }
6232 }
6233
6234 // Fourth... does the caller itself have permission to access
6235 // this uri?
6236 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6237 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6238 throw new SecurityException("Uid " + callingUid
6239 + " does not have permission to uri " + uri);
6240 }
6241 }
6242
6243 // Okay! So here we are: the caller has the assumed permission
6244 // to the uri, and the target doesn't. Let's now give this to
6245 // the target.
6246
6247 HashMap<Uri, UriPermission> targetUris
6248 = mGrantedUriPermissions.get(targetUid);
6249 if (targetUris == null) {
6250 targetUris = new HashMap<Uri, UriPermission>();
6251 mGrantedUriPermissions.put(targetUid, targetUris);
6252 }
6253
6254 UriPermission perm = targetUris.get(uri);
6255 if (perm == null) {
6256 perm = new UriPermission(targetUid, uri);
6257 targetUris.put(uri, perm);
6258
6259 }
6260 perm.modeFlags |= modeFlags;
6261 if (activity == null) {
6262 perm.globalModeFlags |= modeFlags;
6263 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6264 perm.readActivities.add(activity);
6265 if (activity.readUriPermissions == null) {
6266 activity.readUriPermissions = new HashSet<UriPermission>();
6267 }
6268 activity.readUriPermissions.add(perm);
6269 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6270 perm.writeActivities.add(activity);
6271 if (activity.writeUriPermissions == null) {
6272 activity.writeUriPermissions = new HashSet<UriPermission>();
6273 }
6274 activity.writeUriPermissions.add(perm);
6275 }
6276 }
6277
6278 private void grantUriPermissionFromIntentLocked(int callingUid,
6279 String targetPkg, Intent intent, HistoryRecord activity) {
6280 if (intent == null) {
6281 return;
6282 }
6283 Uri data = intent.getData();
6284 if (data == null) {
6285 return;
6286 }
6287 grantUriPermissionLocked(callingUid, targetPkg, data,
6288 intent.getFlags(), activity);
6289 }
6290
6291 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6292 Uri uri, int modeFlags) {
6293 synchronized(this) {
6294 final ProcessRecord r = getRecordForAppLocked(caller);
6295 if (r == null) {
6296 throw new SecurityException("Unable to find app for caller "
6297 + caller
6298 + " when granting permission to uri " + uri);
6299 }
6300 if (targetPkg == null) {
6301 Log.w(TAG, "grantUriPermission: null target");
6302 return;
6303 }
6304 if (uri == null) {
6305 Log.w(TAG, "grantUriPermission: null uri");
6306 return;
6307 }
6308
6309 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6310 null);
6311 }
6312 }
6313
6314 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6315 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6316 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6317 HashMap<Uri, UriPermission> perms
6318 = mGrantedUriPermissions.get(perm.uid);
6319 if (perms != null) {
6320 perms.remove(perm.uri);
6321 if (perms.size() == 0) {
6322 mGrantedUriPermissions.remove(perm.uid);
6323 }
6324 }
6325 }
6326 }
6327
6328 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6329 if (activity.readUriPermissions != null) {
6330 for (UriPermission perm : activity.readUriPermissions) {
6331 perm.readActivities.remove(activity);
6332 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6333 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6334 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6335 removeUriPermissionIfNeededLocked(perm);
6336 }
6337 }
6338 }
6339 if (activity.writeUriPermissions != null) {
6340 for (UriPermission perm : activity.writeUriPermissions) {
6341 perm.writeActivities.remove(activity);
6342 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6343 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6344 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6345 removeUriPermissionIfNeededLocked(perm);
6346 }
6347 }
6348 }
6349 }
6350
6351 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6352 int modeFlags) {
6353 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6354 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6355 if (modeFlags == 0) {
6356 return;
6357 }
6358
6359 final IPackageManager pm = ActivityThread.getPackageManager();
6360
6361 final String authority = uri.getAuthority();
6362 ProviderInfo pi = null;
6363 ContentProviderRecord cpr
6364 = (ContentProviderRecord)mProvidersByName.get(authority);
6365 if (cpr != null) {
6366 pi = cpr.info;
6367 } else {
6368 try {
6369 pi = pm.resolveContentProvider(authority,
6370 PackageManager.GET_URI_PERMISSION_PATTERNS);
6371 } catch (RemoteException ex) {
6372 }
6373 }
6374 if (pi == null) {
6375 Log.w(TAG, "No content provider found for: " + authority);
6376 return;
6377 }
6378
6379 // Does the caller have this permission on the URI?
6380 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6381 // Right now, if you are not the original owner of the permission,
6382 // you are not allowed to revoke it.
6383 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6384 throw new SecurityException("Uid " + callingUid
6385 + " does not have permission to uri " + uri);
6386 //}
6387 }
6388
6389 // Go through all of the permissions and remove any that match.
6390 final List<String> SEGMENTS = uri.getPathSegments();
6391 if (SEGMENTS != null) {
6392 final int NS = SEGMENTS.size();
6393 int N = mGrantedUriPermissions.size();
6394 for (int i=0; i<N; i++) {
6395 HashMap<Uri, UriPermission> perms
6396 = mGrantedUriPermissions.valueAt(i);
6397 Iterator<UriPermission> it = perms.values().iterator();
6398 toploop:
6399 while (it.hasNext()) {
6400 UriPermission perm = it.next();
6401 Uri targetUri = perm.uri;
6402 if (!authority.equals(targetUri.getAuthority())) {
6403 continue;
6404 }
6405 List<String> targetSegments = targetUri.getPathSegments();
6406 if (targetSegments == null) {
6407 continue;
6408 }
6409 if (targetSegments.size() < NS) {
6410 continue;
6411 }
6412 for (int j=0; j<NS; j++) {
6413 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6414 continue toploop;
6415 }
6416 }
6417 perm.clearModes(modeFlags);
6418 if (perm.modeFlags == 0) {
6419 it.remove();
6420 }
6421 }
6422 if (perms.size() == 0) {
6423 mGrantedUriPermissions.remove(
6424 mGrantedUriPermissions.keyAt(i));
6425 N--;
6426 i--;
6427 }
6428 }
6429 }
6430 }
6431
6432 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6433 int modeFlags) {
6434 synchronized(this) {
6435 final ProcessRecord r = getRecordForAppLocked(caller);
6436 if (r == null) {
6437 throw new SecurityException("Unable to find app for caller "
6438 + caller
6439 + " when revoking permission to uri " + uri);
6440 }
6441 if (uri == null) {
6442 Log.w(TAG, "revokeUriPermission: null uri");
6443 return;
6444 }
6445
6446 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6447 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6448 if (modeFlags == 0) {
6449 return;
6450 }
6451
6452 final IPackageManager pm = ActivityThread.getPackageManager();
6453
6454 final String authority = uri.getAuthority();
6455 ProviderInfo pi = null;
6456 ContentProviderRecord cpr
6457 = (ContentProviderRecord)mProvidersByName.get(authority);
6458 if (cpr != null) {
6459 pi = cpr.info;
6460 } else {
6461 try {
6462 pi = pm.resolveContentProvider(authority,
6463 PackageManager.GET_URI_PERMISSION_PATTERNS);
6464 } catch (RemoteException ex) {
6465 }
6466 }
6467 if (pi == null) {
6468 Log.w(TAG, "No content provider found for: " + authority);
6469 return;
6470 }
6471
6472 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6473 }
6474 }
6475
6476 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6477 synchronized (this) {
6478 ProcessRecord app =
6479 who != null ? getRecordForAppLocked(who) : null;
6480 if (app == null) return;
6481
6482 Message msg = Message.obtain();
6483 msg.what = WAIT_FOR_DEBUGGER_MSG;
6484 msg.obj = app;
6485 msg.arg1 = waiting ? 1 : 0;
6486 mHandler.sendMessage(msg);
6487 }
6488 }
6489
6490 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6491 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006492 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006493 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006494 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006495 }
6496
6497 // =========================================================
6498 // TASK MANAGEMENT
6499 // =========================================================
6500
6501 public List getTasks(int maxNum, int flags,
6502 IThumbnailReceiver receiver) {
6503 ArrayList list = new ArrayList();
6504
6505 PendingThumbnailsRecord pending = null;
6506 IApplicationThread topThumbnail = null;
6507 HistoryRecord topRecord = null;
6508
6509 synchronized(this) {
6510 if (localLOGV) Log.v(
6511 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6512 + ", receiver=" + receiver);
6513
6514 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6515 != PackageManager.PERMISSION_GRANTED) {
6516 if (receiver != null) {
6517 // If the caller wants to wait for pending thumbnails,
6518 // it ain't gonna get them.
6519 try {
6520 receiver.finished();
6521 } catch (RemoteException ex) {
6522 }
6523 }
6524 String msg = "Permission Denial: getTasks() from pid="
6525 + Binder.getCallingPid()
6526 + ", uid=" + Binder.getCallingUid()
6527 + " requires " + android.Manifest.permission.GET_TASKS;
6528 Log.w(TAG, msg);
6529 throw new SecurityException(msg);
6530 }
6531
6532 int pos = mHistory.size()-1;
6533 HistoryRecord next =
6534 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6535 HistoryRecord top = null;
6536 CharSequence topDescription = null;
6537 TaskRecord curTask = null;
6538 int numActivities = 0;
6539 int numRunning = 0;
6540 while (pos >= 0 && maxNum > 0) {
6541 final HistoryRecord r = next;
6542 pos--;
6543 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6544
6545 // Initialize state for next task if needed.
6546 if (top == null ||
6547 (top.state == ActivityState.INITIALIZING
6548 && top.task == r.task)) {
6549 top = r;
6550 topDescription = r.description;
6551 curTask = r.task;
6552 numActivities = numRunning = 0;
6553 }
6554
6555 // Add 'r' into the current task.
6556 numActivities++;
6557 if (r.app != null && r.app.thread != null) {
6558 numRunning++;
6559 }
6560 if (topDescription == null) {
6561 topDescription = r.description;
6562 }
6563
6564 if (localLOGV) Log.v(
6565 TAG, r.intent.getComponent().flattenToShortString()
6566 + ": task=" + r.task);
6567
6568 // If the next one is a different task, generate a new
6569 // TaskInfo entry for what we have.
6570 if (next == null || next.task != curTask) {
6571 ActivityManager.RunningTaskInfo ci
6572 = new ActivityManager.RunningTaskInfo();
6573 ci.id = curTask.taskId;
6574 ci.baseActivity = r.intent.getComponent();
6575 ci.topActivity = top.intent.getComponent();
6576 ci.thumbnail = top.thumbnail;
6577 ci.description = topDescription;
6578 ci.numActivities = numActivities;
6579 ci.numRunning = numRunning;
6580 //System.out.println(
6581 // "#" + maxNum + ": " + " descr=" + ci.description);
6582 if (ci.thumbnail == null && receiver != null) {
6583 if (localLOGV) Log.v(
6584 TAG, "State=" + top.state + "Idle=" + top.idle
6585 + " app=" + top.app
6586 + " thr=" + (top.app != null ? top.app.thread : null));
6587 if (top.state == ActivityState.RESUMED
6588 || top.state == ActivityState.PAUSING) {
6589 if (top.idle && top.app != null
6590 && top.app.thread != null) {
6591 topRecord = top;
6592 topThumbnail = top.app.thread;
6593 } else {
6594 top.thumbnailNeeded = true;
6595 }
6596 }
6597 if (pending == null) {
6598 pending = new PendingThumbnailsRecord(receiver);
6599 }
6600 pending.pendingRecords.add(top);
6601 }
6602 list.add(ci);
6603 maxNum--;
6604 top = null;
6605 }
6606 }
6607
6608 if (pending != null) {
6609 mPendingThumbnails.add(pending);
6610 }
6611 }
6612
6613 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6614
6615 if (topThumbnail != null) {
6616 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6617 try {
6618 topThumbnail.requestThumbnail(topRecord);
6619 } catch (Exception e) {
6620 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6621 sendPendingThumbnail(null, topRecord, null, null, true);
6622 }
6623 }
6624
6625 if (pending == null && receiver != null) {
6626 // In this case all thumbnails were available and the client
6627 // is being asked to be told when the remaining ones come in...
6628 // which is unusually, since the top-most currently running
6629 // activity should never have a canned thumbnail! Oh well.
6630 try {
6631 receiver.finished();
6632 } catch (RemoteException ex) {
6633 }
6634 }
6635
6636 return list;
6637 }
6638
6639 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6640 int flags) {
6641 synchronized (this) {
6642 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6643 "getRecentTasks()");
6644
6645 final int N = mRecentTasks.size();
6646 ArrayList<ActivityManager.RecentTaskInfo> res
6647 = new ArrayList<ActivityManager.RecentTaskInfo>(
6648 maxNum < N ? maxNum : N);
6649 for (int i=0; i<N && maxNum > 0; i++) {
6650 TaskRecord tr = mRecentTasks.get(i);
6651 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6652 || (tr.intent == null)
6653 || ((tr.intent.getFlags()
6654 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6655 ActivityManager.RecentTaskInfo rti
6656 = new ActivityManager.RecentTaskInfo();
6657 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6658 rti.baseIntent = new Intent(
6659 tr.intent != null ? tr.intent : tr.affinityIntent);
6660 rti.origActivity = tr.origActivity;
6661 res.add(rti);
6662 maxNum--;
6663 }
6664 }
6665 return res;
6666 }
6667 }
6668
6669 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6670 int j;
6671 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6672 TaskRecord jt = startTask;
6673
6674 // First look backwards
6675 for (j=startIndex-1; j>=0; j--) {
6676 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6677 if (r.task != jt) {
6678 jt = r.task;
6679 if (affinity.equals(jt.affinity)) {
6680 return j;
6681 }
6682 }
6683 }
6684
6685 // Now look forwards
6686 final int N = mHistory.size();
6687 jt = startTask;
6688 for (j=startIndex+1; j<N; j++) {
6689 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6690 if (r.task != jt) {
6691 if (affinity.equals(jt.affinity)) {
6692 return j;
6693 }
6694 jt = r.task;
6695 }
6696 }
6697
6698 // Might it be at the top?
6699 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6700 return N-1;
6701 }
6702
6703 return -1;
6704 }
6705
6706 /**
6707 * Perform a reset of the given task, if needed as part of launching it.
6708 * Returns the new HistoryRecord at the top of the task.
6709 */
6710 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6711 HistoryRecord newActivity) {
6712 boolean forceReset = (newActivity.info.flags
6713 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6714 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6715 if ((newActivity.info.flags
6716 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6717 forceReset = true;
6718 }
6719 }
6720
6721 final TaskRecord task = taskTop.task;
6722
6723 // We are going to move through the history list so that we can look
6724 // at each activity 'target' with 'below' either the interesting
6725 // activity immediately below it in the stack or null.
6726 HistoryRecord target = null;
6727 int targetI = 0;
6728 int taskTopI = -1;
6729 int replyChainEnd = -1;
6730 int lastReparentPos = -1;
6731 for (int i=mHistory.size()-1; i>=-1; i--) {
6732 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6733
6734 if (below != null && below.finishing) {
6735 continue;
6736 }
6737 if (target == null) {
6738 target = below;
6739 targetI = i;
6740 // If we were in the middle of a reply chain before this
6741 // task, it doesn't appear like the root of the chain wants
6742 // anything interesting, so drop it.
6743 replyChainEnd = -1;
6744 continue;
6745 }
6746
6747 final int flags = target.info.flags;
6748
6749 final boolean finishOnTaskLaunch =
6750 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6751 final boolean allowTaskReparenting =
6752 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6753
6754 if (target.task == task) {
6755 // We are inside of the task being reset... we'll either
6756 // finish this activity, push it out for another task,
6757 // or leave it as-is. We only do this
6758 // for activities that are not the root of the task (since
6759 // if we finish the root, we may no longer have the task!).
6760 if (taskTopI < 0) {
6761 taskTopI = targetI;
6762 }
6763 if (below != null && below.task == task) {
6764 final boolean clearWhenTaskReset =
6765 (target.intent.getFlags()
6766 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006767 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006768 // If this activity is sending a reply to a previous
6769 // activity, we can't do anything with it now until
6770 // we reach the start of the reply chain.
6771 // XXX note that we are assuming the result is always
6772 // to the previous activity, which is almost always
6773 // the case but we really shouldn't count on.
6774 if (replyChainEnd < 0) {
6775 replyChainEnd = targetI;
6776 }
Ed Heyl73798232009-03-24 21:32:21 -07006777 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006778 && target.taskAffinity != null
6779 && !target.taskAffinity.equals(task.affinity)) {
6780 // If this activity has an affinity for another
6781 // task, then we need to move it out of here. We will
6782 // move it as far out of the way as possible, to the
6783 // bottom of the activity stack. This also keeps it
6784 // correctly ordered with any activities we previously
6785 // moved.
6786 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6787 if (target.taskAffinity != null
6788 && target.taskAffinity.equals(p.task.affinity)) {
6789 // If the activity currently at the bottom has the
6790 // same task affinity as the one we are moving,
6791 // then merge it into the same task.
6792 target.task = p.task;
6793 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6794 + " out to bottom task " + p.task);
6795 } else {
6796 mCurTask++;
6797 if (mCurTask <= 0) {
6798 mCurTask = 1;
6799 }
6800 target.task = new TaskRecord(mCurTask, target.info, null,
6801 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6802 target.task.affinityIntent = target.intent;
6803 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6804 + " out to new task " + target.task);
6805 }
6806 mWindowManager.setAppGroupId(target, task.taskId);
6807 if (replyChainEnd < 0) {
6808 replyChainEnd = targetI;
6809 }
6810 int dstPos = 0;
6811 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6812 p = (HistoryRecord)mHistory.get(srcPos);
6813 if (p.finishing) {
6814 continue;
6815 }
6816 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6817 + " out to target's task " + target.task);
6818 task.numActivities--;
6819 p.task = target.task;
6820 target.task.numActivities++;
6821 mHistory.remove(srcPos);
6822 mHistory.add(dstPos, p);
6823 mWindowManager.moveAppToken(dstPos, p);
6824 mWindowManager.setAppGroupId(p, p.task.taskId);
6825 dstPos++;
6826 if (VALIDATE_TOKENS) {
6827 mWindowManager.validateAppTokens(mHistory);
6828 }
6829 i++;
6830 }
6831 if (taskTop == p) {
6832 taskTop = below;
6833 }
6834 if (taskTopI == replyChainEnd) {
6835 taskTopI = -1;
6836 }
6837 replyChainEnd = -1;
6838 addRecentTask(target.task);
6839 } else if (forceReset || finishOnTaskLaunch
6840 || clearWhenTaskReset) {
6841 // If the activity should just be removed -- either
6842 // because it asks for it, or the task should be
6843 // cleared -- then finish it and anything that is
6844 // part of its reply chain.
6845 if (clearWhenTaskReset) {
6846 // In this case, we want to finish this activity
6847 // and everything above it, so be sneaky and pretend
6848 // like these are all in the reply chain.
6849 replyChainEnd = targetI+1;
6850 while (replyChainEnd < mHistory.size() &&
6851 ((HistoryRecord)mHistory.get(
6852 replyChainEnd)).task == task) {
6853 replyChainEnd++;
6854 }
6855 replyChainEnd--;
6856 } else if (replyChainEnd < 0) {
6857 replyChainEnd = targetI;
6858 }
6859 HistoryRecord p = null;
6860 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6861 p = (HistoryRecord)mHistory.get(srcPos);
6862 if (p.finishing) {
6863 continue;
6864 }
6865 if (finishActivityLocked(p, srcPos,
6866 Activity.RESULT_CANCELED, null, "reset")) {
6867 replyChainEnd--;
6868 srcPos--;
6869 }
6870 }
6871 if (taskTop == p) {
6872 taskTop = below;
6873 }
6874 if (taskTopI == replyChainEnd) {
6875 taskTopI = -1;
6876 }
6877 replyChainEnd = -1;
6878 } else {
6879 // If we were in the middle of a chain, well the
6880 // activity that started it all doesn't want anything
6881 // special, so leave it all as-is.
6882 replyChainEnd = -1;
6883 }
6884 } else {
6885 // Reached the bottom of the task -- any reply chain
6886 // should be left as-is.
6887 replyChainEnd = -1;
6888 }
6889
6890 } else if (target.resultTo != null) {
6891 // If this activity is sending a reply to a previous
6892 // activity, we can't do anything with it now until
6893 // we reach the start of the reply chain.
6894 // XXX note that we are assuming the result is always
6895 // to the previous activity, which is almost always
6896 // the case but we really shouldn't count on.
6897 if (replyChainEnd < 0) {
6898 replyChainEnd = targetI;
6899 }
6900
6901 } else if (taskTopI >= 0 && allowTaskReparenting
6902 && task.affinity != null
6903 && task.affinity.equals(target.taskAffinity)) {
6904 // We are inside of another task... if this activity has
6905 // an affinity for our task, then either remove it if we are
6906 // clearing or move it over to our task. Note that
6907 // we currently punt on the case where we are resetting a
6908 // task that is not at the top but who has activities above
6909 // with an affinity to it... this is really not a normal
6910 // case, and we will need to later pull that task to the front
6911 // and usually at that point we will do the reset and pick
6912 // up those remaining activities. (This only happens if
6913 // someone starts an activity in a new task from an activity
6914 // in a task that is not currently on top.)
6915 if (forceReset || finishOnTaskLaunch) {
6916 if (replyChainEnd < 0) {
6917 replyChainEnd = targetI;
6918 }
6919 HistoryRecord p = null;
6920 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6921 p = (HistoryRecord)mHistory.get(srcPos);
6922 if (p.finishing) {
6923 continue;
6924 }
6925 if (finishActivityLocked(p, srcPos,
6926 Activity.RESULT_CANCELED, null, "reset")) {
6927 taskTopI--;
6928 lastReparentPos--;
6929 replyChainEnd--;
6930 srcPos--;
6931 }
6932 }
6933 replyChainEnd = -1;
6934 } else {
6935 if (replyChainEnd < 0) {
6936 replyChainEnd = targetI;
6937 }
6938 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6939 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6940 if (p.finishing) {
6941 continue;
6942 }
6943 if (lastReparentPos < 0) {
6944 lastReparentPos = taskTopI;
6945 taskTop = p;
6946 } else {
6947 lastReparentPos--;
6948 }
6949 mHistory.remove(srcPos);
6950 p.task.numActivities--;
6951 p.task = task;
6952 mHistory.add(lastReparentPos, p);
6953 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6954 + " in to resetting task " + task);
6955 task.numActivities++;
6956 mWindowManager.moveAppToken(lastReparentPos, p);
6957 mWindowManager.setAppGroupId(p, p.task.taskId);
6958 if (VALIDATE_TOKENS) {
6959 mWindowManager.validateAppTokens(mHistory);
6960 }
6961 }
6962 replyChainEnd = -1;
6963
6964 // Now we've moved it in to place... but what if this is
6965 // a singleTop activity and we have put it on top of another
6966 // instance of the same activity? Then we drop the instance
6967 // below so it remains singleTop.
6968 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6969 for (int j=lastReparentPos-1; j>=0; j--) {
6970 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6971 if (p.finishing) {
6972 continue;
6973 }
6974 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6975 if (finishActivityLocked(p, j,
6976 Activity.RESULT_CANCELED, null, "replace")) {
6977 taskTopI--;
6978 lastReparentPos--;
6979 }
6980 }
6981 }
6982 }
6983 }
6984 }
6985
6986 target = below;
6987 targetI = i;
6988 }
6989
6990 return taskTop;
6991 }
6992
6993 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006994 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006995 */
6996 public void moveTaskToFront(int task) {
6997 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6998 "moveTaskToFront()");
6999
7000 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007001 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7002 Binder.getCallingUid(), "Task to front")) {
7003 return;
7004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007005 final long origId = Binder.clearCallingIdentity();
7006 try {
7007 int N = mRecentTasks.size();
7008 for (int i=0; i<N; i++) {
7009 TaskRecord tr = mRecentTasks.get(i);
7010 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007011 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007012 return;
7013 }
7014 }
7015 for (int i=mHistory.size()-1; i>=0; i--) {
7016 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7017 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007018 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007019 return;
7020 }
7021 }
7022 } finally {
7023 Binder.restoreCallingIdentity(origId);
7024 }
7025 }
7026 }
7027
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007028 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007029 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7030
7031 final int task = tr.taskId;
7032 int top = mHistory.size()-1;
7033
7034 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7035 // nothing to do!
7036 return;
7037 }
7038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007039 ArrayList moved = new ArrayList();
7040
7041 // Applying the affinities may have removed entries from the history,
7042 // so get the size again.
7043 top = mHistory.size()-1;
7044 int pos = top;
7045
7046 // Shift all activities with this task up to the top
7047 // of the stack, keeping them in the same internal order.
7048 while (pos >= 0) {
7049 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7050 if (localLOGV) Log.v(
7051 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7052 boolean first = true;
7053 if (r.task.taskId == task) {
7054 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7055 mHistory.remove(pos);
7056 mHistory.add(top, r);
7057 moved.add(0, r);
7058 top--;
7059 if (first) {
7060 addRecentTask(r.task);
7061 first = false;
7062 }
7063 }
7064 pos--;
7065 }
7066
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007067 if (DEBUG_TRANSITION) Log.v(TAG,
7068 "Prepare to front transition: task=" + tr);
7069 if (reason != null &&
7070 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7071 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7072 HistoryRecord r = topRunningActivityLocked(null);
7073 if (r != null) {
7074 mNoAnimActivities.add(r);
7075 }
7076 } else {
7077 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7078 }
7079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007080 mWindowManager.moveAppTokensToTop(moved);
7081 if (VALIDATE_TOKENS) {
7082 mWindowManager.validateAppTokens(mHistory);
7083 }
7084
7085 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007086 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007087 }
7088
7089 private final void finishTaskMove(int task) {
7090 resumeTopActivityLocked(null);
7091 }
7092
7093 public void moveTaskToBack(int task) {
7094 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7095 "moveTaskToBack()");
7096
7097 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007098 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7099 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7100 Binder.getCallingUid(), "Task to back")) {
7101 return;
7102 }
7103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007104 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007105 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007106 Binder.restoreCallingIdentity(origId);
7107 }
7108 }
7109
7110 /**
7111 * Moves an activity, and all of the other activities within the same task, to the bottom
7112 * of the history stack. The activity's order within the task is unchanged.
7113 *
7114 * @param token A reference to the activity we wish to move
7115 * @param nonRoot If false then this only works if the activity is the root
7116 * of a task; if true it will work for any activity in a task.
7117 * @return Returns true if the move completed, false if not.
7118 */
7119 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7120 synchronized(this) {
7121 final long origId = Binder.clearCallingIdentity();
7122 int taskId = getTaskForActivityLocked(token, !nonRoot);
7123 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007124 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007125 }
7126 Binder.restoreCallingIdentity(origId);
7127 }
7128 return false;
7129 }
7130
7131 /**
7132 * Worker method for rearranging history stack. Implements the function of moving all
7133 * activities for a specific task (gathering them if disjoint) into a single group at the
7134 * bottom of the stack.
7135 *
7136 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7137 * to premeptively cancel the move.
7138 *
7139 * @param task The taskId to collect and move to the bottom.
7140 * @return Returns true if the move completed, false if not.
7141 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007142 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007143 Log.i(TAG, "moveTaskToBack: " + task);
7144
7145 // If we have a watcher, preflight the move before committing to it. First check
7146 // for *other* available tasks, but if none are available, then try again allowing the
7147 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007148 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007149 HistoryRecord next = topRunningActivityLocked(null, task);
7150 if (next == null) {
7151 next = topRunningActivityLocked(null, 0);
7152 }
7153 if (next != null) {
7154 // ask watcher if this is allowed
7155 boolean moveOK = true;
7156 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007157 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007158 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007159 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007160 }
7161 if (!moveOK) {
7162 return false;
7163 }
7164 }
7165 }
7166
7167 ArrayList moved = new ArrayList();
7168
7169 if (DEBUG_TRANSITION) Log.v(TAG,
7170 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007171
7172 final int N = mHistory.size();
7173 int bottom = 0;
7174 int pos = 0;
7175
7176 // Shift all activities with this task down to the bottom
7177 // of the stack, keeping them in the same internal order.
7178 while (pos < N) {
7179 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7180 if (localLOGV) Log.v(
7181 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7182 if (r.task.taskId == task) {
7183 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7184 mHistory.remove(pos);
7185 mHistory.add(bottom, r);
7186 moved.add(r);
7187 bottom++;
7188 }
7189 pos++;
7190 }
7191
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007192 if (reason != null &&
7193 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7194 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7195 HistoryRecord r = topRunningActivityLocked(null);
7196 if (r != null) {
7197 mNoAnimActivities.add(r);
7198 }
7199 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007200 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007202 mWindowManager.moveAppTokensToBottom(moved);
7203 if (VALIDATE_TOKENS) {
7204 mWindowManager.validateAppTokens(mHistory);
7205 }
7206
7207 finishTaskMove(task);
7208 return true;
7209 }
7210
7211 public void moveTaskBackwards(int task) {
7212 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7213 "moveTaskBackwards()");
7214
7215 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007216 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7217 Binder.getCallingUid(), "Task backwards")) {
7218 return;
7219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007220 final long origId = Binder.clearCallingIdentity();
7221 moveTaskBackwardsLocked(task);
7222 Binder.restoreCallingIdentity(origId);
7223 }
7224 }
7225
7226 private final void moveTaskBackwardsLocked(int task) {
7227 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7228 }
7229
7230 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7231 synchronized(this) {
7232 return getTaskForActivityLocked(token, onlyRoot);
7233 }
7234 }
7235
7236 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7237 final int N = mHistory.size();
7238 TaskRecord lastTask = null;
7239 for (int i=0; i<N; i++) {
7240 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7241 if (r == token) {
7242 if (!onlyRoot || lastTask != r.task) {
7243 return r.task.taskId;
7244 }
7245 return -1;
7246 }
7247 lastTask = r.task;
7248 }
7249
7250 return -1;
7251 }
7252
7253 /**
7254 * Returns the top activity in any existing task matching the given
7255 * Intent. Returns null if no such task is found.
7256 */
7257 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7258 ComponentName cls = intent.getComponent();
7259 if (info.targetActivity != null) {
7260 cls = new ComponentName(info.packageName, info.targetActivity);
7261 }
7262
7263 TaskRecord cp = null;
7264
7265 final int N = mHistory.size();
7266 for (int i=(N-1); i>=0; i--) {
7267 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7268 if (!r.finishing && r.task != cp
7269 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7270 cp = r.task;
7271 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7272 // + "/aff=" + r.task.affinity + " to new cls="
7273 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7274 if (r.task.affinity != null) {
7275 if (r.task.affinity.equals(info.taskAffinity)) {
7276 //Log.i(TAG, "Found matching affinity!");
7277 return r;
7278 }
7279 } else if (r.task.intent != null
7280 && r.task.intent.getComponent().equals(cls)) {
7281 //Log.i(TAG, "Found matching class!");
7282 //dump();
7283 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7284 return r;
7285 } else if (r.task.affinityIntent != null
7286 && r.task.affinityIntent.getComponent().equals(cls)) {
7287 //Log.i(TAG, "Found matching class!");
7288 //dump();
7289 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7290 return r;
7291 }
7292 }
7293 }
7294
7295 return null;
7296 }
7297
7298 /**
7299 * Returns the first activity (starting from the top of the stack) that
7300 * is the same as the given activity. Returns null if no such activity
7301 * is found.
7302 */
7303 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7304 ComponentName cls = intent.getComponent();
7305 if (info.targetActivity != null) {
7306 cls = new ComponentName(info.packageName, info.targetActivity);
7307 }
7308
7309 final int N = mHistory.size();
7310 for (int i=(N-1); i>=0; i--) {
7311 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7312 if (!r.finishing) {
7313 if (r.intent.getComponent().equals(cls)) {
7314 //Log.i(TAG, "Found matching class!");
7315 //dump();
7316 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7317 return r;
7318 }
7319 }
7320 }
7321
7322 return null;
7323 }
7324
7325 public void finishOtherInstances(IBinder token, ComponentName className) {
7326 synchronized(this) {
7327 final long origId = Binder.clearCallingIdentity();
7328
7329 int N = mHistory.size();
7330 TaskRecord lastTask = null;
7331 for (int i=0; i<N; i++) {
7332 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7333 if (r.realActivity.equals(className)
7334 && r != token && lastTask != r.task) {
7335 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7336 null, "others")) {
7337 i--;
7338 N--;
7339 }
7340 }
7341 lastTask = r.task;
7342 }
7343
7344 Binder.restoreCallingIdentity(origId);
7345 }
7346 }
7347
7348 // =========================================================
7349 // THUMBNAILS
7350 // =========================================================
7351
7352 public void reportThumbnail(IBinder token,
7353 Bitmap thumbnail, CharSequence description) {
7354 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7355 final long origId = Binder.clearCallingIdentity();
7356 sendPendingThumbnail(null, token, thumbnail, description, true);
7357 Binder.restoreCallingIdentity(origId);
7358 }
7359
7360 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7361 Bitmap thumbnail, CharSequence description, boolean always) {
7362 TaskRecord task = null;
7363 ArrayList receivers = null;
7364
7365 //System.out.println("Send pending thumbnail: " + r);
7366
7367 synchronized(this) {
7368 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007369 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007370 if (index < 0) {
7371 return;
7372 }
7373 r = (HistoryRecord)mHistory.get(index);
7374 }
7375 if (thumbnail == null) {
7376 thumbnail = r.thumbnail;
7377 description = r.description;
7378 }
7379 if (thumbnail == null && !always) {
7380 // If there is no thumbnail, and this entry is not actually
7381 // going away, then abort for now and pick up the next
7382 // thumbnail we get.
7383 return;
7384 }
7385 task = r.task;
7386
7387 int N = mPendingThumbnails.size();
7388 int i=0;
7389 while (i<N) {
7390 PendingThumbnailsRecord pr =
7391 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7392 //System.out.println("Looking in " + pr.pendingRecords);
7393 if (pr.pendingRecords.remove(r)) {
7394 if (receivers == null) {
7395 receivers = new ArrayList();
7396 }
7397 receivers.add(pr);
7398 if (pr.pendingRecords.size() == 0) {
7399 pr.finished = true;
7400 mPendingThumbnails.remove(i);
7401 N--;
7402 continue;
7403 }
7404 }
7405 i++;
7406 }
7407 }
7408
7409 if (receivers != null) {
7410 final int N = receivers.size();
7411 for (int i=0; i<N; i++) {
7412 try {
7413 PendingThumbnailsRecord pr =
7414 (PendingThumbnailsRecord)receivers.get(i);
7415 pr.receiver.newThumbnail(
7416 task != null ? task.taskId : -1, thumbnail, description);
7417 if (pr.finished) {
7418 pr.receiver.finished();
7419 }
7420 } catch (Exception e) {
7421 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7422 }
7423 }
7424 }
7425 }
7426
7427 // =========================================================
7428 // CONTENT PROVIDERS
7429 // =========================================================
7430
7431 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7432 List providers = null;
7433 try {
7434 providers = ActivityThread.getPackageManager().
7435 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007436 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007437 } catch (RemoteException ex) {
7438 }
7439 if (providers != null) {
7440 final int N = providers.size();
7441 for (int i=0; i<N; i++) {
7442 ProviderInfo cpi =
7443 (ProviderInfo)providers.get(i);
7444 ContentProviderRecord cpr =
7445 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7446 if (cpr == null) {
7447 cpr = new ContentProviderRecord(cpi, app.info);
7448 mProvidersByClass.put(cpi.name, cpr);
7449 }
7450 app.pubProviders.put(cpi.name, cpr);
7451 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007452 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007453 }
7454 }
7455 return providers;
7456 }
7457
7458 private final String checkContentProviderPermissionLocked(
7459 ProviderInfo cpi, ProcessRecord r, int mode) {
7460 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7461 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7462 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7463 cpi.exported ? -1 : cpi.applicationInfo.uid)
7464 == PackageManager.PERMISSION_GRANTED
7465 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7466 return null;
7467 }
7468 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7469 cpi.exported ? -1 : cpi.applicationInfo.uid)
7470 == PackageManager.PERMISSION_GRANTED) {
7471 return null;
7472 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007473
7474 PathPermission[] pps = cpi.pathPermissions;
7475 if (pps != null) {
7476 int i = pps.length;
7477 while (i > 0) {
7478 i--;
7479 PathPermission pp = pps[i];
7480 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7481 cpi.exported ? -1 : cpi.applicationInfo.uid)
7482 == PackageManager.PERMISSION_GRANTED
7483 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7484 return null;
7485 }
7486 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7487 cpi.exported ? -1 : cpi.applicationInfo.uid)
7488 == PackageManager.PERMISSION_GRANTED) {
7489 return null;
7490 }
7491 }
7492 }
7493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007494 String msg = "Permission Denial: opening provider " + cpi.name
7495 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7496 + ", uid=" + callingUid + ") requires "
7497 + cpi.readPermission + " or " + cpi.writePermission;
7498 Log.w(TAG, msg);
7499 return msg;
7500 }
7501
7502 private final ContentProviderHolder getContentProviderImpl(
7503 IApplicationThread caller, String name) {
7504 ContentProviderRecord cpr;
7505 ProviderInfo cpi = null;
7506
7507 synchronized(this) {
7508 ProcessRecord r = null;
7509 if (caller != null) {
7510 r = getRecordForAppLocked(caller);
7511 if (r == null) {
7512 throw new SecurityException(
7513 "Unable to find app for caller " + caller
7514 + " (pid=" + Binder.getCallingPid()
7515 + ") when getting content provider " + name);
7516 }
7517 }
7518
7519 // First check if this content provider has been published...
7520 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7521 if (cpr != null) {
7522 cpi = cpr.info;
7523 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7524 return new ContentProviderHolder(cpi,
7525 cpi.readPermission != null
7526 ? cpi.readPermission : cpi.writePermission);
7527 }
7528
7529 if (r != null && cpr.canRunHere(r)) {
7530 // This provider has been published or is in the process
7531 // of being published... but it is also allowed to run
7532 // in the caller's process, so don't make a connection
7533 // and just let the caller instantiate its own instance.
7534 if (cpr.provider != null) {
7535 // don't give caller the provider object, it needs
7536 // to make its own.
7537 cpr = new ContentProviderRecord(cpr);
7538 }
7539 return cpr;
7540 }
7541
7542 final long origId = Binder.clearCallingIdentity();
7543
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007544 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007545 // return it right away.
7546 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007547 if (DEBUG_PROVIDER) Log.v(TAG,
7548 "Adding provider requested by "
7549 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007550 + cpr.info.processName);
7551 Integer cnt = r.conProviders.get(cpr);
7552 if (cnt == null) {
7553 r.conProviders.put(cpr, new Integer(1));
7554 } else {
7555 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007557 cpr.clients.add(r);
7558 } else {
7559 cpr.externals++;
7560 }
7561
7562 if (cpr.app != null) {
7563 updateOomAdjLocked(cpr.app);
7564 }
7565
7566 Binder.restoreCallingIdentity(origId);
7567
7568 } else {
7569 try {
7570 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007571 resolveContentProvider(name,
7572 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007573 } catch (RemoteException ex) {
7574 }
7575 if (cpi == null) {
7576 return null;
7577 }
7578
7579 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7580 return new ContentProviderHolder(cpi,
7581 cpi.readPermission != null
7582 ? cpi.readPermission : cpi.writePermission);
7583 }
7584
7585 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7586 final boolean firstClass = cpr == null;
7587 if (firstClass) {
7588 try {
7589 ApplicationInfo ai =
7590 ActivityThread.getPackageManager().
7591 getApplicationInfo(
7592 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007593 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007594 if (ai == null) {
7595 Log.w(TAG, "No package info for content provider "
7596 + cpi.name);
7597 return null;
7598 }
7599 cpr = new ContentProviderRecord(cpi, ai);
7600 } catch (RemoteException ex) {
7601 // pm is in same process, this will never happen.
7602 }
7603 }
7604
7605 if (r != null && cpr.canRunHere(r)) {
7606 // If this is a multiprocess provider, then just return its
7607 // info and allow the caller to instantiate it. Only do
7608 // this if the provider is the same user as the caller's
7609 // process, or can run as root (so can be in any process).
7610 return cpr;
7611 }
7612
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007613 if (DEBUG_PROVIDER) {
7614 RuntimeException e = new RuntimeException("here");
7615 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7616 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007617 }
7618
7619 // This is single process, and our app is now connecting to it.
7620 // See if we are already in the process of launching this
7621 // provider.
7622 final int N = mLaunchingProviders.size();
7623 int i;
7624 for (i=0; i<N; i++) {
7625 if (mLaunchingProviders.get(i) == cpr) {
7626 break;
7627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007628 }
7629
7630 // If the provider is not already being launched, then get it
7631 // started.
7632 if (i >= N) {
7633 final long origId = Binder.clearCallingIdentity();
7634 ProcessRecord proc = startProcessLocked(cpi.processName,
7635 cpr.appInfo, false, 0, "content provider",
7636 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007637 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007638 if (proc == null) {
7639 Log.w(TAG, "Unable to launch app "
7640 + cpi.applicationInfo.packageName + "/"
7641 + cpi.applicationInfo.uid + " for provider "
7642 + name + ": process is bad");
7643 return null;
7644 }
7645 cpr.launchingApp = proc;
7646 mLaunchingProviders.add(cpr);
7647 Binder.restoreCallingIdentity(origId);
7648 }
7649
7650 // Make sure the provider is published (the same provider class
7651 // may be published under multiple names).
7652 if (firstClass) {
7653 mProvidersByClass.put(cpi.name, cpr);
7654 }
7655 mProvidersByName.put(name, cpr);
7656
7657 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007658 if (DEBUG_PROVIDER) Log.v(TAG,
7659 "Adding provider requested by "
7660 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007661 + cpr.info.processName);
7662 Integer cnt = r.conProviders.get(cpr);
7663 if (cnt == null) {
7664 r.conProviders.put(cpr, new Integer(1));
7665 } else {
7666 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007668 cpr.clients.add(r);
7669 } else {
7670 cpr.externals++;
7671 }
7672 }
7673 }
7674
7675 // Wait for the provider to be published...
7676 synchronized (cpr) {
7677 while (cpr.provider == null) {
7678 if (cpr.launchingApp == null) {
7679 Log.w(TAG, "Unable to launch app "
7680 + cpi.applicationInfo.packageName + "/"
7681 + cpi.applicationInfo.uid + " for provider "
7682 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007683 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007684 cpi.applicationInfo.packageName,
7685 cpi.applicationInfo.uid, name);
7686 return null;
7687 }
7688 try {
7689 cpr.wait();
7690 } catch (InterruptedException ex) {
7691 }
7692 }
7693 }
7694 return cpr;
7695 }
7696
7697 public final ContentProviderHolder getContentProvider(
7698 IApplicationThread caller, String name) {
7699 if (caller == null) {
7700 String msg = "null IApplicationThread when getting content provider "
7701 + name;
7702 Log.w(TAG, msg);
7703 throw new SecurityException(msg);
7704 }
7705
7706 return getContentProviderImpl(caller, name);
7707 }
7708
7709 private ContentProviderHolder getContentProviderExternal(String name) {
7710 return getContentProviderImpl(null, name);
7711 }
7712
7713 /**
7714 * Drop a content provider from a ProcessRecord's bookkeeping
7715 * @param cpr
7716 */
7717 public void removeContentProvider(IApplicationThread caller, String name) {
7718 synchronized (this) {
7719 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7720 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007721 // remove from mProvidersByClass
7722 if (DEBUG_PROVIDER) Log.v(TAG, name +
7723 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007724 return;
7725 }
7726 final ProcessRecord r = getRecordForAppLocked(caller);
7727 if (r == null) {
7728 throw new SecurityException(
7729 "Unable to find app for caller " + caller +
7730 " when removing content provider " + name);
7731 }
7732 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007733 ContentProviderRecord localCpr = (ContentProviderRecord)
7734 mProvidersByClass.get(cpr.info.name);
7735 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7736 + r.info.processName + " from process "
7737 + localCpr.appInfo.processName);
7738 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007739 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007740 Log.w(TAG, "removeContentProvider called on local provider: "
7741 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007742 return;
7743 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007744 Integer cnt = r.conProviders.get(localCpr);
7745 if (cnt == null || cnt.intValue() <= 1) {
7746 localCpr.clients.remove(r);
7747 r.conProviders.remove(localCpr);
7748 } else {
7749 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007751 }
7752 updateOomAdjLocked();
7753 }
7754 }
7755
7756 private void removeContentProviderExternal(String name) {
7757 synchronized (this) {
7758 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7759 if(cpr == null) {
7760 //remove from mProvidersByClass
7761 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7762 return;
7763 }
7764
7765 //update content provider record entry info
7766 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7767 localCpr.externals--;
7768 if (localCpr.externals < 0) {
7769 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7770 }
7771 updateOomAdjLocked();
7772 }
7773 }
7774
7775 public final void publishContentProviders(IApplicationThread caller,
7776 List<ContentProviderHolder> providers) {
7777 if (providers == null) {
7778 return;
7779 }
7780
7781 synchronized(this) {
7782 final ProcessRecord r = getRecordForAppLocked(caller);
7783 if (r == null) {
7784 throw new SecurityException(
7785 "Unable to find app for caller " + caller
7786 + " (pid=" + Binder.getCallingPid()
7787 + ") when publishing content providers");
7788 }
7789
7790 final long origId = Binder.clearCallingIdentity();
7791
7792 final int N = providers.size();
7793 for (int i=0; i<N; i++) {
7794 ContentProviderHolder src = providers.get(i);
7795 if (src == null || src.info == null || src.provider == null) {
7796 continue;
7797 }
7798 ContentProviderRecord dst =
7799 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7800 if (dst != null) {
7801 mProvidersByClass.put(dst.info.name, dst);
7802 String names[] = dst.info.authority.split(";");
7803 for (int j = 0; j < names.length; j++) {
7804 mProvidersByName.put(names[j], dst);
7805 }
7806
7807 int NL = mLaunchingProviders.size();
7808 int j;
7809 for (j=0; j<NL; j++) {
7810 if (mLaunchingProviders.get(j) == dst) {
7811 mLaunchingProviders.remove(j);
7812 j--;
7813 NL--;
7814 }
7815 }
7816 synchronized (dst) {
7817 dst.provider = src.provider;
7818 dst.app = r;
7819 dst.notifyAll();
7820 }
7821 updateOomAdjLocked(r);
7822 }
7823 }
7824
7825 Binder.restoreCallingIdentity(origId);
7826 }
7827 }
7828
7829 public static final void installSystemProviders() {
7830 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7831 List providers = mSelf.generateApplicationProvidersLocked(app);
7832 mSystemThread.installSystemProviders(providers);
7833 }
7834
7835 // =========================================================
7836 // GLOBAL MANAGEMENT
7837 // =========================================================
7838
7839 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7840 ApplicationInfo info, String customProcess) {
7841 String proc = customProcess != null ? customProcess : info.processName;
7842 BatteryStatsImpl.Uid.Proc ps = null;
7843 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7844 synchronized (stats) {
7845 ps = stats.getProcessStatsLocked(info.uid, proc);
7846 }
7847 return new ProcessRecord(ps, thread, info, proc);
7848 }
7849
7850 final ProcessRecord addAppLocked(ApplicationInfo info) {
7851 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7852
7853 if (app == null) {
7854 app = newProcessRecordLocked(null, info, null);
7855 mProcessNames.put(info.processName, info.uid, app);
7856 updateLRUListLocked(app, true);
7857 }
7858
7859 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7860 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7861 app.persistent = true;
7862 app.maxAdj = CORE_SERVER_ADJ;
7863 }
7864 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7865 mPersistentStartingProcesses.add(app);
7866 startProcessLocked(app, "added application", app.processName);
7867 }
7868
7869 return app;
7870 }
7871
7872 public void unhandledBack() {
7873 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7874 "unhandledBack()");
7875
7876 synchronized(this) {
7877 int count = mHistory.size();
7878 if (Config.LOGD) Log.d(
7879 TAG, "Performing unhandledBack(): stack size = " + count);
7880 if (count > 1) {
7881 final long origId = Binder.clearCallingIdentity();
7882 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7883 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7884 Binder.restoreCallingIdentity(origId);
7885 }
7886 }
7887 }
7888
7889 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7890 String name = uri.getAuthority();
7891 ContentProviderHolder cph = getContentProviderExternal(name);
7892 ParcelFileDescriptor pfd = null;
7893 if (cph != null) {
7894 // We record the binder invoker's uid in thread-local storage before
7895 // going to the content provider to open the file. Later, in the code
7896 // that handles all permissions checks, we look for this uid and use
7897 // that rather than the Activity Manager's own uid. The effect is that
7898 // we do the check against the caller's permissions even though it looks
7899 // to the content provider like the Activity Manager itself is making
7900 // the request.
7901 sCallerIdentity.set(new Identity(
7902 Binder.getCallingPid(), Binder.getCallingUid()));
7903 try {
7904 pfd = cph.provider.openFile(uri, "r");
7905 } catch (FileNotFoundException e) {
7906 // do nothing; pfd will be returned null
7907 } finally {
7908 // Ensure that whatever happens, we clean up the identity state
7909 sCallerIdentity.remove();
7910 }
7911
7912 // We've got the fd now, so we're done with the provider.
7913 removeContentProviderExternal(name);
7914 } else {
7915 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7916 }
7917 return pfd;
7918 }
7919
7920 public void goingToSleep() {
7921 synchronized(this) {
7922 mSleeping = true;
7923 mWindowManager.setEventDispatching(false);
7924
7925 if (mResumedActivity != null) {
7926 pauseIfSleepingLocked();
7927 } else {
7928 Log.w(TAG, "goingToSleep with no resumed activity!");
7929 }
7930 }
7931 }
7932
Dianne Hackborn55280a92009-05-07 15:53:46 -07007933 public boolean shutdown(int timeout) {
7934 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7935 != PackageManager.PERMISSION_GRANTED) {
7936 throw new SecurityException("Requires permission "
7937 + android.Manifest.permission.SHUTDOWN);
7938 }
7939
7940 boolean timedout = false;
7941
7942 synchronized(this) {
7943 mShuttingDown = true;
7944 mWindowManager.setEventDispatching(false);
7945
7946 if (mResumedActivity != null) {
7947 pauseIfSleepingLocked();
7948 final long endTime = System.currentTimeMillis() + timeout;
7949 while (mResumedActivity != null || mPausingActivity != null) {
7950 long delay = endTime - System.currentTimeMillis();
7951 if (delay <= 0) {
7952 Log.w(TAG, "Activity manager shutdown timed out");
7953 timedout = true;
7954 break;
7955 }
7956 try {
7957 this.wait();
7958 } catch (InterruptedException e) {
7959 }
7960 }
7961 }
7962 }
7963
7964 mUsageStatsService.shutdown();
7965 mBatteryStatsService.shutdown();
7966
7967 return timedout;
7968 }
7969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007970 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007971 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007972 if (!mGoingToSleep.isHeld()) {
7973 mGoingToSleep.acquire();
7974 if (mLaunchingActivity.isHeld()) {
7975 mLaunchingActivity.release();
7976 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7977 }
7978 }
7979
7980 // If we are not currently pausing an activity, get the current
7981 // one to pause. If we are pausing one, we will just let that stuff
7982 // run and release the wake lock when all done.
7983 if (mPausingActivity == null) {
7984 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7985 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7986 startPausingLocked(false, true);
7987 }
7988 }
7989 }
7990
7991 public void wakingUp() {
7992 synchronized(this) {
7993 if (mGoingToSleep.isHeld()) {
7994 mGoingToSleep.release();
7995 }
7996 mWindowManager.setEventDispatching(true);
7997 mSleeping = false;
7998 resumeTopActivityLocked(null);
7999 }
8000 }
8001
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008002 public void stopAppSwitches() {
8003 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8004 != PackageManager.PERMISSION_GRANTED) {
8005 throw new SecurityException("Requires permission "
8006 + android.Manifest.permission.STOP_APP_SWITCHES);
8007 }
8008
8009 synchronized(this) {
8010 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8011 + APP_SWITCH_DELAY_TIME;
8012 mDidAppSwitch = false;
8013 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8014 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8015 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8016 }
8017 }
8018
8019 public void resumeAppSwitches() {
8020 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8021 != PackageManager.PERMISSION_GRANTED) {
8022 throw new SecurityException("Requires permission "
8023 + android.Manifest.permission.STOP_APP_SWITCHES);
8024 }
8025
8026 synchronized(this) {
8027 // Note that we don't execute any pending app switches... we will
8028 // let those wait until either the timeout, or the next start
8029 // activity request.
8030 mAppSwitchesAllowedTime = 0;
8031 }
8032 }
8033
8034 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8035 String name) {
8036 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8037 return true;
8038 }
8039
8040 final int perm = checkComponentPermission(
8041 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8042 callingUid, -1);
8043 if (perm == PackageManager.PERMISSION_GRANTED) {
8044 return true;
8045 }
8046
8047 Log.w(TAG, name + " request from " + callingUid + " stopped");
8048 return false;
8049 }
8050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008051 public void setDebugApp(String packageName, boolean waitForDebugger,
8052 boolean persistent) {
8053 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8054 "setDebugApp()");
8055
8056 // Note that this is not really thread safe if there are multiple
8057 // callers into it at the same time, but that's not a situation we
8058 // care about.
8059 if (persistent) {
8060 final ContentResolver resolver = mContext.getContentResolver();
8061 Settings.System.putString(
8062 resolver, Settings.System.DEBUG_APP,
8063 packageName);
8064 Settings.System.putInt(
8065 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8066 waitForDebugger ? 1 : 0);
8067 }
8068
8069 synchronized (this) {
8070 if (!persistent) {
8071 mOrigDebugApp = mDebugApp;
8072 mOrigWaitForDebugger = mWaitForDebugger;
8073 }
8074 mDebugApp = packageName;
8075 mWaitForDebugger = waitForDebugger;
8076 mDebugTransient = !persistent;
8077 if (packageName != null) {
8078 final long origId = Binder.clearCallingIdentity();
8079 uninstallPackageLocked(packageName, -1, false);
8080 Binder.restoreCallingIdentity(origId);
8081 }
8082 }
8083 }
8084
8085 public void setAlwaysFinish(boolean enabled) {
8086 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8087 "setAlwaysFinish()");
8088
8089 Settings.System.putInt(
8090 mContext.getContentResolver(),
8091 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8092
8093 synchronized (this) {
8094 mAlwaysFinishActivities = enabled;
8095 }
8096 }
8097
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008098 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008099 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008100 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008101 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008102 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008103 }
8104 }
8105
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008106 public void registerActivityWatcher(IActivityWatcher watcher) {
8107 mWatchers.register(watcher);
8108 }
8109
8110 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8111 mWatchers.unregister(watcher);
8112 }
8113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008114 public final void enterSafeMode() {
8115 synchronized(this) {
8116 // It only makes sense to do this before the system is ready
8117 // and started launching other packages.
8118 if (!mSystemReady) {
8119 try {
8120 ActivityThread.getPackageManager().enterSafeMode();
8121 } catch (RemoteException e) {
8122 }
8123
8124 View v = LayoutInflater.from(mContext).inflate(
8125 com.android.internal.R.layout.safe_mode, null);
8126 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8127 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8128 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8129 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8130 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8131 lp.format = v.getBackground().getOpacity();
8132 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8133 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8134 ((WindowManager)mContext.getSystemService(
8135 Context.WINDOW_SERVICE)).addView(v, lp);
8136 }
8137 }
8138 }
8139
8140 public void noteWakeupAlarm(IIntentSender sender) {
8141 if (!(sender instanceof PendingIntentRecord)) {
8142 return;
8143 }
8144 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8145 synchronized (stats) {
8146 if (mBatteryStatsService.isOnBattery()) {
8147 mBatteryStatsService.enforceCallingPermission();
8148 PendingIntentRecord rec = (PendingIntentRecord)sender;
8149 int MY_UID = Binder.getCallingUid();
8150 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8151 BatteryStatsImpl.Uid.Pkg pkg =
8152 stats.getPackageStatsLocked(uid, rec.key.packageName);
8153 pkg.incWakeupsLocked();
8154 }
8155 }
8156 }
8157
8158 public boolean killPidsForMemory(int[] pids) {
8159 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8160 throw new SecurityException("killPidsForMemory only available to the system");
8161 }
8162
8163 // XXX Note: don't acquire main activity lock here, because the window
8164 // manager calls in with its locks held.
8165
8166 boolean killed = false;
8167 synchronized (mPidsSelfLocked) {
8168 int[] types = new int[pids.length];
8169 int worstType = 0;
8170 for (int i=0; i<pids.length; i++) {
8171 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8172 if (proc != null) {
8173 int type = proc.setAdj;
8174 types[i] = type;
8175 if (type > worstType) {
8176 worstType = type;
8177 }
8178 }
8179 }
8180
8181 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8182 // then constrain it so we will kill all hidden procs.
8183 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8184 worstType = HIDDEN_APP_MIN_ADJ;
8185 }
8186 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8187 for (int i=0; i<pids.length; i++) {
8188 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8189 if (proc == null) {
8190 continue;
8191 }
8192 int adj = proc.setAdj;
8193 if (adj >= worstType) {
8194 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8195 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008196 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008197 proc.processName, adj);
8198 killed = true;
8199 Process.killProcess(pids[i]);
8200 }
8201 }
8202 }
8203 return killed;
8204 }
8205
8206 public void reportPss(IApplicationThread caller, int pss) {
8207 Watchdog.PssRequestor req;
8208 String name;
8209 ProcessRecord callerApp;
8210 synchronized (this) {
8211 if (caller == null) {
8212 return;
8213 }
8214 callerApp = getRecordForAppLocked(caller);
8215 if (callerApp == null) {
8216 return;
8217 }
8218 callerApp.lastPss = pss;
8219 req = callerApp;
8220 name = callerApp.processName;
8221 }
8222 Watchdog.getInstance().reportPss(req, name, pss);
8223 if (!callerApp.persistent) {
8224 removeRequestedPss(callerApp);
8225 }
8226 }
8227
8228 public void requestPss(Runnable completeCallback) {
8229 ArrayList<ProcessRecord> procs;
8230 synchronized (this) {
8231 mRequestPssCallback = completeCallback;
8232 mRequestPssList.clear();
8233 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8234 ProcessRecord proc = mLRUProcesses.get(i);
8235 if (!proc.persistent) {
8236 mRequestPssList.add(proc);
8237 }
8238 }
8239 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8240 }
8241
8242 int oldPri = Process.getThreadPriority(Process.myTid());
8243 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8244 for (int i=procs.size()-1; i>=0; i--) {
8245 ProcessRecord proc = procs.get(i);
8246 proc.lastPss = 0;
8247 proc.requestPss();
8248 }
8249 Process.setThreadPriority(oldPri);
8250 }
8251
8252 void removeRequestedPss(ProcessRecord proc) {
8253 Runnable callback = null;
8254 synchronized (this) {
8255 if (mRequestPssList.remove(proc)) {
8256 if (mRequestPssList.size() == 0) {
8257 callback = mRequestPssCallback;
8258 mRequestPssCallback = null;
8259 }
8260 }
8261 }
8262
8263 if (callback != null) {
8264 callback.run();
8265 }
8266 }
8267
8268 public void collectPss(Watchdog.PssStats stats) {
8269 stats.mEmptyPss = 0;
8270 stats.mEmptyCount = 0;
8271 stats.mBackgroundPss = 0;
8272 stats.mBackgroundCount = 0;
8273 stats.mServicePss = 0;
8274 stats.mServiceCount = 0;
8275 stats.mVisiblePss = 0;
8276 stats.mVisibleCount = 0;
8277 stats.mForegroundPss = 0;
8278 stats.mForegroundCount = 0;
8279 stats.mNoPssCount = 0;
8280 synchronized (this) {
8281 int i;
8282 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8283 ? mProcDeaths.length : stats.mProcDeaths.length;
8284 int aggr = 0;
8285 for (i=0; i<NPD; i++) {
8286 aggr += mProcDeaths[i];
8287 stats.mProcDeaths[i] = aggr;
8288 }
8289 while (i<stats.mProcDeaths.length) {
8290 stats.mProcDeaths[i] = 0;
8291 i++;
8292 }
8293
8294 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8295 ProcessRecord proc = mLRUProcesses.get(i);
8296 if (proc.persistent) {
8297 continue;
8298 }
8299 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8300 if (proc.lastPss == 0) {
8301 stats.mNoPssCount++;
8302 continue;
8303 }
8304 if (proc.setAdj == EMPTY_APP_ADJ) {
8305 stats.mEmptyPss += proc.lastPss;
8306 stats.mEmptyCount++;
8307 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8308 stats.mEmptyPss += proc.lastPss;
8309 stats.mEmptyCount++;
8310 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8311 stats.mBackgroundPss += proc.lastPss;
8312 stats.mBackgroundCount++;
8313 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8314 stats.mVisiblePss += proc.lastPss;
8315 stats.mVisibleCount++;
8316 } else {
8317 stats.mForegroundPss += proc.lastPss;
8318 stats.mForegroundCount++;
8319 }
8320 }
8321 }
8322 }
8323
8324 public final void startRunning(String pkg, String cls, String action,
8325 String data) {
8326 synchronized(this) {
8327 if (mStartRunning) {
8328 return;
8329 }
8330 mStartRunning = true;
8331 mTopComponent = pkg != null && cls != null
8332 ? new ComponentName(pkg, cls) : null;
8333 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8334 mTopData = data;
8335 if (!mSystemReady) {
8336 return;
8337 }
8338 }
8339
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008340 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008341 }
8342
8343 private void retrieveSettings() {
8344 final ContentResolver resolver = mContext.getContentResolver();
8345 String debugApp = Settings.System.getString(
8346 resolver, Settings.System.DEBUG_APP);
8347 boolean waitForDebugger = Settings.System.getInt(
8348 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8349 boolean alwaysFinishActivities = Settings.System.getInt(
8350 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8351
8352 Configuration configuration = new Configuration();
8353 Settings.System.getConfiguration(resolver, configuration);
8354
8355 synchronized (this) {
8356 mDebugApp = mOrigDebugApp = debugApp;
8357 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8358 mAlwaysFinishActivities = alwaysFinishActivities;
8359 // This happens before any activities are started, so we can
8360 // change mConfiguration in-place.
8361 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008362 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008363 }
8364 }
8365
8366 public boolean testIsSystemReady() {
8367 // no need to synchronize(this) just to read & return the value
8368 return mSystemReady;
8369 }
8370
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008371 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008372 // In the simulator, startRunning will never have been called, which
8373 // normally sets a few crucial variables. Do it here instead.
8374 if (!Process.supportsProcesses()) {
8375 mStartRunning = true;
8376 mTopAction = Intent.ACTION_MAIN;
8377 }
8378
8379 synchronized(this) {
8380 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008381 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008382 return;
8383 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008384
8385 // Check to see if there are any update receivers to run.
8386 if (!mDidUpdate) {
8387 if (mWaitingUpdate) {
8388 return;
8389 }
8390 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8391 List<ResolveInfo> ris = null;
8392 try {
8393 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8394 intent, null, 0);
8395 } catch (RemoteException e) {
8396 }
8397 if (ris != null) {
8398 for (int i=ris.size()-1; i>=0; i--) {
8399 if ((ris.get(i).activityInfo.applicationInfo.flags
8400 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8401 ris.remove(i);
8402 }
8403 }
8404 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8405 for (int i=0; i<ris.size(); i++) {
8406 ActivityInfo ai = ris.get(i).activityInfo;
8407 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8408 IIntentReceiver finisher = null;
8409 if (i == 0) {
8410 finisher = new IIntentReceiver.Stub() {
8411 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008412 String data, Bundle extras, boolean ordered,
8413 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008414 throws RemoteException {
8415 synchronized (ActivityManagerService.this) {
8416 mDidUpdate = true;
8417 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008418 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008419 }
8420 };
8421 }
8422 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8423 broadcastIntentLocked(null, null, intent, null, finisher,
8424 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8425 if (i == 0) {
8426 mWaitingUpdate = true;
8427 }
8428 }
8429 }
8430 if (mWaitingUpdate) {
8431 return;
8432 }
8433 mDidUpdate = true;
8434 }
8435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008436 mSystemReady = true;
8437 if (!mStartRunning) {
8438 return;
8439 }
8440 }
8441
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008442 ArrayList<ProcessRecord> procsToKill = null;
8443 synchronized(mPidsSelfLocked) {
8444 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8445 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8446 if (!isAllowedWhileBooting(proc.info)){
8447 if (procsToKill == null) {
8448 procsToKill = new ArrayList<ProcessRecord>();
8449 }
8450 procsToKill.add(proc);
8451 }
8452 }
8453 }
8454
8455 if (procsToKill != null) {
8456 synchronized(this) {
8457 for (int i=procsToKill.size()-1; i>=0; i--) {
8458 ProcessRecord proc = procsToKill.get(i);
8459 Log.i(TAG, "Removing system update proc: " + proc);
8460 removeProcessLocked(proc, true);
8461 }
8462 }
8463 }
8464
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008465 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008466 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008467 SystemClock.uptimeMillis());
8468
8469 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008470 // Make sure we have no pre-ready processes sitting around.
8471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008472 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8473 ResolveInfo ri = mContext.getPackageManager()
8474 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008475 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008476 CharSequence errorMsg = null;
8477 if (ri != null) {
8478 ActivityInfo ai = ri.activityInfo;
8479 ApplicationInfo app = ai.applicationInfo;
8480 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8481 mTopAction = Intent.ACTION_FACTORY_TEST;
8482 mTopData = null;
8483 mTopComponent = new ComponentName(app.packageName,
8484 ai.name);
8485 } else {
8486 errorMsg = mContext.getResources().getText(
8487 com.android.internal.R.string.factorytest_not_system);
8488 }
8489 } else {
8490 errorMsg = mContext.getResources().getText(
8491 com.android.internal.R.string.factorytest_no_action);
8492 }
8493 if (errorMsg != null) {
8494 mTopAction = null;
8495 mTopData = null;
8496 mTopComponent = null;
8497 Message msg = Message.obtain();
8498 msg.what = SHOW_FACTORY_ERROR_MSG;
8499 msg.getData().putCharSequence("msg", errorMsg);
8500 mHandler.sendMessage(msg);
8501 }
8502 }
8503 }
8504
8505 retrieveSettings();
8506
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008507 if (goingCallback != null) goingCallback.run();
8508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 synchronized (this) {
8510 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8511 try {
8512 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008513 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008514 if (apps != null) {
8515 int N = apps.size();
8516 int i;
8517 for (i=0; i<N; i++) {
8518 ApplicationInfo info
8519 = (ApplicationInfo)apps.get(i);
8520 if (info != null &&
8521 !info.packageName.equals("android")) {
8522 addAppLocked(info);
8523 }
8524 }
8525 }
8526 } catch (RemoteException ex) {
8527 // pm is in same process, this will never happen.
8528 }
8529 }
8530
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008531 // Start up initial activity.
8532 mBooting = true;
8533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008534 try {
8535 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8536 Message msg = Message.obtain();
8537 msg.what = SHOW_UID_ERROR_MSG;
8538 mHandler.sendMessage(msg);
8539 }
8540 } catch (RemoteException e) {
8541 }
8542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008543 resumeTopActivityLocked(null);
8544 }
8545 }
8546
8547 boolean makeAppCrashingLocked(ProcessRecord app,
8548 String tag, String shortMsg, String longMsg, byte[] crashData) {
8549 app.crashing = true;
8550 app.crashingReport = generateProcessError(app,
8551 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8552 startAppProblemLocked(app);
8553 app.stopFreezingAllLocked();
8554 return handleAppCrashLocked(app);
8555 }
8556
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008557 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008558 // check if error reporting is enabled in Gservices
8559 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8560 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8561 if (enabled == 0) {
8562 return null;
8563 }
8564
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008565 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008566
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008567 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008568 // look for receiver in the installer package
8569 String candidate = pm.getInstallerPackageName(app.info.packageName);
8570 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8571 if (result != null) {
8572 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008573 }
8574
Jacek Surazski82a73df2009-06-17 14:33:18 +02008575 // if the error app is on the system image, look for system apps
8576 // error receiver
8577 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8578 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8579 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8580 if (result != null) {
8581 return result;
8582 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008583 }
8584
Jacek Surazski82a73df2009-06-17 14:33:18 +02008585 // if there is a default receiver, try that
8586 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8587 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008588 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008589 // should not happen
8590 Log.e(TAG, "error talking to PackageManager", e);
8591 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008592 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008593 }
8594
8595 /**
8596 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8597 *
8598 * @param pm PackageManager isntance
8599 * @param errorPackage package which caused the error
8600 * @param receiverPackage candidate package to receive the error
8601 * @return activity component within receiverPackage which handles
8602 * ACTION_APP_ERROR, or null if not found
8603 */
8604 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8605 String receiverPackage) throws RemoteException {
8606 if (receiverPackage == null || receiverPackage.length() == 0) {
8607 return null;
8608 }
8609
8610 // break the loop if it's the error report receiver package that crashed
8611 if (receiverPackage.equals(errorPackage)) {
8612 return null;
8613 }
8614
8615 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8616 intent.setPackage(receiverPackage);
8617 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8618 if (info == null || info.activityInfo == null) {
8619 return null;
8620 }
8621 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008622 }
8623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008624 void makeAppNotRespondingLocked(ProcessRecord app,
8625 String tag, String shortMsg, String longMsg, byte[] crashData) {
8626 app.notResponding = true;
8627 app.notRespondingReport = generateProcessError(app,
8628 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8629 crashData);
8630 startAppProblemLocked(app);
8631 app.stopFreezingAllLocked();
8632 }
8633
8634 /**
8635 * Generate a process error record, suitable for attachment to a ProcessRecord.
8636 *
8637 * @param app The ProcessRecord in which the error occurred.
8638 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8639 * ActivityManager.AppErrorStateInfo
8640 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8641 * @param shortMsg Short message describing the crash.
8642 * @param longMsg Long message describing the crash.
8643 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8644 *
8645 * @return Returns a fully-formed AppErrorStateInfo record.
8646 */
8647 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8648 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8649 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8650
8651 report.condition = condition;
8652 report.processName = app.processName;
8653 report.pid = app.pid;
8654 report.uid = app.info.uid;
8655 report.tag = tag;
8656 report.shortMsg = shortMsg;
8657 report.longMsg = longMsg;
8658 report.crashData = crashData;
8659
8660 return report;
8661 }
8662
8663 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8664 boolean crashed) {
8665 synchronized (this) {
8666 app.crashing = false;
8667 app.crashingReport = null;
8668 app.notResponding = false;
8669 app.notRespondingReport = null;
8670 if (app.anrDialog == fromDialog) {
8671 app.anrDialog = null;
8672 }
8673 if (app.waitDialog == fromDialog) {
8674 app.waitDialog = null;
8675 }
8676 if (app.pid > 0 && app.pid != MY_PID) {
8677 if (crashed) {
8678 handleAppCrashLocked(app);
8679 }
8680 Log.i(ActivityManagerService.TAG, "Killing process "
8681 + app.processName
8682 + " (pid=" + app.pid + ") at user's request");
8683 Process.killProcess(app.pid);
8684 }
8685
8686 }
8687 }
8688
8689 boolean handleAppCrashLocked(ProcessRecord app) {
8690 long now = SystemClock.uptimeMillis();
8691
8692 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8693 app.info.uid);
8694 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8695 // This process loses!
8696 Log.w(TAG, "Process " + app.info.processName
8697 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008698 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008699 app.info.processName, app.info.uid);
8700 killServicesLocked(app, false);
8701 for (int i=mHistory.size()-1; i>=0; i--) {
8702 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8703 if (r.app == app) {
8704 if (Config.LOGD) Log.d(
8705 TAG, " Force finishing activity "
8706 + r.intent.getComponent().flattenToShortString());
8707 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8708 }
8709 }
8710 if (!app.persistent) {
8711 // We don't want to start this process again until the user
8712 // explicitly does so... but for persistent process, we really
8713 // need to keep it running. If a persistent process is actually
8714 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008715 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008716 app.info.processName);
8717 mBadProcesses.put(app.info.processName, app.info.uid, now);
8718 app.bad = true;
8719 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8720 app.removed = true;
8721 removeProcessLocked(app, false);
8722 return false;
8723 }
8724 }
8725
8726 // Bump up the crash count of any services currently running in the proc.
8727 if (app.services.size() != 0) {
8728 // Any services running in the application need to be placed
8729 // back in the pending list.
8730 Iterator it = app.services.iterator();
8731 while (it.hasNext()) {
8732 ServiceRecord sr = (ServiceRecord)it.next();
8733 sr.crashCount++;
8734 }
8735 }
8736
8737 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8738 return true;
8739 }
8740
8741 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008742 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008743 skipCurrentReceiverLocked(app);
8744 }
8745
8746 void skipCurrentReceiverLocked(ProcessRecord app) {
8747 boolean reschedule = false;
8748 BroadcastRecord r = app.curReceiver;
8749 if (r != null) {
8750 // The current broadcast is waiting for this app's receiver
8751 // to be finished. Looks like that's not going to happen, so
8752 // let the broadcast continue.
8753 logBroadcastReceiverDiscard(r);
8754 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8755 r.resultExtras, r.resultAbort, true);
8756 reschedule = true;
8757 }
8758 r = mPendingBroadcast;
8759 if (r != null && r.curApp == app) {
8760 if (DEBUG_BROADCAST) Log.v(TAG,
8761 "skip & discard pending app " + r);
8762 logBroadcastReceiverDiscard(r);
8763 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8764 r.resultExtras, r.resultAbort, true);
8765 reschedule = true;
8766 }
8767 if (reschedule) {
8768 scheduleBroadcastsLocked();
8769 }
8770 }
8771
8772 public int handleApplicationError(IBinder app, int flags,
8773 String tag, String shortMsg, String longMsg, byte[] crashData) {
8774 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008775 ProcessRecord r = null;
8776 synchronized (this) {
8777 if (app != null) {
8778 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8779 final int NA = apps.size();
8780 for (int ia=0; ia<NA; ia++) {
8781 ProcessRecord p = apps.valueAt(ia);
8782 if (p.thread != null && p.thread.asBinder() == app) {
8783 r = p;
8784 break;
8785 }
8786 }
8787 }
8788 }
8789
8790 if (r != null) {
8791 // The application has crashed. Send the SIGQUIT to the process so
8792 // that it can dump its state.
8793 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8794 //Log.i(TAG, "Current system threads:");
8795 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8796 }
8797
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008798 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008799 try {
8800 String name = r != null ? r.processName : null;
8801 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008802 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008803 shortMsg, longMsg, crashData)) {
8804 Log.w(TAG, "Force-killing crashed app " + name
8805 + " at watcher's request");
8806 Process.killProcess(pid);
8807 return 0;
8808 }
8809 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008810 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008811 }
8812 }
8813
8814 final long origId = Binder.clearCallingIdentity();
8815
8816 // If this process is running instrumentation, finish it.
8817 if (r != null && r.instrumentationClass != null) {
8818 Log.w(TAG, "Error in app " + r.processName
8819 + " running instrumentation " + r.instrumentationClass + ":");
8820 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8821 if (longMsg != null) Log.w(TAG, " " + longMsg);
8822 Bundle info = new Bundle();
8823 info.putString("shortMsg", shortMsg);
8824 info.putString("longMsg", longMsg);
8825 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8826 Binder.restoreCallingIdentity(origId);
8827 return 0;
8828 }
8829
8830 if (r != null) {
8831 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8832 return 0;
8833 }
8834 } else {
8835 Log.w(TAG, "Some application object " + app + " tag " + tag
8836 + " has crashed, but I don't know who it is.");
8837 Log.w(TAG, "ShortMsg:" + shortMsg);
8838 Log.w(TAG, "LongMsg:" + longMsg);
8839 Binder.restoreCallingIdentity(origId);
8840 return 0;
8841 }
8842
8843 Message msg = Message.obtain();
8844 msg.what = SHOW_ERROR_MSG;
8845 HashMap data = new HashMap();
8846 data.put("result", result);
8847 data.put("app", r);
8848 data.put("flags", flags);
8849 data.put("shortMsg", shortMsg);
8850 data.put("longMsg", longMsg);
8851 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8852 // For system processes, submit crash data to the server.
8853 data.put("crashData", crashData);
8854 }
8855 msg.obj = data;
8856 mHandler.sendMessage(msg);
8857
8858 Binder.restoreCallingIdentity(origId);
8859 }
8860
8861 int res = result.get();
8862
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008863 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008864 synchronized (this) {
8865 if (r != null) {
8866 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8867 SystemClock.uptimeMillis());
8868 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008869 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8870 appErrorIntent = createAppErrorIntentLocked(r);
8871 res = AppErrorDialog.FORCE_QUIT;
8872 }
8873 }
8874
8875 if (appErrorIntent != null) {
8876 try {
8877 mContext.startActivity(appErrorIntent);
8878 } catch (ActivityNotFoundException e) {
8879 Log.w(TAG, "bug report receiver dissappeared", e);
8880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008881 }
8882
8883 return res;
8884 }
8885
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008886 Intent createAppErrorIntentLocked(ProcessRecord r) {
8887 ApplicationErrorReport report = createAppErrorReportLocked(r);
8888 if (report == null) {
8889 return null;
8890 }
8891 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8892 result.setComponent(r.errorReportReceiver);
8893 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8894 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8895 return result;
8896 }
8897
8898 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8899 if (r.errorReportReceiver == null) {
8900 return null;
8901 }
8902
8903 if (!r.crashing && !r.notResponding) {
8904 return null;
8905 }
8906
8907 try {
8908 ApplicationErrorReport report = new ApplicationErrorReport();
8909 report.packageName = r.info.packageName;
8910 report.installerPackageName = r.errorReportReceiver.getPackageName();
8911 report.processName = r.processName;
8912
8913 if (r.crashing) {
8914 report.type = ApplicationErrorReport.TYPE_CRASH;
8915 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8916
8917 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8918 r.crashingReport.crashData);
8919 DataInputStream dataStream = new DataInputStream(byteStream);
8920 CrashData crashData = new CrashData(dataStream);
8921 ThrowableData throwData = crashData.getThrowableData();
8922
8923 report.time = crashData.getTime();
8924 report.crashInfo.stackTrace = throwData.toString();
8925
Jacek Surazskif829a782009-06-11 22:47:02 +02008926 // Extract the source of the exception, useful for report
8927 // clustering. Also extract the "deepest" non-null exception
8928 // message.
8929 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008930 while (throwData.getCause() != null) {
8931 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008932 String msg = throwData.getMessage();
8933 if (msg != null && msg.length() > 0) {
8934 exceptionMessage = msg;
8935 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008936 }
8937 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008938 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008939 report.crashInfo.exceptionClassName = throwData.getType();
8940 report.crashInfo.throwFileName = trace.getFileName();
8941 report.crashInfo.throwClassName = trace.getClassName();
8942 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008943 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008944 } else if (r.notResponding) {
8945 report.type = ApplicationErrorReport.TYPE_ANR;
8946 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8947
8948 report.anrInfo.activity = r.notRespondingReport.tag;
8949 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8950 report.anrInfo.info = r.notRespondingReport.longMsg;
8951 }
8952
8953 return report;
8954 } catch (IOException e) {
8955 // we don't send it
8956 }
8957
8958 return null;
8959 }
8960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008961 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8962 // assume our apps are happy - lazy create the list
8963 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8964
8965 synchronized (this) {
8966
8967 // iterate across all processes
8968 final int N = mLRUProcesses.size();
8969 for (int i = 0; i < N; i++) {
8970 ProcessRecord app = mLRUProcesses.get(i);
8971 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8972 // This one's in trouble, so we'll generate a report for it
8973 // crashes are higher priority (in case there's a crash *and* an anr)
8974 ActivityManager.ProcessErrorStateInfo report = null;
8975 if (app.crashing) {
8976 report = app.crashingReport;
8977 } else if (app.notResponding) {
8978 report = app.notRespondingReport;
8979 }
8980
8981 if (report != null) {
8982 if (errList == null) {
8983 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8984 }
8985 errList.add(report);
8986 } else {
8987 Log.w(TAG, "Missing app error report, app = " + app.processName +
8988 " crashing = " + app.crashing +
8989 " notResponding = " + app.notResponding);
8990 }
8991 }
8992 }
8993 }
8994
8995 return errList;
8996 }
8997
8998 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8999 // Lazy instantiation of list
9000 List<ActivityManager.RunningAppProcessInfo> runList = null;
9001 synchronized (this) {
9002 // Iterate across all processes
9003 final int N = mLRUProcesses.size();
9004 for (int i = 0; i < N; i++) {
9005 ProcessRecord app = mLRUProcesses.get(i);
9006 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9007 // Generate process state info for running application
9008 ActivityManager.RunningAppProcessInfo currApp =
9009 new ActivityManager.RunningAppProcessInfo(app.processName,
9010 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009011 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009012 int adj = app.curAdj;
9013 if (adj >= CONTENT_PROVIDER_ADJ) {
9014 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9015 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9016 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009017 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9018 } else if (adj >= HOME_APP_ADJ) {
9019 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9020 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009021 } else if (adj >= SECONDARY_SERVER_ADJ) {
9022 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9023 } else if (adj >= VISIBLE_APP_ADJ) {
9024 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9025 } else {
9026 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9027 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009028 currApp.importanceReasonCode = app.adjTypeCode;
9029 if (app.adjSource instanceof ProcessRecord) {
9030 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9031 } else if (app.adjSource instanceof HistoryRecord) {
9032 HistoryRecord r = (HistoryRecord)app.adjSource;
9033 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9034 }
9035 if (app.adjTarget instanceof ComponentName) {
9036 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009038 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9039 // + " lru=" + currApp.lru);
9040 if (runList == null) {
9041 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9042 }
9043 runList.add(currApp);
9044 }
9045 }
9046 }
9047 return runList;
9048 }
9049
9050 @Override
9051 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9052 synchronized (this) {
9053 if (checkCallingPermission(android.Manifest.permission.DUMP)
9054 != PackageManager.PERMISSION_GRANTED) {
9055 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9056 + Binder.getCallingPid()
9057 + ", uid=" + Binder.getCallingUid()
9058 + " without permission "
9059 + android.Manifest.permission.DUMP);
9060 return;
9061 }
9062 if (args.length != 0 && "service".equals(args[0])) {
9063 dumpService(fd, pw, args);
9064 return;
9065 }
9066 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009067 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 pw.println(" ");
9069 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009070 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 if (mWaitingVisibleActivities.size() > 0) {
9072 pw.println(" ");
9073 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009074 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009075 }
9076 if (mStoppingActivities.size() > 0) {
9077 pw.println(" ");
9078 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009079 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009080 }
9081 if (mFinishingActivities.size() > 0) {
9082 pw.println(" ");
9083 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009084 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009085 }
9086
9087 pw.println(" ");
9088 pw.println(" mPausingActivity: " + mPausingActivity);
9089 pw.println(" mResumedActivity: " + mResumedActivity);
9090 pw.println(" mFocusedActivity: " + mFocusedActivity);
9091 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9092
9093 if (mRecentTasks.size() > 0) {
9094 pw.println(" ");
9095 pw.println("Recent tasks in Current Activity Manager State:");
9096
9097 final int N = mRecentTasks.size();
9098 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009099 TaskRecord tr = mRecentTasks.get(i);
9100 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9101 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009102 mRecentTasks.get(i).dump(pw, " ");
9103 }
9104 }
9105
9106 pw.println(" ");
9107 pw.println(" mCurTask: " + mCurTask);
9108
9109 pw.println(" ");
9110 pw.println("Processes in Current Activity Manager State:");
9111
9112 boolean needSep = false;
9113 int numPers = 0;
9114
9115 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9116 final int NA = procs.size();
9117 for (int ia=0; ia<NA; ia++) {
9118 if (!needSep) {
9119 pw.println(" All known processes:");
9120 needSep = true;
9121 }
9122 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009123 pw.print(r.persistent ? " *PERS*" : " *APP*");
9124 pw.print(" UID "); pw.print(procs.keyAt(ia));
9125 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009126 r.dump(pw, " ");
9127 if (r.persistent) {
9128 numPers++;
9129 }
9130 }
9131 }
9132
9133 if (mLRUProcesses.size() > 0) {
9134 if (needSep) pw.println(" ");
9135 needSep = true;
9136 pw.println(" Running processes (most recent first):");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009137 dumpProcessList(pw, this, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009138 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009139 needSep = true;
9140 }
9141
9142 synchronized (mPidsSelfLocked) {
9143 if (mPidsSelfLocked.size() > 0) {
9144 if (needSep) pw.println(" ");
9145 needSep = true;
9146 pw.println(" PID mappings:");
9147 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009148 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9149 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009150 }
9151 }
9152 }
9153
9154 if (mForegroundProcesses.size() > 0) {
9155 if (needSep) pw.println(" ");
9156 needSep = true;
9157 pw.println(" Foreground Processes:");
9158 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009159 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9160 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009161 }
9162 }
9163
9164 if (mPersistentStartingProcesses.size() > 0) {
9165 if (needSep) pw.println(" ");
9166 needSep = true;
9167 pw.println(" Persisent processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009168 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009169 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009170 }
9171
9172 if (mStartingProcesses.size() > 0) {
9173 if (needSep) pw.println(" ");
9174 needSep = true;
9175 pw.println(" Processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009176 dumpProcessList(pw, this, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009177 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009178 }
9179
9180 if (mRemovedProcesses.size() > 0) {
9181 if (needSep) pw.println(" ");
9182 needSep = true;
9183 pw.println(" Processes that are being removed:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009184 dumpProcessList(pw, this, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009185 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009186 }
9187
9188 if (mProcessesOnHold.size() > 0) {
9189 if (needSep) pw.println(" ");
9190 needSep = true;
9191 pw.println(" Processes that are on old until the system is ready:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009192 dumpProcessList(pw, this, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009193 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009194 }
9195
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009196 if (mProcessesToGc.size() > 0) {
9197 if (needSep) pw.println(" ");
9198 needSep = true;
9199 pw.println(" Processes that are waiting to GC:");
9200 long now = SystemClock.uptimeMillis();
9201 for (int i=0; i<mProcessesToGc.size(); i++) {
9202 ProcessRecord proc = mProcessesToGc.get(i);
9203 pw.print(" Process "); pw.println(proc);
9204 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9205 pw.print(", last gced=");
9206 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009207 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009208 pw.print(now-proc.lastLowMemory);
9209 pw.println(" ms ago");
9210
9211 }
9212 }
9213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009214 if (mProcessCrashTimes.getMap().size() > 0) {
9215 if (needSep) pw.println(" ");
9216 needSep = true;
9217 pw.println(" Time since processes crashed:");
9218 long now = SystemClock.uptimeMillis();
9219 for (Map.Entry<String, SparseArray<Long>> procs
9220 : mProcessCrashTimes.getMap().entrySet()) {
9221 SparseArray<Long> uids = procs.getValue();
9222 final int N = uids.size();
9223 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009224 pw.print(" Process "); pw.print(procs.getKey());
9225 pw.print(" uid "); pw.print(uids.keyAt(i));
9226 pw.print(": last crashed ");
9227 pw.print((now-uids.valueAt(i)));
9228 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009229 }
9230 }
9231 }
9232
9233 if (mBadProcesses.getMap().size() > 0) {
9234 if (needSep) pw.println(" ");
9235 needSep = true;
9236 pw.println(" Bad processes:");
9237 for (Map.Entry<String, SparseArray<Long>> procs
9238 : mBadProcesses.getMap().entrySet()) {
9239 SparseArray<Long> uids = procs.getValue();
9240 final int N = uids.size();
9241 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009242 pw.print(" Bad process "); pw.print(procs.getKey());
9243 pw.print(" uid "); pw.print(uids.keyAt(i));
9244 pw.print(": crashed at time ");
9245 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009246 }
9247 }
9248 }
9249
9250 pw.println(" ");
9251 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009252 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009253 pw.println(" mConfiguration: " + mConfiguration);
9254 pw.println(" mStartRunning=" + mStartRunning
9255 + " mSystemReady=" + mSystemReady
9256 + " mBooting=" + mBooting
9257 + " mBooted=" + mBooted
9258 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009259 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009260 pw.println(" mGoingToSleep=" + mGoingToSleep);
9261 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9262 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9263 + " mDebugTransient=" + mDebugTransient
9264 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9265 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009266 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009267 }
9268 }
9269
9270 /**
9271 * There are three ways to call this:
9272 * - no service specified: dump all the services
9273 * - a flattened component name that matched an existing service was specified as the
9274 * first arg: dump that one service
9275 * - the first arg isn't the flattened component name of an existing service:
9276 * dump all services whose component contains the first arg as a substring
9277 */
9278 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9279 String[] newArgs;
9280 String componentNameString;
9281 ServiceRecord r;
9282 if (args.length == 1) {
9283 componentNameString = null;
9284 newArgs = EMPTY_STRING_ARRAY;
9285 r = null;
9286 } else {
9287 componentNameString = args[1];
9288 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9289 r = componentName != null ? mServices.get(componentName) : null;
9290 newArgs = new String[args.length - 2];
9291 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9292 }
9293
9294 if (r != null) {
9295 dumpService(fd, pw, r, newArgs);
9296 } else {
9297 for (ServiceRecord r1 : mServices.values()) {
9298 if (componentNameString == null
9299 || r1.name.flattenToString().contains(componentNameString)) {
9300 dumpService(fd, pw, r1, newArgs);
9301 }
9302 }
9303 }
9304 }
9305
9306 /**
9307 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9308 * there is a thread associated with the service.
9309 */
9310 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9311 pw.println(" Service " + r.name.flattenToString());
9312 if (r.app != null && r.app.thread != null) {
9313 try {
9314 // flush anything that is already in the PrintWriter since the thread is going
9315 // to write to the file descriptor directly
9316 pw.flush();
9317 r.app.thread.dumpService(fd, r, args);
9318 pw.print("\n");
9319 } catch (RemoteException e) {
9320 pw.println("got a RemoteException while dumping the service");
9321 }
9322 }
9323 }
9324
9325 void dumpBroadcasts(PrintWriter pw) {
9326 synchronized (this) {
9327 if (checkCallingPermission(android.Manifest.permission.DUMP)
9328 != PackageManager.PERMISSION_GRANTED) {
9329 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9330 + Binder.getCallingPid()
9331 + ", uid=" + Binder.getCallingUid()
9332 + " without permission "
9333 + android.Manifest.permission.DUMP);
9334 return;
9335 }
9336 pw.println("Broadcasts in Current Activity Manager State:");
9337
9338 if (mRegisteredReceivers.size() > 0) {
9339 pw.println(" ");
9340 pw.println(" Registered Receivers:");
9341 Iterator it = mRegisteredReceivers.values().iterator();
9342 while (it.hasNext()) {
9343 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009344 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009345 r.dump(pw, " ");
9346 }
9347 }
9348
9349 pw.println(" ");
9350 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009351 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009352
9353 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9354 || mPendingBroadcast != null) {
9355 if (mParallelBroadcasts.size() > 0) {
9356 pw.println(" ");
9357 pw.println(" Active broadcasts:");
9358 }
9359 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9360 pw.println(" Broadcast #" + i + ":");
9361 mParallelBroadcasts.get(i).dump(pw, " ");
9362 }
9363 if (mOrderedBroadcasts.size() > 0) {
9364 pw.println(" ");
9365 pw.println(" Active serialized broadcasts:");
9366 }
9367 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9368 pw.println(" Serialized Broadcast #" + i + ":");
9369 mOrderedBroadcasts.get(i).dump(pw, " ");
9370 }
9371 pw.println(" ");
9372 pw.println(" Pending broadcast:");
9373 if (mPendingBroadcast != null) {
9374 mPendingBroadcast.dump(pw, " ");
9375 } else {
9376 pw.println(" (null)");
9377 }
9378 }
9379
9380 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009381 pw.println(" Historical broadcasts:");
9382 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9383 BroadcastRecord r = mBroadcastHistory[i];
9384 if (r == null) {
9385 break;
9386 }
9387 pw.println(" Historical Broadcast #" + i + ":");
9388 r.dump(pw, " ");
9389 }
9390
9391 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009392 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9393 if (mStickyBroadcasts != null) {
9394 pw.println(" ");
9395 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009396 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009397 for (Map.Entry<String, ArrayList<Intent>> ent
9398 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009399 pw.print(" * Sticky action "); pw.print(ent.getKey());
9400 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009401 ArrayList<Intent> intents = ent.getValue();
9402 final int N = intents.size();
9403 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009404 sb.setLength(0);
9405 sb.append(" Intent: ");
9406 intents.get(i).toShortString(sb, true, false);
9407 pw.println(sb.toString());
9408 Bundle bundle = intents.get(i).getExtras();
9409 if (bundle != null) {
9410 pw.print(" ");
9411 pw.println(bundle.toString());
9412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009413 }
9414 }
9415 }
9416
9417 pw.println(" ");
9418 pw.println(" mHandler:");
9419 mHandler.dump(new PrintWriterPrinter(pw), " ");
9420 }
9421 }
9422
9423 void dumpServices(PrintWriter pw) {
9424 synchronized (this) {
9425 if (checkCallingPermission(android.Manifest.permission.DUMP)
9426 != PackageManager.PERMISSION_GRANTED) {
9427 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9428 + Binder.getCallingPid()
9429 + ", uid=" + Binder.getCallingUid()
9430 + " without permission "
9431 + android.Manifest.permission.DUMP);
9432 return;
9433 }
9434 pw.println("Services in Current Activity Manager State:");
9435
9436 boolean needSep = false;
9437
9438 if (mServices.size() > 0) {
9439 pw.println(" Active services:");
9440 Iterator<ServiceRecord> it = mServices.values().iterator();
9441 while (it.hasNext()) {
9442 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009443 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009444 r.dump(pw, " ");
9445 }
9446 needSep = true;
9447 }
9448
9449 if (mPendingServices.size() > 0) {
9450 if (needSep) pw.println(" ");
9451 pw.println(" Pending services:");
9452 for (int i=0; i<mPendingServices.size(); i++) {
9453 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009454 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009455 r.dump(pw, " ");
9456 }
9457 needSep = true;
9458 }
9459
9460 if (mRestartingServices.size() > 0) {
9461 if (needSep) pw.println(" ");
9462 pw.println(" Restarting services:");
9463 for (int i=0; i<mRestartingServices.size(); i++) {
9464 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009465 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009466 r.dump(pw, " ");
9467 }
9468 needSep = true;
9469 }
9470
9471 if (mStoppingServices.size() > 0) {
9472 if (needSep) pw.println(" ");
9473 pw.println(" Stopping services:");
9474 for (int i=0; i<mStoppingServices.size(); i++) {
9475 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009476 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009477 r.dump(pw, " ");
9478 }
9479 needSep = true;
9480 }
9481
9482 if (mServiceConnections.size() > 0) {
9483 if (needSep) pw.println(" ");
9484 pw.println(" Connection bindings to services:");
9485 Iterator<ConnectionRecord> it
9486 = mServiceConnections.values().iterator();
9487 while (it.hasNext()) {
9488 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009489 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009490 r.dump(pw, " ");
9491 }
9492 }
9493 }
9494 }
9495
9496 void dumpProviders(PrintWriter pw) {
9497 synchronized (this) {
9498 if (checkCallingPermission(android.Manifest.permission.DUMP)
9499 != PackageManager.PERMISSION_GRANTED) {
9500 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9501 + Binder.getCallingPid()
9502 + ", uid=" + Binder.getCallingUid()
9503 + " without permission "
9504 + android.Manifest.permission.DUMP);
9505 return;
9506 }
9507
9508 pw.println("Content Providers in Current Activity Manager State:");
9509
9510 boolean needSep = false;
9511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009512 if (mProvidersByClass.size() > 0) {
9513 if (needSep) pw.println(" ");
9514 pw.println(" Published content providers (by class):");
9515 Iterator it = mProvidersByClass.entrySet().iterator();
9516 while (it.hasNext()) {
9517 Map.Entry e = (Map.Entry)it.next();
9518 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009519 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009520 r.dump(pw, " ");
9521 }
9522 needSep = true;
9523 }
9524
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009525 if (mProvidersByName.size() > 0) {
9526 pw.println(" ");
9527 pw.println(" Authority to provider mappings:");
9528 Iterator it = mProvidersByName.entrySet().iterator();
9529 while (it.hasNext()) {
9530 Map.Entry e = (Map.Entry)it.next();
9531 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9532 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9533 pw.println(r);
9534 }
9535 needSep = true;
9536 }
9537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009538 if (mLaunchingProviders.size() > 0) {
9539 if (needSep) pw.println(" ");
9540 pw.println(" Launching content providers:");
9541 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009542 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9543 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009544 }
9545 needSep = true;
9546 }
9547
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009548 if (mGrantedUriPermissions.size() > 0) {
9549 pw.println();
9550 pw.println("Granted Uri Permissions:");
9551 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9552 int uid = mGrantedUriPermissions.keyAt(i);
9553 HashMap<Uri, UriPermission> perms
9554 = mGrantedUriPermissions.valueAt(i);
9555 pw.print(" * UID "); pw.print(uid);
9556 pw.println(" holds:");
9557 for (UriPermission perm : perms.values()) {
9558 pw.print(" "); pw.println(perm);
9559 perm.dump(pw, " ");
9560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009561 }
9562 }
9563 }
9564 }
9565
9566 void dumpSenders(PrintWriter pw) {
9567 synchronized (this) {
9568 if (checkCallingPermission(android.Manifest.permission.DUMP)
9569 != PackageManager.PERMISSION_GRANTED) {
9570 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9571 + Binder.getCallingPid()
9572 + ", uid=" + Binder.getCallingUid()
9573 + " without permission "
9574 + android.Manifest.permission.DUMP);
9575 return;
9576 }
9577
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009578 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009579
9580 if (this.mIntentSenderRecords.size() > 0) {
9581 Iterator<WeakReference<PendingIntentRecord>> it
9582 = mIntentSenderRecords.values().iterator();
9583 while (it.hasNext()) {
9584 WeakReference<PendingIntentRecord> ref = it.next();
9585 PendingIntentRecord rec = ref != null ? ref.get(): null;
9586 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009587 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009588 rec.dump(pw, " ");
9589 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009590 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009591 }
9592 }
9593 }
9594 }
9595 }
9596
9597 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009598 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009599 TaskRecord lastTask = null;
9600 for (int i=list.size()-1; i>=0; i--) {
9601 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009602 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009603 if (lastTask != r.task) {
9604 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009605 pw.print(prefix);
9606 pw.print(full ? "* " : " ");
9607 pw.println(lastTask);
9608 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009609 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009611 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009612 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9613 pw.print(" #"); pw.print(i); pw.print(": ");
9614 pw.println(r);
9615 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009616 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009617 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009618 }
9619 }
9620
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009621 private static String buildOomTag(String prefix, String space, int val, int base) {
9622 if (val == base) {
9623 if (space == null) return prefix;
9624 return prefix + " ";
9625 }
9626 return prefix + "+" + Integer.toString(val-base);
9627 }
9628
9629 private static final int dumpProcessList(PrintWriter pw,
9630 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009631 String prefix, String normalLabel, String persistentLabel,
9632 boolean inclOomAdj) {
9633 int numPers = 0;
9634 for (int i=list.size()-1; i>=0; i--) {
9635 ProcessRecord r = (ProcessRecord)list.get(i);
9636 if (false) {
9637 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9638 + " #" + i + ":");
9639 r.dump(pw, prefix + " ");
9640 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009641 String oomAdj;
9642 if (r.setAdj >= EMPTY_APP_ADJ) {
9643 oomAdj = buildOomTag("empty", null, r.setAdj,
9644 EMPTY_APP_ADJ);
9645 } else if (r.setAdj >= CONTENT_PROVIDER_ADJ) {
9646 oomAdj = buildOomTag("cprov", null, r.setAdj,
9647 CONTENT_PROVIDER_ADJ);
9648 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
9649 oomAdj = buildOomTag("hid", " ", r.setAdj,
9650 HIDDEN_APP_MIN_ADJ);
9651 } else if (r.setAdj >= service.HOME_APP_ADJ) {
9652 oomAdj = buildOomTag("home ", null, r.setAdj,
9653 service.HOME_APP_ADJ);
9654 } else if (r.setAdj >= service.SECONDARY_SERVER_ADJ) {
9655 oomAdj = buildOomTag("svc", " ", r.setAdj,
9656 service.SECONDARY_SERVER_ADJ);
9657 } else if (r.setAdj >= service.BACKUP_APP_ADJ) {
9658 oomAdj = buildOomTag("bckup", null, r.setAdj,
9659 service.BACKUP_APP_ADJ);
9660 } else if (r.setAdj >= service.VISIBLE_APP_ADJ) {
9661 oomAdj = buildOomTag("vis ", null, r.setAdj,
9662 service.VISIBLE_APP_ADJ);
9663 } else if (r.setAdj >= service.FOREGROUND_APP_ADJ) {
9664 oomAdj = buildOomTag("fore ", null, r.setAdj,
9665 service.FOREGROUND_APP_ADJ);
9666 } else if (r.setAdj >= CORE_SERVER_ADJ) {
9667 oomAdj = buildOomTag("core ", null, r.setAdj,
9668 CORE_SERVER_ADJ);
9669 } else if (r.setAdj >= SYSTEM_ADJ) {
9670 oomAdj = buildOomTag("sys ", null, r.setAdj,
9671 SYSTEM_ADJ);
9672 } else {
9673 oomAdj = Integer.toString(r.setAdj);
9674 }
9675 String schedGroup;
9676 switch (r.setSchedGroup) {
9677 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9678 schedGroup = "B";
9679 break;
9680 case Process.THREAD_GROUP_DEFAULT:
9681 schedGroup = "F";
9682 break;
9683 default:
9684 schedGroup = Integer.toString(r.setSchedGroup);
9685 break;
9686 }
9687 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009688 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009689 i, oomAdj, schedGroup, r.toString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009690 if (r.adjSource != null || r.adjTarget != null) {
9691 pw.println(prefix + " " + r.adjTarget
9692 + " used by " + r.adjSource);
9693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009694 } else {
9695 pw.println(String.format("%s%s #%2d: %s",
9696 prefix, (r.persistent ? persistentLabel : normalLabel),
9697 i, r.toString()));
9698 }
9699 if (r.persistent) {
9700 numPers++;
9701 }
9702 }
9703 return numPers;
9704 }
9705
9706 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9707 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009708 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009709 long uptime = SystemClock.uptimeMillis();
9710 long realtime = SystemClock.elapsedRealtime();
9711
9712 if (isCheckinRequest) {
9713 // short checkin version
9714 pw.println(uptime + "," + realtime);
9715 pw.flush();
9716 } else {
9717 pw.println("Applications Memory Usage (kB):");
9718 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9719 }
9720 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9721 ProcessRecord r = (ProcessRecord)list.get(i);
9722 if (r.thread != null) {
9723 if (!isCheckinRequest) {
9724 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9725 pw.flush();
9726 }
9727 try {
9728 r.thread.asBinder().dump(fd, args);
9729 } catch (RemoteException e) {
9730 if (!isCheckinRequest) {
9731 pw.println("Got RemoteException!");
9732 pw.flush();
9733 }
9734 }
9735 }
9736 }
9737 }
9738
9739 /**
9740 * Searches array of arguments for the specified string
9741 * @param args array of argument strings
9742 * @param value value to search for
9743 * @return true if the value is contained in the array
9744 */
9745 private static boolean scanArgs(String[] args, String value) {
9746 if (args != null) {
9747 for (String arg : args) {
9748 if (value.equals(arg)) {
9749 return true;
9750 }
9751 }
9752 }
9753 return false;
9754 }
9755
Dianne Hackborn75b03852009-06-12 15:43:26 -07009756 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009757 int count = mHistory.size();
9758
9759 // convert the token to an entry in the history.
9760 HistoryRecord r = null;
9761 int index = -1;
9762 for (int i=count-1; i>=0; i--) {
9763 Object o = mHistory.get(i);
9764 if (o == token) {
9765 r = (HistoryRecord)o;
9766 index = i;
9767 break;
9768 }
9769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009770
9771 return index;
9772 }
9773
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009774 private final void killServicesLocked(ProcessRecord app,
9775 boolean allowRestart) {
9776 // Report disconnected services.
9777 if (false) {
9778 // XXX we are letting the client link to the service for
9779 // death notifications.
9780 if (app.services.size() > 0) {
9781 Iterator it = app.services.iterator();
9782 while (it.hasNext()) {
9783 ServiceRecord r = (ServiceRecord)it.next();
9784 if (r.connections.size() > 0) {
9785 Iterator<ConnectionRecord> jt
9786 = r.connections.values().iterator();
9787 while (jt.hasNext()) {
9788 ConnectionRecord c = jt.next();
9789 if (c.binding.client != app) {
9790 try {
9791 //c.conn.connected(r.className, null);
9792 } catch (Exception e) {
9793 // todo: this should be asynchronous!
9794 Log.w(TAG, "Exception thrown disconnected servce "
9795 + r.shortName
9796 + " from app " + app.processName, e);
9797 }
9798 }
9799 }
9800 }
9801 }
9802 }
9803 }
9804
9805 // Clean up any connections this application has to other services.
9806 if (app.connections.size() > 0) {
9807 Iterator<ConnectionRecord> it = app.connections.iterator();
9808 while (it.hasNext()) {
9809 ConnectionRecord r = it.next();
9810 removeConnectionLocked(r, app, null);
9811 }
9812 }
9813 app.connections.clear();
9814
9815 if (app.services.size() != 0) {
9816 // Any services running in the application need to be placed
9817 // back in the pending list.
9818 Iterator it = app.services.iterator();
9819 while (it.hasNext()) {
9820 ServiceRecord sr = (ServiceRecord)it.next();
9821 synchronized (sr.stats.getBatteryStats()) {
9822 sr.stats.stopLaunchedLocked();
9823 }
9824 sr.app = null;
9825 sr.executeNesting = 0;
9826 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009827
9828 boolean hasClients = sr.bindings.size() > 0;
9829 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009830 Iterator<IntentBindRecord> bindings
9831 = sr.bindings.values().iterator();
9832 while (bindings.hasNext()) {
9833 IntentBindRecord b = bindings.next();
9834 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9835 + ": shouldUnbind=" + b.hasBound);
9836 b.binder = null;
9837 b.requested = b.received = b.hasBound = false;
9838 }
9839 }
9840
9841 if (sr.crashCount >= 2) {
9842 Log.w(TAG, "Service crashed " + sr.crashCount
9843 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -08009844 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009845 sr.crashCount, sr.shortName, app.pid);
9846 bringDownServiceLocked(sr, true);
9847 } else if (!allowRestart) {
9848 bringDownServiceLocked(sr, true);
9849 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009850 boolean canceled = scheduleServiceRestartLocked(sr, true);
9851
9852 // Should the service remain running? Note that in the
9853 // extreme case of so many attempts to deliver a command
9854 // that it failed, that we also will stop it here.
9855 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9856 if (sr.pendingStarts.size() == 0) {
9857 sr.startRequested = false;
9858 if (!hasClients) {
9859 // Whoops, no reason to restart!
9860 bringDownServiceLocked(sr, true);
9861 }
9862 }
9863 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009864 }
9865 }
9866
9867 if (!allowRestart) {
9868 app.services.clear();
9869 }
9870 }
9871
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009872 // Make sure we have no more records on the stopping list.
9873 int i = mStoppingServices.size();
9874 while (i > 0) {
9875 i--;
9876 ServiceRecord sr = mStoppingServices.get(i);
9877 if (sr.app == app) {
9878 mStoppingServices.remove(i);
9879 }
9880 }
9881
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009882 app.executingServices.clear();
9883 }
9884
9885 private final void removeDyingProviderLocked(ProcessRecord proc,
9886 ContentProviderRecord cpr) {
9887 synchronized (cpr) {
9888 cpr.launchingApp = null;
9889 cpr.notifyAll();
9890 }
9891
9892 mProvidersByClass.remove(cpr.info.name);
9893 String names[] = cpr.info.authority.split(";");
9894 for (int j = 0; j < names.length; j++) {
9895 mProvidersByName.remove(names[j]);
9896 }
9897
9898 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9899 while (cit.hasNext()) {
9900 ProcessRecord capp = cit.next();
9901 if (!capp.persistent && capp.thread != null
9902 && capp.pid != 0
9903 && capp.pid != MY_PID) {
9904 Log.i(TAG, "Killing app " + capp.processName
9905 + " (pid " + capp.pid
9906 + ") because provider " + cpr.info.name
9907 + " is in dying process " + proc.processName);
9908 Process.killProcess(capp.pid);
9909 }
9910 }
9911
9912 mLaunchingProviders.remove(cpr);
9913 }
9914
9915 /**
9916 * Main code for cleaning up a process when it has gone away. This is
9917 * called both as a result of the process dying, or directly when stopping
9918 * a process when running in single process mode.
9919 */
9920 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9921 boolean restarting, int index) {
9922 if (index >= 0) {
9923 mLRUProcesses.remove(index);
9924 }
9925
Dianne Hackborn36124872009-10-08 16:22:03 -07009926 mProcessesToGc.remove(app);
9927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009928 // Dismiss any open dialogs.
9929 if (app.crashDialog != null) {
9930 app.crashDialog.dismiss();
9931 app.crashDialog = null;
9932 }
9933 if (app.anrDialog != null) {
9934 app.anrDialog.dismiss();
9935 app.anrDialog = null;
9936 }
9937 if (app.waitDialog != null) {
9938 app.waitDialog.dismiss();
9939 app.waitDialog = null;
9940 }
9941
9942 app.crashing = false;
9943 app.notResponding = false;
9944
9945 app.resetPackageList();
9946 app.thread = null;
9947 app.forcingToForeground = null;
9948 app.foregroundServices = false;
9949
9950 killServicesLocked(app, true);
9951
9952 boolean restart = false;
9953
9954 int NL = mLaunchingProviders.size();
9955
9956 // Remove published content providers.
9957 if (!app.pubProviders.isEmpty()) {
9958 Iterator it = app.pubProviders.values().iterator();
9959 while (it.hasNext()) {
9960 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9961 cpr.provider = null;
9962 cpr.app = null;
9963
9964 // See if someone is waiting for this provider... in which
9965 // case we don't remove it, but just let it restart.
9966 int i = 0;
9967 if (!app.bad) {
9968 for (; i<NL; i++) {
9969 if (mLaunchingProviders.get(i) == cpr) {
9970 restart = true;
9971 break;
9972 }
9973 }
9974 } else {
9975 i = NL;
9976 }
9977
9978 if (i >= NL) {
9979 removeDyingProviderLocked(app, cpr);
9980 NL = mLaunchingProviders.size();
9981 }
9982 }
9983 app.pubProviders.clear();
9984 }
9985
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009986 // Take care of any launching providers waiting for this process.
9987 if (checkAppInLaunchingProvidersLocked(app, false)) {
9988 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009989 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009991 // Unregister from connected content providers.
9992 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009993 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009994 while (it.hasNext()) {
9995 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9996 cpr.clients.remove(app);
9997 }
9998 app.conProviders.clear();
9999 }
10000
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010001 // At this point there may be remaining entries in mLaunchingProviders
10002 // where we were the only one waiting, so they are no longer of use.
10003 // Look for these and clean up if found.
10004 // XXX Commented out for now. Trying to figure out a way to reproduce
10005 // the actual situation to identify what is actually going on.
10006 if (false) {
10007 for (int i=0; i<NL; i++) {
10008 ContentProviderRecord cpr = (ContentProviderRecord)
10009 mLaunchingProviders.get(i);
10010 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10011 synchronized (cpr) {
10012 cpr.launchingApp = null;
10013 cpr.notifyAll();
10014 }
10015 }
10016 }
10017 }
10018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010019 skipCurrentReceiverLocked(app);
10020
10021 // Unregister any receivers.
10022 if (app.receivers.size() > 0) {
10023 Iterator<ReceiverList> it = app.receivers.iterator();
10024 while (it.hasNext()) {
10025 removeReceiverLocked(it.next());
10026 }
10027 app.receivers.clear();
10028 }
10029
Christopher Tate181fafa2009-05-14 11:12:14 -070010030 // If the app is undergoing backup, tell the backup manager about it
10031 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10032 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10033 try {
10034 IBackupManager bm = IBackupManager.Stub.asInterface(
10035 ServiceManager.getService(Context.BACKUP_SERVICE));
10036 bm.agentDisconnected(app.info.packageName);
10037 } catch (RemoteException e) {
10038 // can't happen; backup manager is local
10039 }
10040 }
10041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010042 // If the caller is restarting this app, then leave it in its
10043 // current lists and let the caller take care of it.
10044 if (restarting) {
10045 return;
10046 }
10047
10048 if (!app.persistent) {
10049 if (DEBUG_PROCESSES) Log.v(TAG,
10050 "Removing non-persistent process during cleanup: " + app);
10051 mProcessNames.remove(app.processName, app.info.uid);
10052 } else if (!app.removed) {
10053 // This app is persistent, so we need to keep its record around.
10054 // If it is not already on the pending app list, add it there
10055 // and start a new process for it.
10056 app.thread = null;
10057 app.forcingToForeground = null;
10058 app.foregroundServices = false;
10059 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10060 mPersistentStartingProcesses.add(app);
10061 restart = true;
10062 }
10063 }
10064 mProcessesOnHold.remove(app);
10065
The Android Open Source Project4df24232009-03-05 14:34:35 -080010066 if (app == mHomeProcess) {
10067 mHomeProcess = null;
10068 }
10069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010070 if (restart) {
10071 // We have components that still need to be running in the
10072 // process, so re-launch it.
10073 mProcessNames.put(app.processName, app.info.uid, app);
10074 startProcessLocked(app, "restart", app.processName);
10075 } else if (app.pid > 0 && app.pid != MY_PID) {
10076 // Goodbye!
10077 synchronized (mPidsSelfLocked) {
10078 mPidsSelfLocked.remove(app.pid);
10079 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10080 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010081 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010082 }
10083 }
10084
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010085 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10086 // Look through the content providers we are waiting to have launched,
10087 // and if any run in this process then either schedule a restart of
10088 // the process or kill the client waiting for it if this process has
10089 // gone bad.
10090 int NL = mLaunchingProviders.size();
10091 boolean restart = false;
10092 for (int i=0; i<NL; i++) {
10093 ContentProviderRecord cpr = (ContentProviderRecord)
10094 mLaunchingProviders.get(i);
10095 if (cpr.launchingApp == app) {
10096 if (!alwaysBad && !app.bad) {
10097 restart = true;
10098 } else {
10099 removeDyingProviderLocked(app, cpr);
10100 NL = mLaunchingProviders.size();
10101 }
10102 }
10103 }
10104 return restart;
10105 }
10106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010107 // =========================================================
10108 // SERVICES
10109 // =========================================================
10110
10111 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10112 ActivityManager.RunningServiceInfo info =
10113 new ActivityManager.RunningServiceInfo();
10114 info.service = r.name;
10115 if (r.app != null) {
10116 info.pid = r.app.pid;
10117 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010118 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010119 info.process = r.processName;
10120 info.foreground = r.isForeground;
10121 info.activeSince = r.createTime;
10122 info.started = r.startRequested;
10123 info.clientCount = r.connections.size();
10124 info.crashCount = r.crashCount;
10125 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010126 if (r.isForeground) {
10127 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10128 }
10129 if (r.startRequested) {
10130 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10131 }
10132 if (r.app != null && r.app.pid == Process.myPid()) {
10133 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10134 }
10135 if (r.app != null && r.app.persistent) {
10136 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10137 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010138 for (ConnectionRecord conn : r.connections.values()) {
10139 if (conn.clientLabel != 0) {
10140 info.clientPackage = conn.binding.client.info.packageName;
10141 info.clientLabel = conn.clientLabel;
10142 break;
10143 }
10144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010145 return info;
10146 }
10147
10148 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10149 int flags) {
10150 synchronized (this) {
10151 ArrayList<ActivityManager.RunningServiceInfo> res
10152 = new ArrayList<ActivityManager.RunningServiceInfo>();
10153
10154 if (mServices.size() > 0) {
10155 Iterator<ServiceRecord> it = mServices.values().iterator();
10156 while (it.hasNext() && res.size() < maxNum) {
10157 res.add(makeRunningServiceInfoLocked(it.next()));
10158 }
10159 }
10160
10161 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10162 ServiceRecord r = mRestartingServices.get(i);
10163 ActivityManager.RunningServiceInfo info =
10164 makeRunningServiceInfoLocked(r);
10165 info.restarting = r.nextRestartTime;
10166 res.add(info);
10167 }
10168
10169 return res;
10170 }
10171 }
10172
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010173 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10174 synchronized (this) {
10175 ServiceRecord r = mServices.get(name);
10176 if (r != null) {
10177 for (ConnectionRecord conn : r.connections.values()) {
10178 if (conn.clientIntent != null) {
10179 return conn.clientIntent;
10180 }
10181 }
10182 }
10183 }
10184 return null;
10185 }
10186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010187 private final ServiceRecord findServiceLocked(ComponentName name,
10188 IBinder token) {
10189 ServiceRecord r = mServices.get(name);
10190 return r == token ? r : null;
10191 }
10192
10193 private final class ServiceLookupResult {
10194 final ServiceRecord record;
10195 final String permission;
10196
10197 ServiceLookupResult(ServiceRecord _record, String _permission) {
10198 record = _record;
10199 permission = _permission;
10200 }
10201 };
10202
10203 private ServiceLookupResult findServiceLocked(Intent service,
10204 String resolvedType) {
10205 ServiceRecord r = null;
10206 if (service.getComponent() != null) {
10207 r = mServices.get(service.getComponent());
10208 }
10209 if (r == null) {
10210 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10211 r = mServicesByIntent.get(filter);
10212 }
10213
10214 if (r == null) {
10215 try {
10216 ResolveInfo rInfo =
10217 ActivityThread.getPackageManager().resolveService(
10218 service, resolvedType, 0);
10219 ServiceInfo sInfo =
10220 rInfo != null ? rInfo.serviceInfo : null;
10221 if (sInfo == null) {
10222 return null;
10223 }
10224
10225 ComponentName name = new ComponentName(
10226 sInfo.applicationInfo.packageName, sInfo.name);
10227 r = mServices.get(name);
10228 } catch (RemoteException ex) {
10229 // pm is in same process, this will never happen.
10230 }
10231 }
10232 if (r != null) {
10233 int callingPid = Binder.getCallingPid();
10234 int callingUid = Binder.getCallingUid();
10235 if (checkComponentPermission(r.permission,
10236 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10237 != PackageManager.PERMISSION_GRANTED) {
10238 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10239 + " from pid=" + callingPid
10240 + ", uid=" + callingUid
10241 + " requires " + r.permission);
10242 return new ServiceLookupResult(null, r.permission);
10243 }
10244 return new ServiceLookupResult(r, null);
10245 }
10246 return null;
10247 }
10248
10249 private class ServiceRestarter implements Runnable {
10250 private ServiceRecord mService;
10251
10252 void setService(ServiceRecord service) {
10253 mService = service;
10254 }
10255
10256 public void run() {
10257 synchronized(ActivityManagerService.this) {
10258 performServiceRestartLocked(mService);
10259 }
10260 }
10261 }
10262
10263 private ServiceLookupResult retrieveServiceLocked(Intent service,
10264 String resolvedType, int callingPid, int callingUid) {
10265 ServiceRecord r = null;
10266 if (service.getComponent() != null) {
10267 r = mServices.get(service.getComponent());
10268 }
10269 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10270 r = mServicesByIntent.get(filter);
10271 if (r == null) {
10272 try {
10273 ResolveInfo rInfo =
10274 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010275 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010276 ServiceInfo sInfo =
10277 rInfo != null ? rInfo.serviceInfo : null;
10278 if (sInfo == null) {
10279 Log.w(TAG, "Unable to start service " + service +
10280 ": not found");
10281 return null;
10282 }
10283
10284 ComponentName name = new ComponentName(
10285 sInfo.applicationInfo.packageName, sInfo.name);
10286 r = mServices.get(name);
10287 if (r == null) {
10288 filter = new Intent.FilterComparison(service.cloneFilter());
10289 ServiceRestarter res = new ServiceRestarter();
10290 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10291 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10292 synchronized (stats) {
10293 ss = stats.getServiceStatsLocked(
10294 sInfo.applicationInfo.uid, sInfo.packageName,
10295 sInfo.name);
10296 }
10297 r = new ServiceRecord(ss, name, filter, sInfo, res);
10298 res.setService(r);
10299 mServices.put(name, r);
10300 mServicesByIntent.put(filter, r);
10301
10302 // Make sure this component isn't in the pending list.
10303 int N = mPendingServices.size();
10304 for (int i=0; i<N; i++) {
10305 ServiceRecord pr = mPendingServices.get(i);
10306 if (pr.name.equals(name)) {
10307 mPendingServices.remove(i);
10308 i--;
10309 N--;
10310 }
10311 }
10312 }
10313 } catch (RemoteException ex) {
10314 // pm is in same process, this will never happen.
10315 }
10316 }
10317 if (r != null) {
10318 if (checkComponentPermission(r.permission,
10319 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10320 != PackageManager.PERMISSION_GRANTED) {
10321 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10322 + " from pid=" + Binder.getCallingPid()
10323 + ", uid=" + Binder.getCallingUid()
10324 + " requires " + r.permission);
10325 return new ServiceLookupResult(null, r.permission);
10326 }
10327 return new ServiceLookupResult(r, null);
10328 }
10329 return null;
10330 }
10331
10332 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10333 long now = SystemClock.uptimeMillis();
10334 if (r.executeNesting == 0 && r.app != null) {
10335 if (r.app.executingServices.size() == 0) {
10336 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10337 msg.obj = r.app;
10338 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10339 }
10340 r.app.executingServices.add(r);
10341 }
10342 r.executeNesting++;
10343 r.executingStart = now;
10344 }
10345
10346 private final void sendServiceArgsLocked(ServiceRecord r,
10347 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010348 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010349 if (N == 0) {
10350 return;
10351 }
10352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010353 int i = 0;
10354 while (i < N) {
10355 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010356 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010357 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010358 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010359 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010360 // If somehow we got a dummy start at the front, then
10361 // just drop it here.
10362 i++;
10363 continue;
10364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010365 bumpServiceExecutingLocked(r);
10366 if (!oomAdjusted) {
10367 oomAdjusted = true;
10368 updateOomAdjLocked(r.app);
10369 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010370 int flags = 0;
10371 if (si.deliveryCount > 0) {
10372 flags |= Service.START_FLAG_RETRY;
10373 }
10374 if (si.doneExecutingCount > 0) {
10375 flags |= Service.START_FLAG_REDELIVERY;
10376 }
10377 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10378 si.deliveredTime = SystemClock.uptimeMillis();
10379 r.deliveredStarts.add(si);
10380 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010381 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010382 } catch (RemoteException e) {
10383 // Remote process gone... we'll let the normal cleanup take
10384 // care of this.
10385 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010386 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010387 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010388 break;
10389 }
10390 }
10391 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010392 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010393 } else {
10394 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010395 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010396 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010397 }
10398 }
10399 }
10400
10401 private final boolean requestServiceBindingLocked(ServiceRecord r,
10402 IntentBindRecord i, boolean rebind) {
10403 if (r.app == null || r.app.thread == null) {
10404 // If service is not currently running, can't yet bind.
10405 return false;
10406 }
10407 if ((!i.requested || rebind) && i.apps.size() > 0) {
10408 try {
10409 bumpServiceExecutingLocked(r);
10410 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10411 + ": shouldUnbind=" + i.hasBound);
10412 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10413 if (!rebind) {
10414 i.requested = true;
10415 }
10416 i.hasBound = true;
10417 i.doRebind = false;
10418 } catch (RemoteException e) {
10419 return false;
10420 }
10421 }
10422 return true;
10423 }
10424
10425 private final void requestServiceBindingsLocked(ServiceRecord r) {
10426 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10427 while (bindings.hasNext()) {
10428 IntentBindRecord i = bindings.next();
10429 if (!requestServiceBindingLocked(r, i, false)) {
10430 break;
10431 }
10432 }
10433 }
10434
10435 private final void realStartServiceLocked(ServiceRecord r,
10436 ProcessRecord app) throws RemoteException {
10437 if (app.thread == null) {
10438 throw new RemoteException();
10439 }
10440
10441 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010442 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010443
10444 app.services.add(r);
10445 bumpServiceExecutingLocked(r);
10446 updateLRUListLocked(app, true);
10447
10448 boolean created = false;
10449 try {
10450 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10451 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010452 mStringBuilder.setLength(0);
10453 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010454 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010455 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010456 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010457 synchronized (r.stats.getBatteryStats()) {
10458 r.stats.startLaunchedLocked();
10459 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010460 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010461 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010462 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010463 created = true;
10464 } finally {
10465 if (!created) {
10466 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010467 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010468 }
10469 }
10470
10471 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010472
10473 // If the service is in the started state, and there are no
10474 // pending arguments, then fake up one so its onStartCommand() will
10475 // be called.
10476 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10477 r.lastStartId++;
10478 if (r.lastStartId < 1) {
10479 r.lastStartId = 1;
10480 }
10481 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10482 }
10483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010484 sendServiceArgsLocked(r, true);
10485 }
10486
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010487 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10488 boolean allowCancel) {
10489 boolean canceled = false;
10490
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010491 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010492 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010493 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010494
10495 // Any delivered but not yet finished starts should be put back
10496 // on the pending list.
10497 final int N = r.deliveredStarts.size();
10498 if (N > 0) {
10499 for (int i=N-1; i>=0; i--) {
10500 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10501 if (si.intent == null) {
10502 // We'll generate this again if needed.
10503 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10504 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10505 r.pendingStarts.add(0, si);
10506 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10507 dur *= 2;
10508 if (minDuration < dur) minDuration = dur;
10509 if (resetTime < dur) resetTime = dur;
10510 } else {
10511 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10512 + r.name);
10513 canceled = true;
10514 }
10515 }
10516 r.deliveredStarts.clear();
10517 }
10518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010519 r.totalRestartCount++;
10520 if (r.restartDelay == 0) {
10521 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010522 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010523 } else {
10524 // If it has been a "reasonably long time" since the service
10525 // was started, then reset our restart duration back to
10526 // the beginning, so we don't infinitely increase the duration
10527 // on a service that just occasionally gets killed (which is
10528 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010529 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010530 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010531 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010532 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010533 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010534 if (r.restartDelay < minDuration) {
10535 r.restartDelay = minDuration;
10536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010537 }
10538 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010539
10540 r.nextRestartTime = now + r.restartDelay;
10541
10542 // Make sure that we don't end up restarting a bunch of services
10543 // all at the same time.
10544 boolean repeat;
10545 do {
10546 repeat = false;
10547 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10548 ServiceRecord r2 = mRestartingServices.get(i);
10549 if (r2 != r && r.nextRestartTime
10550 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10551 && r.nextRestartTime
10552 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10553 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10554 r.restartDelay = r.nextRestartTime - now;
10555 repeat = true;
10556 break;
10557 }
10558 }
10559 } while (repeat);
10560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010561 if (!mRestartingServices.contains(r)) {
10562 mRestartingServices.add(r);
10563 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010564
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010565 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010567 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010568 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010569 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10570 Log.w(TAG, "Scheduling restart of crashed service "
10571 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010572 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010573 r.shortName, r.restartDelay);
10574
10575 Message msg = Message.obtain();
10576 msg.what = SERVICE_ERROR_MSG;
10577 msg.obj = r;
10578 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010579
10580 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010581 }
10582
10583 final void performServiceRestartLocked(ServiceRecord r) {
10584 if (!mRestartingServices.contains(r)) {
10585 return;
10586 }
10587 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10588 }
10589
10590 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10591 if (r.restartDelay == 0) {
10592 return false;
10593 }
10594 r.resetRestartCounter();
10595 mRestartingServices.remove(r);
10596 mHandler.removeCallbacks(r.restarter);
10597 return true;
10598 }
10599
10600 private final boolean bringUpServiceLocked(ServiceRecord r,
10601 int intentFlags, boolean whileRestarting) {
10602 //Log.i(TAG, "Bring up service:");
10603 //r.dump(" ");
10604
Dianne Hackborn36124872009-10-08 16:22:03 -070010605 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010606 sendServiceArgsLocked(r, false);
10607 return true;
10608 }
10609
10610 if (!whileRestarting && r.restartDelay > 0) {
10611 // If waiting for a restart, then do nothing.
10612 return true;
10613 }
10614
10615 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10616 + " " + r.intent);
10617
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010618 // We are now bringing the service up, so no longer in the
10619 // restarting state.
10620 mRestartingServices.remove(r);
10621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010622 final String appName = r.processName;
10623 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10624 if (app != null && app.thread != null) {
10625 try {
10626 realStartServiceLocked(r, app);
10627 return true;
10628 } catch (RemoteException e) {
10629 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10630 }
10631
10632 // If a dead object exception was thrown -- fall through to
10633 // restart the application.
10634 }
10635
Dianne Hackborn36124872009-10-08 16:22:03 -070010636 // Not running -- get it started, and enqueue this service record
10637 // to be executed when the app comes up.
10638 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10639 "service", r.name, false) == null) {
10640 Log.w(TAG, "Unable to launch app "
10641 + r.appInfo.packageName + "/"
10642 + r.appInfo.uid + " for service "
10643 + r.intent.getIntent() + ": process is bad");
10644 bringDownServiceLocked(r, true);
10645 return false;
10646 }
10647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010648 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010649 mPendingServices.add(r);
10650 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010652 return true;
10653 }
10654
10655 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10656 //Log.i(TAG, "Bring down service:");
10657 //r.dump(" ");
10658
10659 // Does it still need to run?
10660 if (!force && r.startRequested) {
10661 return;
10662 }
10663 if (r.connections.size() > 0) {
10664 if (!force) {
10665 // XXX should probably keep a count of the number of auto-create
10666 // connections directly in the service.
10667 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10668 while (it.hasNext()) {
10669 ConnectionRecord cr = it.next();
10670 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10671 return;
10672 }
10673 }
10674 }
10675
10676 // Report to all of the connections that the service is no longer
10677 // available.
10678 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10679 while (it.hasNext()) {
10680 ConnectionRecord c = it.next();
10681 try {
10682 // todo: shouldn't be a synchronous call!
10683 c.conn.connected(r.name, null);
10684 } catch (Exception e) {
10685 Log.w(TAG, "Failure disconnecting service " + r.name +
10686 " to connection " + c.conn.asBinder() +
10687 " (in " + c.binding.client.processName + ")", e);
10688 }
10689 }
10690 }
10691
10692 // Tell the service that it has been unbound.
10693 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10694 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10695 while (it.hasNext()) {
10696 IntentBindRecord ibr = it.next();
10697 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10698 + ": hasBound=" + ibr.hasBound);
10699 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10700 try {
10701 bumpServiceExecutingLocked(r);
10702 updateOomAdjLocked(r.app);
10703 ibr.hasBound = false;
10704 r.app.thread.scheduleUnbindService(r,
10705 ibr.intent.getIntent());
10706 } catch (Exception e) {
10707 Log.w(TAG, "Exception when unbinding service "
10708 + r.shortName, e);
10709 serviceDoneExecutingLocked(r, true);
10710 }
10711 }
10712 }
10713 }
10714
10715 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10716 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010717 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010718 System.identityHashCode(r), r.shortName,
10719 (r.app != null) ? r.app.pid : -1);
10720
10721 mServices.remove(r.name);
10722 mServicesByIntent.remove(r.intent);
10723 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10724 r.totalRestartCount = 0;
10725 unscheduleServiceRestartLocked(r);
10726
10727 // Also make sure it is not on the pending list.
10728 int N = mPendingServices.size();
10729 for (int i=0; i<N; i++) {
10730 if (mPendingServices.get(i) == r) {
10731 mPendingServices.remove(i);
10732 if (DEBUG_SERVICE) Log.v(
10733 TAG, "Removed pending service: " + r.shortName);
10734 i--;
10735 N--;
10736 }
10737 }
10738
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010739 r.cancelNotification();
10740 r.isForeground = false;
10741 r.foregroundId = 0;
10742 r.foregroundNoti = null;
10743
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010744 // Clear start entries.
10745 r.deliveredStarts.clear();
10746 r.pendingStarts.clear();
10747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010748 if (r.app != null) {
10749 synchronized (r.stats.getBatteryStats()) {
10750 r.stats.stopLaunchedLocked();
10751 }
10752 r.app.services.remove(r);
10753 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010754 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010755 if (DEBUG_SERVICE) Log.v(TAG,
10756 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010757 bumpServiceExecutingLocked(r);
10758 mStoppingServices.add(r);
10759 updateOomAdjLocked(r.app);
10760 r.app.thread.scheduleStopService(r);
10761 } catch (Exception e) {
10762 Log.w(TAG, "Exception when stopping service "
10763 + r.shortName, e);
10764 serviceDoneExecutingLocked(r, true);
10765 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010766 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010767 } else {
10768 if (DEBUG_SERVICE) Log.v(
10769 TAG, "Removed service that has no process: " + r.shortName);
10770 }
10771 } else {
10772 if (DEBUG_SERVICE) Log.v(
10773 TAG, "Removed service that is not running: " + r.shortName);
10774 }
10775 }
10776
10777 ComponentName startServiceLocked(IApplicationThread caller,
10778 Intent service, String resolvedType,
10779 int callingPid, int callingUid) {
10780 synchronized(this) {
10781 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10782 + " type=" + resolvedType + " args=" + service.getExtras());
10783
10784 if (caller != null) {
10785 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10786 if (callerApp == null) {
10787 throw new SecurityException(
10788 "Unable to find app for caller " + caller
10789 + " (pid=" + Binder.getCallingPid()
10790 + ") when starting service " + service);
10791 }
10792 }
10793
10794 ServiceLookupResult res =
10795 retrieveServiceLocked(service, resolvedType,
10796 callingPid, callingUid);
10797 if (res == null) {
10798 return null;
10799 }
10800 if (res.record == null) {
10801 return new ComponentName("!", res.permission != null
10802 ? res.permission : "private to package");
10803 }
10804 ServiceRecord r = res.record;
10805 if (unscheduleServiceRestartLocked(r)) {
10806 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10807 + r.shortName);
10808 }
10809 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010810 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010811 r.lastStartId++;
10812 if (r.lastStartId < 1) {
10813 r.lastStartId = 1;
10814 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010815 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010816 r.lastActivity = SystemClock.uptimeMillis();
10817 synchronized (r.stats.getBatteryStats()) {
10818 r.stats.startRunningLocked();
10819 }
10820 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10821 return new ComponentName("!", "Service process is bad");
10822 }
10823 return r.name;
10824 }
10825 }
10826
10827 public ComponentName startService(IApplicationThread caller, Intent service,
10828 String resolvedType) {
10829 // Refuse possible leaked file descriptors
10830 if (service != null && service.hasFileDescriptors() == true) {
10831 throw new IllegalArgumentException("File descriptors passed in Intent");
10832 }
10833
10834 synchronized(this) {
10835 final int callingPid = Binder.getCallingPid();
10836 final int callingUid = Binder.getCallingUid();
10837 final long origId = Binder.clearCallingIdentity();
10838 ComponentName res = startServiceLocked(caller, service,
10839 resolvedType, callingPid, callingUid);
10840 Binder.restoreCallingIdentity(origId);
10841 return res;
10842 }
10843 }
10844
10845 ComponentName startServiceInPackage(int uid,
10846 Intent service, String resolvedType) {
10847 synchronized(this) {
10848 final long origId = Binder.clearCallingIdentity();
10849 ComponentName res = startServiceLocked(null, service,
10850 resolvedType, -1, uid);
10851 Binder.restoreCallingIdentity(origId);
10852 return res;
10853 }
10854 }
10855
10856 public int stopService(IApplicationThread caller, Intent service,
10857 String resolvedType) {
10858 // Refuse possible leaked file descriptors
10859 if (service != null && service.hasFileDescriptors() == true) {
10860 throw new IllegalArgumentException("File descriptors passed in Intent");
10861 }
10862
10863 synchronized(this) {
10864 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10865 + " type=" + resolvedType);
10866
10867 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10868 if (caller != null && callerApp == null) {
10869 throw new SecurityException(
10870 "Unable to find app for caller " + caller
10871 + " (pid=" + Binder.getCallingPid()
10872 + ") when stopping service " + service);
10873 }
10874
10875 // If this service is active, make sure it is stopped.
10876 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10877 if (r != null) {
10878 if (r.record != null) {
10879 synchronized (r.record.stats.getBatteryStats()) {
10880 r.record.stats.stopRunningLocked();
10881 }
10882 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010883 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010884 final long origId = Binder.clearCallingIdentity();
10885 bringDownServiceLocked(r.record, false);
10886 Binder.restoreCallingIdentity(origId);
10887 return 1;
10888 }
10889 return -1;
10890 }
10891 }
10892
10893 return 0;
10894 }
10895
10896 public IBinder peekService(Intent service, String resolvedType) {
10897 // Refuse possible leaked file descriptors
10898 if (service != null && service.hasFileDescriptors() == true) {
10899 throw new IllegalArgumentException("File descriptors passed in Intent");
10900 }
10901
10902 IBinder ret = null;
10903
10904 synchronized(this) {
10905 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10906
10907 if (r != null) {
10908 // r.record is null if findServiceLocked() failed the caller permission check
10909 if (r.record == null) {
10910 throw new SecurityException(
10911 "Permission Denial: Accessing service " + r.record.name
10912 + " from pid=" + Binder.getCallingPid()
10913 + ", uid=" + Binder.getCallingUid()
10914 + " requires " + r.permission);
10915 }
10916 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10917 if (ib != null) {
10918 ret = ib.binder;
10919 }
10920 }
10921 }
10922
10923 return ret;
10924 }
10925
10926 public boolean stopServiceToken(ComponentName className, IBinder token,
10927 int startId) {
10928 synchronized(this) {
10929 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10930 + " " + token + " startId=" + startId);
10931 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010932 if (r != null) {
10933 if (startId >= 0) {
10934 // Asked to only stop if done with all work. Note that
10935 // to avoid leaks, we will take this as dropping all
10936 // start items up to and including this one.
10937 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10938 if (si != null) {
10939 while (r.deliveredStarts.size() > 0) {
10940 if (r.deliveredStarts.remove(0) == si) {
10941 break;
10942 }
10943 }
10944 }
10945
10946 if (r.lastStartId != startId) {
10947 return false;
10948 }
10949
10950 if (r.deliveredStarts.size() > 0) {
10951 Log.w(TAG, "stopServiceToken startId " + startId
10952 + " is last, but have " + r.deliveredStarts.size()
10953 + " remaining args");
10954 }
10955 }
10956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010957 synchronized (r.stats.getBatteryStats()) {
10958 r.stats.stopRunningLocked();
10959 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010960 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010961 }
10962 final long origId = Binder.clearCallingIdentity();
10963 bringDownServiceLocked(r, false);
10964 Binder.restoreCallingIdentity(origId);
10965 return true;
10966 }
10967 }
10968 return false;
10969 }
10970
10971 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010972 int id, Notification notification, boolean removeNotification) {
10973 final long origId = Binder.clearCallingIdentity();
10974 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010975 synchronized(this) {
10976 ServiceRecord r = findServiceLocked(className, token);
10977 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010978 if (id != 0) {
10979 if (notification == null) {
10980 throw new IllegalArgumentException("null notification");
10981 }
10982 if (r.foregroundId != id) {
10983 r.cancelNotification();
10984 r.foregroundId = id;
10985 }
10986 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10987 r.foregroundNoti = notification;
10988 r.isForeground = true;
10989 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010990 if (r.app != null) {
10991 updateServiceForegroundLocked(r.app, true);
10992 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010993 } else {
10994 if (r.isForeground) {
10995 r.isForeground = false;
10996 if (r.app != null) {
10997 updateServiceForegroundLocked(r.app, true);
10998 }
10999 }
11000 if (removeNotification) {
11001 r.cancelNotification();
11002 r.foregroundId = 0;
11003 r.foregroundNoti = null;
11004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011005 }
11006 }
11007 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011008 } finally {
11009 Binder.restoreCallingIdentity(origId);
11010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011011 }
11012
11013 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11014 boolean anyForeground = false;
11015 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11016 if (sr.isForeground) {
11017 anyForeground = true;
11018 break;
11019 }
11020 }
11021 if (anyForeground != proc.foregroundServices) {
11022 proc.foregroundServices = anyForeground;
11023 if (oomAdj) {
11024 updateOomAdjLocked();
11025 }
11026 }
11027 }
11028
11029 public int bindService(IApplicationThread caller, IBinder token,
11030 Intent service, String resolvedType,
11031 IServiceConnection connection, int flags) {
11032 // Refuse possible leaked file descriptors
11033 if (service != null && service.hasFileDescriptors() == true) {
11034 throw new IllegalArgumentException("File descriptors passed in Intent");
11035 }
11036
11037 synchronized(this) {
11038 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11039 + " type=" + resolvedType + " conn=" + connection.asBinder()
11040 + " flags=0x" + Integer.toHexString(flags));
11041 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11042 if (callerApp == null) {
11043 throw new SecurityException(
11044 "Unable to find app for caller " + caller
11045 + " (pid=" + Binder.getCallingPid()
11046 + ") when binding service " + service);
11047 }
11048
11049 HistoryRecord activity = null;
11050 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011051 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011052 if (aindex < 0) {
11053 Log.w(TAG, "Binding with unknown activity: " + token);
11054 return 0;
11055 }
11056 activity = (HistoryRecord)mHistory.get(aindex);
11057 }
11058
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011059 int clientLabel = 0;
11060 PendingIntent clientIntent = null;
11061
11062 if (callerApp.info.uid == Process.SYSTEM_UID) {
11063 // Hacky kind of thing -- allow system stuff to tell us
11064 // what they are, so we can report this elsewhere for
11065 // others to know why certain services are running.
11066 try {
11067 clientIntent = (PendingIntent)service.getParcelableExtra(
11068 Intent.EXTRA_CLIENT_INTENT);
11069 } catch (RuntimeException e) {
11070 }
11071 if (clientIntent != null) {
11072 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11073 if (clientLabel != 0) {
11074 // There are no useful extras in the intent, trash them.
11075 // System code calling with this stuff just needs to know
11076 // this will happen.
11077 service = service.cloneFilter();
11078 }
11079 }
11080 }
11081
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011082 ServiceLookupResult res =
11083 retrieveServiceLocked(service, resolvedType,
11084 Binder.getCallingPid(), Binder.getCallingUid());
11085 if (res == null) {
11086 return 0;
11087 }
11088 if (res.record == null) {
11089 return -1;
11090 }
11091 ServiceRecord s = res.record;
11092
11093 final long origId = Binder.clearCallingIdentity();
11094
11095 if (unscheduleServiceRestartLocked(s)) {
11096 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11097 + s.shortName);
11098 }
11099
11100 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11101 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011102 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011103
11104 IBinder binder = connection.asBinder();
11105 s.connections.put(binder, c);
11106 b.connections.add(c);
11107 if (activity != null) {
11108 if (activity.connections == null) {
11109 activity.connections = new HashSet<ConnectionRecord>();
11110 }
11111 activity.connections.add(c);
11112 }
11113 b.client.connections.add(c);
11114 mServiceConnections.put(binder, c);
11115
11116 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11117 s.lastActivity = SystemClock.uptimeMillis();
11118 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11119 return 0;
11120 }
11121 }
11122
11123 if (s.app != null) {
11124 // This could have made the service more important.
11125 updateOomAdjLocked(s.app);
11126 }
11127
11128 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11129 + ": received=" + b.intent.received
11130 + " apps=" + b.intent.apps.size()
11131 + " doRebind=" + b.intent.doRebind);
11132
11133 if (s.app != null && b.intent.received) {
11134 // Service is already running, so we can immediately
11135 // publish the connection.
11136 try {
11137 c.conn.connected(s.name, b.intent.binder);
11138 } catch (Exception e) {
11139 Log.w(TAG, "Failure sending service " + s.shortName
11140 + " to connection " + c.conn.asBinder()
11141 + " (in " + c.binding.client.processName + ")", e);
11142 }
11143
11144 // If this is the first app connected back to this binding,
11145 // and the service had previously asked to be told when
11146 // rebound, then do so.
11147 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11148 requestServiceBindingLocked(s, b.intent, true);
11149 }
11150 } else if (!b.intent.requested) {
11151 requestServiceBindingLocked(s, b.intent, false);
11152 }
11153
11154 Binder.restoreCallingIdentity(origId);
11155 }
11156
11157 return 1;
11158 }
11159
11160 private void removeConnectionLocked(
11161 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11162 IBinder binder = c.conn.asBinder();
11163 AppBindRecord b = c.binding;
11164 ServiceRecord s = b.service;
11165 s.connections.remove(binder);
11166 b.connections.remove(c);
11167 if (c.activity != null && c.activity != skipAct) {
11168 if (c.activity.connections != null) {
11169 c.activity.connections.remove(c);
11170 }
11171 }
11172 if (b.client != skipApp) {
11173 b.client.connections.remove(c);
11174 }
11175 mServiceConnections.remove(binder);
11176
11177 if (b.connections.size() == 0) {
11178 b.intent.apps.remove(b.client);
11179 }
11180
11181 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11182 + ": shouldUnbind=" + b.intent.hasBound);
11183 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11184 && b.intent.hasBound) {
11185 try {
11186 bumpServiceExecutingLocked(s);
11187 updateOomAdjLocked(s.app);
11188 b.intent.hasBound = false;
11189 // Assume the client doesn't want to know about a rebind;
11190 // we will deal with that later if it asks for one.
11191 b.intent.doRebind = false;
11192 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11193 } catch (Exception e) {
11194 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11195 serviceDoneExecutingLocked(s, true);
11196 }
11197 }
11198
11199 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11200 bringDownServiceLocked(s, false);
11201 }
11202 }
11203
11204 public boolean unbindService(IServiceConnection connection) {
11205 synchronized (this) {
11206 IBinder binder = connection.asBinder();
11207 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11208 ConnectionRecord r = mServiceConnections.get(binder);
11209 if (r == null) {
11210 Log.w(TAG, "Unbind failed: could not find connection for "
11211 + connection.asBinder());
11212 return false;
11213 }
11214
11215 final long origId = Binder.clearCallingIdentity();
11216
11217 removeConnectionLocked(r, null, null);
11218
11219 if (r.binding.service.app != null) {
11220 // This could have made the service less important.
11221 updateOomAdjLocked(r.binding.service.app);
11222 }
11223
11224 Binder.restoreCallingIdentity(origId);
11225 }
11226
11227 return true;
11228 }
11229
11230 public void publishService(IBinder token, Intent intent, IBinder service) {
11231 // Refuse possible leaked file descriptors
11232 if (intent != null && intent.hasFileDescriptors() == true) {
11233 throw new IllegalArgumentException("File descriptors passed in Intent");
11234 }
11235
11236 synchronized(this) {
11237 if (!(token instanceof ServiceRecord)) {
11238 throw new IllegalArgumentException("Invalid service token");
11239 }
11240 ServiceRecord r = (ServiceRecord)token;
11241
11242 final long origId = Binder.clearCallingIdentity();
11243
11244 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11245 + " " + intent + ": " + service);
11246 if (r != null) {
11247 Intent.FilterComparison filter
11248 = new Intent.FilterComparison(intent);
11249 IntentBindRecord b = r.bindings.get(filter);
11250 if (b != null && !b.received) {
11251 b.binder = service;
11252 b.requested = true;
11253 b.received = true;
11254 if (r.connections.size() > 0) {
11255 Iterator<ConnectionRecord> it
11256 = r.connections.values().iterator();
11257 while (it.hasNext()) {
11258 ConnectionRecord c = it.next();
11259 if (!filter.equals(c.binding.intent.intent)) {
11260 if (DEBUG_SERVICE) Log.v(
11261 TAG, "Not publishing to: " + c);
11262 if (DEBUG_SERVICE) Log.v(
11263 TAG, "Bound intent: " + c.binding.intent.intent);
11264 if (DEBUG_SERVICE) Log.v(
11265 TAG, "Published intent: " + intent);
11266 continue;
11267 }
11268 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11269 try {
11270 c.conn.connected(r.name, service);
11271 } catch (Exception e) {
11272 Log.w(TAG, "Failure sending service " + r.name +
11273 " to connection " + c.conn.asBinder() +
11274 " (in " + c.binding.client.processName + ")", e);
11275 }
11276 }
11277 }
11278 }
11279
11280 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11281
11282 Binder.restoreCallingIdentity(origId);
11283 }
11284 }
11285 }
11286
11287 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11288 // Refuse possible leaked file descriptors
11289 if (intent != null && intent.hasFileDescriptors() == true) {
11290 throw new IllegalArgumentException("File descriptors passed in Intent");
11291 }
11292
11293 synchronized(this) {
11294 if (!(token instanceof ServiceRecord)) {
11295 throw new IllegalArgumentException("Invalid service token");
11296 }
11297 ServiceRecord r = (ServiceRecord)token;
11298
11299 final long origId = Binder.clearCallingIdentity();
11300
11301 if (r != null) {
11302 Intent.FilterComparison filter
11303 = new Intent.FilterComparison(intent);
11304 IntentBindRecord b = r.bindings.get(filter);
11305 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11306 + " at " + b + ": apps="
11307 + (b != null ? b.apps.size() : 0));
11308 if (b != null) {
11309 if (b.apps.size() > 0) {
11310 // Applications have already bound since the last
11311 // unbind, so just rebind right here.
11312 requestServiceBindingLocked(r, b, true);
11313 } else {
11314 // Note to tell the service the next time there is
11315 // a new client.
11316 b.doRebind = true;
11317 }
11318 }
11319
11320 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11321
11322 Binder.restoreCallingIdentity(origId);
11323 }
11324 }
11325 }
11326
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011327 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011328 synchronized(this) {
11329 if (!(token instanceof ServiceRecord)) {
11330 throw new IllegalArgumentException("Invalid service token");
11331 }
11332 ServiceRecord r = (ServiceRecord)token;
11333 boolean inStopping = mStoppingServices.contains(token);
11334 if (r != null) {
11335 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11336 + ": nesting=" + r.executeNesting
11337 + ", inStopping=" + inStopping);
11338 if (r != token) {
11339 Log.w(TAG, "Done executing service " + r.name
11340 + " with incorrect token: given " + token
11341 + ", expected " + r);
11342 return;
11343 }
11344
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011345 if (type == 1) {
11346 // This is a call from a service start... take care of
11347 // book-keeping.
11348 r.callStart = true;
11349 switch (res) {
11350 case Service.START_STICKY_COMPATIBILITY:
11351 case Service.START_STICKY: {
11352 // We are done with the associated start arguments.
11353 r.findDeliveredStart(startId, true);
11354 // Don't stop if killed.
11355 r.stopIfKilled = false;
11356 break;
11357 }
11358 case Service.START_NOT_STICKY: {
11359 // We are done with the associated start arguments.
11360 r.findDeliveredStart(startId, true);
11361 if (r.lastStartId == startId) {
11362 // There is no more work, and this service
11363 // doesn't want to hang around if killed.
11364 r.stopIfKilled = true;
11365 }
11366 break;
11367 }
11368 case Service.START_REDELIVER_INTENT: {
11369 // We'll keep this item until they explicitly
11370 // call stop for it, but keep track of the fact
11371 // that it was delivered.
11372 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11373 if (si != null) {
11374 si.deliveryCount = 0;
11375 si.doneExecutingCount++;
11376 // Don't stop if killed.
11377 r.stopIfKilled = true;
11378 }
11379 break;
11380 }
11381 default:
11382 throw new IllegalArgumentException(
11383 "Unknown service start result: " + res);
11384 }
11385 if (res == Service.START_STICKY_COMPATIBILITY) {
11386 r.callStart = false;
11387 }
11388 }
11389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011390 final long origId = Binder.clearCallingIdentity();
11391 serviceDoneExecutingLocked(r, inStopping);
11392 Binder.restoreCallingIdentity(origId);
11393 } else {
11394 Log.w(TAG, "Done executing unknown service " + r.name
11395 + " with token " + token);
11396 }
11397 }
11398 }
11399
11400 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11401 r.executeNesting--;
11402 if (r.executeNesting <= 0 && r.app != null) {
11403 r.app.executingServices.remove(r);
11404 if (r.app.executingServices.size() == 0) {
11405 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11406 }
11407 if (inStopping) {
11408 mStoppingServices.remove(r);
11409 }
11410 updateOomAdjLocked(r.app);
11411 }
11412 }
11413
11414 void serviceTimeout(ProcessRecord proc) {
11415 synchronized(this) {
11416 if (proc.executingServices.size() == 0 || proc.thread == null) {
11417 return;
11418 }
11419 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11420 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11421 ServiceRecord timeout = null;
11422 long nextTime = 0;
11423 while (it.hasNext()) {
11424 ServiceRecord sr = it.next();
11425 if (sr.executingStart < maxTime) {
11426 timeout = sr;
11427 break;
11428 }
11429 if (sr.executingStart > nextTime) {
11430 nextTime = sr.executingStart;
11431 }
11432 }
11433 if (timeout != null && mLRUProcesses.contains(proc)) {
11434 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011435 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011436 + timeout.name);
11437 } else {
11438 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11439 msg.obj = proc;
11440 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11441 }
11442 }
11443 }
11444
11445 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011446 // BACKUP AND RESTORE
11447 // =========================================================
11448
11449 // Cause the target app to be launched if necessary and its backup agent
11450 // instantiated. The backup agent will invoke backupAgentCreated() on the
11451 // activity manager to announce its creation.
11452 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11453 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11454 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11455
11456 synchronized(this) {
11457 // !!! TODO: currently no check here that we're already bound
11458 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11459 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11460 synchronized (stats) {
11461 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11462 }
11463
11464 BackupRecord r = new BackupRecord(ss, app, backupMode);
11465 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11466 // startProcessLocked() returns existing proc's record if it's already running
11467 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011468 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011469 if (proc == null) {
11470 Log.e(TAG, "Unable to start backup agent process " + r);
11471 return false;
11472 }
11473
11474 r.app = proc;
11475 mBackupTarget = r;
11476 mBackupAppName = app.packageName;
11477
Christopher Tate6fa95972009-06-05 18:43:55 -070011478 // Try not to kill the process during backup
11479 updateOomAdjLocked(proc);
11480
Christopher Tate181fafa2009-05-14 11:12:14 -070011481 // If the process is already attached, schedule the creation of the backup agent now.
11482 // If it is not yet live, this will be done when it attaches to the framework.
11483 if (proc.thread != null) {
11484 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11485 try {
11486 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11487 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011488 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011489 }
11490 } else {
11491 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11492 }
11493 // Invariants: at this point, the target app process exists and the application
11494 // is either already running or in the process of coming up. mBackupTarget and
11495 // mBackupAppName describe the app, so that when it binds back to the AM we
11496 // know that it's scheduled for a backup-agent operation.
11497 }
11498
11499 return true;
11500 }
11501
11502 // A backup agent has just come up
11503 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11504 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11505 + " = " + agent);
11506
11507 synchronized(this) {
11508 if (!agentPackageName.equals(mBackupAppName)) {
11509 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11510 return;
11511 }
11512
Christopher Tate043dadc2009-06-02 16:11:00 -070011513 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011514 try {
11515 IBackupManager bm = IBackupManager.Stub.asInterface(
11516 ServiceManager.getService(Context.BACKUP_SERVICE));
11517 bm.agentConnected(agentPackageName, agent);
11518 } catch (RemoteException e) {
11519 // can't happen; the backup manager service is local
11520 } catch (Exception e) {
11521 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11522 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011523 } finally {
11524 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011525 }
11526 }
11527 }
11528
11529 // done with this agent
11530 public void unbindBackupAgent(ApplicationInfo appInfo) {
11531 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011532 if (appInfo == null) {
11533 Log.w(TAG, "unbind backup agent for null app");
11534 return;
11535 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011536
11537 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011538 if (mBackupAppName == null) {
11539 Log.w(TAG, "Unbinding backup agent with no active backup");
11540 return;
11541 }
11542
Christopher Tate181fafa2009-05-14 11:12:14 -070011543 if (!mBackupAppName.equals(appInfo.packageName)) {
11544 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11545 return;
11546 }
11547
Christopher Tate6fa95972009-06-05 18:43:55 -070011548 ProcessRecord proc = mBackupTarget.app;
11549 mBackupTarget = null;
11550 mBackupAppName = null;
11551
11552 // Not backing this app up any more; reset its OOM adjustment
11553 updateOomAdjLocked(proc);
11554
Christopher Tatec7b31e32009-06-10 15:49:30 -070011555 // If the app crashed during backup, 'thread' will be null here
11556 if (proc.thread != null) {
11557 try {
11558 proc.thread.scheduleDestroyBackupAgent(appInfo);
11559 } catch (Exception e) {
11560 Log.e(TAG, "Exception when unbinding backup agent:");
11561 e.printStackTrace();
11562 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011563 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011564 }
11565 }
11566 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011567 // BROADCASTS
11568 // =========================================================
11569
11570 private final List getStickies(String action, IntentFilter filter,
11571 List cur) {
11572 final ContentResolver resolver = mContext.getContentResolver();
11573 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11574 if (list == null) {
11575 return cur;
11576 }
11577 int N = list.size();
11578 for (int i=0; i<N; i++) {
11579 Intent intent = list.get(i);
11580 if (filter.match(resolver, intent, true, TAG) >= 0) {
11581 if (cur == null) {
11582 cur = new ArrayList<Intent>();
11583 }
11584 cur.add(intent);
11585 }
11586 }
11587 return cur;
11588 }
11589
11590 private final void scheduleBroadcastsLocked() {
11591 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11592 + mBroadcastsScheduled);
11593
11594 if (mBroadcastsScheduled) {
11595 return;
11596 }
11597 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11598 mBroadcastsScheduled = true;
11599 }
11600
11601 public Intent registerReceiver(IApplicationThread caller,
11602 IIntentReceiver receiver, IntentFilter filter, String permission) {
11603 synchronized(this) {
11604 ProcessRecord callerApp = null;
11605 if (caller != null) {
11606 callerApp = getRecordForAppLocked(caller);
11607 if (callerApp == null) {
11608 throw new SecurityException(
11609 "Unable to find app for caller " + caller
11610 + " (pid=" + Binder.getCallingPid()
11611 + ") when registering receiver " + receiver);
11612 }
11613 }
11614
11615 List allSticky = null;
11616
11617 // Look for any matching sticky broadcasts...
11618 Iterator actions = filter.actionsIterator();
11619 if (actions != null) {
11620 while (actions.hasNext()) {
11621 String action = (String)actions.next();
11622 allSticky = getStickies(action, filter, allSticky);
11623 }
11624 } else {
11625 allSticky = getStickies(null, filter, allSticky);
11626 }
11627
11628 // The first sticky in the list is returned directly back to
11629 // the client.
11630 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11631
11632 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11633 + ": " + sticky);
11634
11635 if (receiver == null) {
11636 return sticky;
11637 }
11638
11639 ReceiverList rl
11640 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11641 if (rl == null) {
11642 rl = new ReceiverList(this, callerApp,
11643 Binder.getCallingPid(),
11644 Binder.getCallingUid(), receiver);
11645 if (rl.app != null) {
11646 rl.app.receivers.add(rl);
11647 } else {
11648 try {
11649 receiver.asBinder().linkToDeath(rl, 0);
11650 } catch (RemoteException e) {
11651 return sticky;
11652 }
11653 rl.linkedToDeath = true;
11654 }
11655 mRegisteredReceivers.put(receiver.asBinder(), rl);
11656 }
11657 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11658 rl.add(bf);
11659 if (!bf.debugCheck()) {
11660 Log.w(TAG, "==> For Dynamic broadast");
11661 }
11662 mReceiverResolver.addFilter(bf);
11663
11664 // Enqueue broadcasts for all existing stickies that match
11665 // this filter.
11666 if (allSticky != null) {
11667 ArrayList receivers = new ArrayList();
11668 receivers.add(bf);
11669
11670 int N = allSticky.size();
11671 for (int i=0; i<N; i++) {
11672 Intent intent = (Intent)allSticky.get(i);
11673 BroadcastRecord r = new BroadcastRecord(intent, null,
11674 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011675 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011676 if (mParallelBroadcasts.size() == 0) {
11677 scheduleBroadcastsLocked();
11678 }
11679 mParallelBroadcasts.add(r);
11680 }
11681 }
11682
11683 return sticky;
11684 }
11685 }
11686
11687 public void unregisterReceiver(IIntentReceiver receiver) {
11688 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11689
11690 boolean doNext = false;
11691
11692 synchronized(this) {
11693 ReceiverList rl
11694 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11695 if (rl != null) {
11696 if (rl.curBroadcast != null) {
11697 BroadcastRecord r = rl.curBroadcast;
11698 doNext = finishReceiverLocked(
11699 receiver.asBinder(), r.resultCode, r.resultData,
11700 r.resultExtras, r.resultAbort, true);
11701 }
11702
11703 if (rl.app != null) {
11704 rl.app.receivers.remove(rl);
11705 }
11706 removeReceiverLocked(rl);
11707 if (rl.linkedToDeath) {
11708 rl.linkedToDeath = false;
11709 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11710 }
11711 }
11712 }
11713
11714 if (!doNext) {
11715 return;
11716 }
11717
11718 final long origId = Binder.clearCallingIdentity();
11719 processNextBroadcast(false);
11720 trimApplications();
11721 Binder.restoreCallingIdentity(origId);
11722 }
11723
11724 void removeReceiverLocked(ReceiverList rl) {
11725 mRegisteredReceivers.remove(rl.receiver.asBinder());
11726 int N = rl.size();
11727 for (int i=0; i<N; i++) {
11728 mReceiverResolver.removeFilter(rl.get(i));
11729 }
11730 }
11731
11732 private final int broadcastIntentLocked(ProcessRecord callerApp,
11733 String callerPackage, Intent intent, String resolvedType,
11734 IIntentReceiver resultTo, int resultCode, String resultData,
11735 Bundle map, String requiredPermission,
11736 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11737 intent = new Intent(intent);
11738
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011739 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011740 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11741 + " ordered=" + ordered);
11742 if ((resultTo != null) && !ordered) {
11743 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11744 }
11745
11746 // Handle special intents: if this broadcast is from the package
11747 // manager about a package being removed, we need to remove all of
11748 // its activities from the history stack.
11749 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11750 intent.getAction());
11751 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11752 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11753 || uidRemoved) {
11754 if (checkComponentPermission(
11755 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11756 callingPid, callingUid, -1)
11757 == PackageManager.PERMISSION_GRANTED) {
11758 if (uidRemoved) {
11759 final Bundle intentExtras = intent.getExtras();
11760 final int uid = intentExtras != null
11761 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11762 if (uid >= 0) {
11763 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11764 synchronized (bs) {
11765 bs.removeUidStatsLocked(uid);
11766 }
11767 }
11768 } else {
11769 Uri data = intent.getData();
11770 String ssp;
11771 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11772 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11773 uninstallPackageLocked(ssp,
11774 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011775 AttributeCache ac = AttributeCache.instance();
11776 if (ac != null) {
11777 ac.removePackage(ssp);
11778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011779 }
11780 }
11781 }
11782 } else {
11783 String msg = "Permission Denial: " + intent.getAction()
11784 + " broadcast from " + callerPackage + " (pid=" + callingPid
11785 + ", uid=" + callingUid + ")"
11786 + " requires "
11787 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11788 Log.w(TAG, msg);
11789 throw new SecurityException(msg);
11790 }
11791 }
11792
11793 /*
11794 * If this is the time zone changed action, queue up a message that will reset the timezone
11795 * of all currently running processes. This message will get queued up before the broadcast
11796 * happens.
11797 */
11798 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11799 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11800 }
11801
Dianne Hackborn854060af2009-07-09 18:14:31 -070011802 /*
11803 * Prevent non-system code (defined here to be non-persistent
11804 * processes) from sending protected broadcasts.
11805 */
11806 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11807 || callingUid == Process.SHELL_UID || callingUid == 0) {
11808 // Always okay.
11809 } else if (callerApp == null || !callerApp.persistent) {
11810 try {
11811 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11812 intent.getAction())) {
11813 String msg = "Permission Denial: not allowed to send broadcast "
11814 + intent.getAction() + " from pid="
11815 + callingPid + ", uid=" + callingUid;
11816 Log.w(TAG, msg);
11817 throw new SecurityException(msg);
11818 }
11819 } catch (RemoteException e) {
11820 Log.w(TAG, "Remote exception", e);
11821 return BROADCAST_SUCCESS;
11822 }
11823 }
11824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011825 // Add to the sticky list if requested.
11826 if (sticky) {
11827 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11828 callingPid, callingUid)
11829 != PackageManager.PERMISSION_GRANTED) {
11830 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11831 + callingPid + ", uid=" + callingUid
11832 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11833 Log.w(TAG, msg);
11834 throw new SecurityException(msg);
11835 }
11836 if (requiredPermission != null) {
11837 Log.w(TAG, "Can't broadcast sticky intent " + intent
11838 + " and enforce permission " + requiredPermission);
11839 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11840 }
11841 if (intent.getComponent() != null) {
11842 throw new SecurityException(
11843 "Sticky broadcasts can't target a specific component");
11844 }
11845 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11846 if (list == null) {
11847 list = new ArrayList<Intent>();
11848 mStickyBroadcasts.put(intent.getAction(), list);
11849 }
11850 int N = list.size();
11851 int i;
11852 for (i=0; i<N; i++) {
11853 if (intent.filterEquals(list.get(i))) {
11854 // This sticky already exists, replace it.
11855 list.set(i, new Intent(intent));
11856 break;
11857 }
11858 }
11859 if (i >= N) {
11860 list.add(new Intent(intent));
11861 }
11862 }
11863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011864 // Figure out who all will receive this broadcast.
11865 List receivers = null;
11866 List<BroadcastFilter> registeredReceivers = null;
11867 try {
11868 if (intent.getComponent() != null) {
11869 // Broadcast is going to one specific receiver class...
11870 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011871 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011872 if (ai != null) {
11873 receivers = new ArrayList();
11874 ResolveInfo ri = new ResolveInfo();
11875 ri.activityInfo = ai;
11876 receivers.add(ri);
11877 }
11878 } else {
11879 // Need to resolve the intent to interested receivers...
11880 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11881 == 0) {
11882 receivers =
11883 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011884 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011885 }
Mihai Preda074edef2009-05-18 17:13:31 +020011886 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011887 }
11888 } catch (RemoteException ex) {
11889 // pm is in same process, this will never happen.
11890 }
11891
11892 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11893 if (!ordered && NR > 0) {
11894 // If we are not serializing this broadcast, then send the
11895 // registered receivers separately so they don't wait for the
11896 // components to be launched.
11897 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11898 callerPackage, callingPid, callingUid, requiredPermission,
11899 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011900 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011901 if (DEBUG_BROADCAST) Log.v(
11902 TAG, "Enqueueing parallel broadcast " + r
11903 + ": prev had " + mParallelBroadcasts.size());
11904 mParallelBroadcasts.add(r);
11905 scheduleBroadcastsLocked();
11906 registeredReceivers = null;
11907 NR = 0;
11908 }
11909
11910 // Merge into one list.
11911 int ir = 0;
11912 if (receivers != null) {
11913 // A special case for PACKAGE_ADDED: do not allow the package
11914 // being added to see this broadcast. This prevents them from
11915 // using this as a back door to get run as soon as they are
11916 // installed. Maybe in the future we want to have a special install
11917 // broadcast or such for apps, but we'd like to deliberately make
11918 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011919 boolean skip = false;
11920 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011921 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011922 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11923 skip = true;
11924 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11925 skip = true;
11926 }
11927 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011928 ? intent.getData().getSchemeSpecificPart()
11929 : null;
11930 if (skipPackage != null && receivers != null) {
11931 int NT = receivers.size();
11932 for (int it=0; it<NT; it++) {
11933 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11934 if (curt.activityInfo.packageName.equals(skipPackage)) {
11935 receivers.remove(it);
11936 it--;
11937 NT--;
11938 }
11939 }
11940 }
11941
11942 int NT = receivers != null ? receivers.size() : 0;
11943 int it = 0;
11944 ResolveInfo curt = null;
11945 BroadcastFilter curr = null;
11946 while (it < NT && ir < NR) {
11947 if (curt == null) {
11948 curt = (ResolveInfo)receivers.get(it);
11949 }
11950 if (curr == null) {
11951 curr = registeredReceivers.get(ir);
11952 }
11953 if (curr.getPriority() >= curt.priority) {
11954 // Insert this broadcast record into the final list.
11955 receivers.add(it, curr);
11956 ir++;
11957 curr = null;
11958 it++;
11959 NT++;
11960 } else {
11961 // Skip to the next ResolveInfo in the final list.
11962 it++;
11963 curt = null;
11964 }
11965 }
11966 }
11967 while (ir < NR) {
11968 if (receivers == null) {
11969 receivers = new ArrayList();
11970 }
11971 receivers.add(registeredReceivers.get(ir));
11972 ir++;
11973 }
11974
11975 if ((receivers != null && receivers.size() > 0)
11976 || resultTo != null) {
11977 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11978 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011979 receivers, resultTo, resultCode, resultData, map, ordered,
11980 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011981 if (DEBUG_BROADCAST) Log.v(
11982 TAG, "Enqueueing ordered broadcast " + r
11983 + ": prev had " + mOrderedBroadcasts.size());
11984 if (DEBUG_BROADCAST) {
11985 int seq = r.intent.getIntExtra("seq", -1);
11986 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11987 }
11988 mOrderedBroadcasts.add(r);
11989 scheduleBroadcastsLocked();
11990 }
11991
11992 return BROADCAST_SUCCESS;
11993 }
11994
11995 public final int broadcastIntent(IApplicationThread caller,
11996 Intent intent, String resolvedType, IIntentReceiver resultTo,
11997 int resultCode, String resultData, Bundle map,
11998 String requiredPermission, boolean serialized, boolean sticky) {
11999 // Refuse possible leaked file descriptors
12000 if (intent != null && intent.hasFileDescriptors() == true) {
12001 throw new IllegalArgumentException("File descriptors passed in Intent");
12002 }
12003
12004 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012005 int flags = intent.getFlags();
12006
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012007 if (!mSystemReady) {
12008 // if the caller really truly claims to know what they're doing, go
12009 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012010 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12011 intent = new Intent(intent);
12012 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12013 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12014 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12015 + " before boot completion");
12016 throw new IllegalStateException("Cannot broadcast before boot completed");
12017 }
12018 }
12019
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012020 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12021 throw new IllegalArgumentException(
12022 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12023 }
12024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012025 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12026 final int callingPid = Binder.getCallingPid();
12027 final int callingUid = Binder.getCallingUid();
12028 final long origId = Binder.clearCallingIdentity();
12029 int res = broadcastIntentLocked(callerApp,
12030 callerApp != null ? callerApp.info.packageName : null,
12031 intent, resolvedType, resultTo,
12032 resultCode, resultData, map, requiredPermission, serialized,
12033 sticky, callingPid, callingUid);
12034 Binder.restoreCallingIdentity(origId);
12035 return res;
12036 }
12037 }
12038
12039 int broadcastIntentInPackage(String packageName, int uid,
12040 Intent intent, String resolvedType, IIntentReceiver resultTo,
12041 int resultCode, String resultData, Bundle map,
12042 String requiredPermission, boolean serialized, boolean sticky) {
12043 synchronized(this) {
12044 final long origId = Binder.clearCallingIdentity();
12045 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12046 resultTo, resultCode, resultData, map, requiredPermission,
12047 serialized, sticky, -1, uid);
12048 Binder.restoreCallingIdentity(origId);
12049 return res;
12050 }
12051 }
12052
12053 public final void unbroadcastIntent(IApplicationThread caller,
12054 Intent intent) {
12055 // Refuse possible leaked file descriptors
12056 if (intent != null && intent.hasFileDescriptors() == true) {
12057 throw new IllegalArgumentException("File descriptors passed in Intent");
12058 }
12059
12060 synchronized(this) {
12061 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12062 != PackageManager.PERMISSION_GRANTED) {
12063 String msg = "Permission Denial: unbroadcastIntent() from pid="
12064 + Binder.getCallingPid()
12065 + ", uid=" + Binder.getCallingUid()
12066 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12067 Log.w(TAG, msg);
12068 throw new SecurityException(msg);
12069 }
12070 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12071 if (list != null) {
12072 int N = list.size();
12073 int i;
12074 for (i=0; i<N; i++) {
12075 if (intent.filterEquals(list.get(i))) {
12076 list.remove(i);
12077 break;
12078 }
12079 }
12080 }
12081 }
12082 }
12083
12084 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12085 String resultData, Bundle resultExtras, boolean resultAbort,
12086 boolean explicit) {
12087 if (mOrderedBroadcasts.size() == 0) {
12088 if (explicit) {
12089 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12090 }
12091 return false;
12092 }
12093 BroadcastRecord r = mOrderedBroadcasts.get(0);
12094 if (r.receiver == null) {
12095 if (explicit) {
12096 Log.w(TAG, "finishReceiver called but none active");
12097 }
12098 return false;
12099 }
12100 if (r.receiver != receiver) {
12101 Log.w(TAG, "finishReceiver called but active receiver is different");
12102 return false;
12103 }
12104 int state = r.state;
12105 r.state = r.IDLE;
12106 if (state == r.IDLE) {
12107 if (explicit) {
12108 Log.w(TAG, "finishReceiver called but state is IDLE");
12109 }
12110 }
12111 r.receiver = null;
12112 r.intent.setComponent(null);
12113 if (r.curApp != null) {
12114 r.curApp.curReceiver = null;
12115 }
12116 if (r.curFilter != null) {
12117 r.curFilter.receiverList.curBroadcast = null;
12118 }
12119 r.curFilter = null;
12120 r.curApp = null;
12121 r.curComponent = null;
12122 r.curReceiver = null;
12123 mPendingBroadcast = null;
12124
12125 r.resultCode = resultCode;
12126 r.resultData = resultData;
12127 r.resultExtras = resultExtras;
12128 r.resultAbort = resultAbort;
12129
12130 // We will process the next receiver right now if this is finishing
12131 // an app receiver (which is always asynchronous) or after we have
12132 // come back from calling a receiver.
12133 return state == BroadcastRecord.APP_RECEIVE
12134 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12135 }
12136
12137 public void finishReceiver(IBinder who, int resultCode, String resultData,
12138 Bundle resultExtras, boolean resultAbort) {
12139 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12140
12141 // Refuse possible leaked file descriptors
12142 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12143 throw new IllegalArgumentException("File descriptors passed in Bundle");
12144 }
12145
12146 boolean doNext;
12147
12148 final long origId = Binder.clearCallingIdentity();
12149
12150 synchronized(this) {
12151 doNext = finishReceiverLocked(
12152 who, resultCode, resultData, resultExtras, resultAbort, true);
12153 }
12154
12155 if (doNext) {
12156 processNextBroadcast(false);
12157 }
12158 trimApplications();
12159
12160 Binder.restoreCallingIdentity(origId);
12161 }
12162
12163 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12164 if (r.nextReceiver > 0) {
12165 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12166 if (curReceiver instanceof BroadcastFilter) {
12167 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012168 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012169 System.identityHashCode(r),
12170 r.intent.getAction(),
12171 r.nextReceiver - 1,
12172 System.identityHashCode(bf));
12173 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012174 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012175 System.identityHashCode(r),
12176 r.intent.getAction(),
12177 r.nextReceiver - 1,
12178 ((ResolveInfo)curReceiver).toString());
12179 }
12180 } else {
12181 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12182 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012183 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012184 System.identityHashCode(r),
12185 r.intent.getAction(),
12186 r.nextReceiver,
12187 "NONE");
12188 }
12189 }
12190
12191 private final void broadcastTimeout() {
12192 synchronized (this) {
12193 if (mOrderedBroadcasts.size() == 0) {
12194 return;
12195 }
12196 long now = SystemClock.uptimeMillis();
12197 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012198 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012199 if (DEBUG_BROADCAST) Log.v(TAG,
12200 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012201 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012202 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012203 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012204 return;
12205 }
12206
12207 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012208 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012209 r.anrCount++;
12210
12211 // Current receiver has passed its expiration date.
12212 if (r.nextReceiver <= 0) {
12213 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12214 return;
12215 }
12216
12217 ProcessRecord app = null;
12218
12219 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12220 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12221 logBroadcastReceiverDiscard(r);
12222 if (curReceiver instanceof BroadcastFilter) {
12223 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12224 if (bf.receiverList.pid != 0
12225 && bf.receiverList.pid != MY_PID) {
12226 synchronized (this.mPidsSelfLocked) {
12227 app = this.mPidsSelfLocked.get(
12228 bf.receiverList.pid);
12229 }
12230 }
12231 } else {
12232 app = r.curApp;
12233 }
12234
12235 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012236 appNotRespondingLocked(app, null, null,
12237 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012238 }
12239
12240 if (mPendingBroadcast == r) {
12241 mPendingBroadcast = null;
12242 }
12243
12244 // Move on to the next receiver.
12245 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12246 r.resultExtras, r.resultAbort, true);
12247 scheduleBroadcastsLocked();
12248 }
12249 }
12250
12251 private final void processCurBroadcastLocked(BroadcastRecord r,
12252 ProcessRecord app) throws RemoteException {
12253 if (app.thread == null) {
12254 throw new RemoteException();
12255 }
12256 r.receiver = app.thread.asBinder();
12257 r.curApp = app;
12258 app.curReceiver = r;
12259 updateLRUListLocked(app, true);
12260
12261 // Tell the application to launch this receiver.
12262 r.intent.setComponent(r.curComponent);
12263
12264 boolean started = false;
12265 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012266 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012267 "Delivering to component " + r.curComponent
12268 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012269 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012270 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12271 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12272 started = true;
12273 } finally {
12274 if (!started) {
12275 r.receiver = null;
12276 r.curApp = null;
12277 app.curReceiver = null;
12278 }
12279 }
12280
12281 }
12282
12283 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012284 Intent intent, int resultCode, String data, Bundle extras,
12285 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012286 if (app != null && app.thread != null) {
12287 // If we have an app thread, do the call through that so it is
12288 // correctly ordered with other one-way calls.
12289 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012290 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012291 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012292 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012293 }
12294 }
12295
12296 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12297 BroadcastFilter filter, boolean ordered) {
12298 boolean skip = false;
12299 if (filter.requiredPermission != null) {
12300 int perm = checkComponentPermission(filter.requiredPermission,
12301 r.callingPid, r.callingUid, -1);
12302 if (perm != PackageManager.PERMISSION_GRANTED) {
12303 Log.w(TAG, "Permission Denial: broadcasting "
12304 + r.intent.toString()
12305 + " from " + r.callerPackage + " (pid="
12306 + r.callingPid + ", uid=" + r.callingUid + ")"
12307 + " requires " + filter.requiredPermission
12308 + " due to registered receiver " + filter);
12309 skip = true;
12310 }
12311 }
12312 if (r.requiredPermission != null) {
12313 int perm = checkComponentPermission(r.requiredPermission,
12314 filter.receiverList.pid, filter.receiverList.uid, -1);
12315 if (perm != PackageManager.PERMISSION_GRANTED) {
12316 Log.w(TAG, "Permission Denial: receiving "
12317 + r.intent.toString()
12318 + " to " + filter.receiverList.app
12319 + " (pid=" + filter.receiverList.pid
12320 + ", uid=" + filter.receiverList.uid + ")"
12321 + " requires " + r.requiredPermission
12322 + " due to sender " + r.callerPackage
12323 + " (uid " + r.callingUid + ")");
12324 skip = true;
12325 }
12326 }
12327
12328 if (!skip) {
12329 // If this is not being sent as an ordered broadcast, then we
12330 // don't want to touch the fields that keep track of the current
12331 // state of ordered broadcasts.
12332 if (ordered) {
12333 r.receiver = filter.receiverList.receiver.asBinder();
12334 r.curFilter = filter;
12335 filter.receiverList.curBroadcast = r;
12336 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012337 if (filter.receiverList.app != null) {
12338 // Bump hosting application to no longer be in background
12339 // scheduling class. Note that we can't do that if there
12340 // isn't an app... but we can only be in that case for
12341 // things that directly call the IActivityManager API, which
12342 // are already core system stuff so don't matter for this.
12343 r.curApp = filter.receiverList.app;
12344 filter.receiverList.app.curReceiver = r;
12345 updateOomAdjLocked();
12346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012347 }
12348 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012349 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012350 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012351 Log.i(TAG, "Delivering to " + filter.receiverList.app
12352 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012353 }
12354 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12355 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012356 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012357 if (ordered) {
12358 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12359 }
12360 } catch (RemoteException e) {
12361 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12362 if (ordered) {
12363 r.receiver = null;
12364 r.curFilter = null;
12365 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012366 if (filter.receiverList.app != null) {
12367 filter.receiverList.app.curReceiver = null;
12368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012369 }
12370 }
12371 }
12372 }
12373
Dianne Hackborn12527f92009-11-11 17:39:50 -080012374 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12375 if (r.callingUid < 0) {
12376 // This was from a registerReceiver() call; ignore it.
12377 return;
12378 }
12379 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12380 MAX_BROADCAST_HISTORY-1);
12381 r.finishTime = SystemClock.uptimeMillis();
12382 mBroadcastHistory[0] = r;
12383 }
12384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012385 private final void processNextBroadcast(boolean fromMsg) {
12386 synchronized(this) {
12387 BroadcastRecord r;
12388
12389 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12390 + mParallelBroadcasts.size() + " broadcasts, "
12391 + mOrderedBroadcasts.size() + " serialized broadcasts");
12392
12393 updateCpuStats();
12394
12395 if (fromMsg) {
12396 mBroadcastsScheduled = false;
12397 }
12398
12399 // First, deliver any non-serialized broadcasts right away.
12400 while (mParallelBroadcasts.size() > 0) {
12401 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012402 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012403 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012404 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12405 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012406 for (int i=0; i<N; i++) {
12407 Object target = r.receivers.get(i);
12408 if (DEBUG_BROADCAST) Log.v(TAG,
12409 "Delivering non-serialized to registered "
12410 + target + ": " + r);
12411 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12412 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012413 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012414 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12415 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012416 }
12417
12418 // Now take care of the next serialized one...
12419
12420 // If we are waiting for a process to come up to handle the next
12421 // broadcast, then do nothing at this point. Just in case, we
12422 // check that the process we're waiting for still exists.
12423 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012424 if (DEBUG_BROADCAST_LIGHT) {
12425 Log.v(TAG, "processNextBroadcast: waiting for "
12426 + mPendingBroadcast.curApp);
12427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012428
12429 boolean isDead;
12430 synchronized (mPidsSelfLocked) {
12431 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12432 }
12433 if (!isDead) {
12434 // It's still alive, so keep waiting
12435 return;
12436 } else {
12437 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12438 + " died before responding to broadcast");
12439 mPendingBroadcast = null;
12440 }
12441 }
12442
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012443 boolean looped = false;
12444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012445 do {
12446 if (mOrderedBroadcasts.size() == 0) {
12447 // No more broadcasts pending, so all done!
12448 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012449 if (looped) {
12450 // If we had finished the last ordered broadcast, then
12451 // make sure all processes have correct oom and sched
12452 // adjustments.
12453 updateOomAdjLocked();
12454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012455 return;
12456 }
12457 r = mOrderedBroadcasts.get(0);
12458 boolean forceReceive = false;
12459
12460 // Ensure that even if something goes awry with the timeout
12461 // detection, we catch "hung" broadcasts here, discard them,
12462 // and continue to make progress.
12463 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12464 long now = SystemClock.uptimeMillis();
12465 if (r.dispatchTime > 0) {
12466 if ((numReceivers > 0) &&
12467 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12468 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12469 + " now=" + now
12470 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012471 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012472 + " intent=" + r.intent
12473 + " numReceivers=" + numReceivers
12474 + " nextReceiver=" + r.nextReceiver
12475 + " state=" + r.state);
12476 broadcastTimeout(); // forcibly finish this broadcast
12477 forceReceive = true;
12478 r.state = BroadcastRecord.IDLE;
12479 }
12480 }
12481
12482 if (r.state != BroadcastRecord.IDLE) {
12483 if (DEBUG_BROADCAST) Log.d(TAG,
12484 "processNextBroadcast() called when not idle (state="
12485 + r.state + ")");
12486 return;
12487 }
12488
12489 if (r.receivers == null || r.nextReceiver >= numReceivers
12490 || r.resultAbort || forceReceive) {
12491 // No more receivers for this broadcast! Send the final
12492 // result if requested...
12493 if (r.resultTo != null) {
12494 try {
12495 if (DEBUG_BROADCAST) {
12496 int seq = r.intent.getIntExtra("seq", -1);
12497 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12498 + " seq=" + seq + " app=" + r.callerApp);
12499 }
12500 performReceive(r.callerApp, r.resultTo,
12501 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012502 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012503 } catch (RemoteException e) {
12504 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12505 }
12506 }
12507
12508 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12509 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12510
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012511 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12512 + r);
12513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012514 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012515 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012516 mOrderedBroadcasts.remove(0);
12517 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012518 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012519 continue;
12520 }
12521 } while (r == null);
12522
12523 // Get the next receiver...
12524 int recIdx = r.nextReceiver++;
12525
12526 // Keep track of when this receiver started, and make sure there
12527 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012528 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012529 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012530 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012531
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012532 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12533 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012534 if (DEBUG_BROADCAST) Log.v(TAG,
12535 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012536 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012537 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012538 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012539 }
12540
12541 Object nextReceiver = r.receivers.get(recIdx);
12542 if (nextReceiver instanceof BroadcastFilter) {
12543 // Simple case: this is a registered receiver who gets
12544 // a direct call.
12545 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12546 if (DEBUG_BROADCAST) Log.v(TAG,
12547 "Delivering serialized to registered "
12548 + filter + ": " + r);
12549 deliverToRegisteredReceiver(r, filter, r.ordered);
12550 if (r.receiver == null || !r.ordered) {
12551 // The receiver has already finished, so schedule to
12552 // process the next one.
12553 r.state = BroadcastRecord.IDLE;
12554 scheduleBroadcastsLocked();
12555 }
12556 return;
12557 }
12558
12559 // Hard case: need to instantiate the receiver, possibly
12560 // starting its application process to host it.
12561
12562 ResolveInfo info =
12563 (ResolveInfo)nextReceiver;
12564
12565 boolean skip = false;
12566 int perm = checkComponentPermission(info.activityInfo.permission,
12567 r.callingPid, r.callingUid,
12568 info.activityInfo.exported
12569 ? -1 : info.activityInfo.applicationInfo.uid);
12570 if (perm != PackageManager.PERMISSION_GRANTED) {
12571 Log.w(TAG, "Permission Denial: broadcasting "
12572 + r.intent.toString()
12573 + " from " + r.callerPackage + " (pid=" + r.callingPid
12574 + ", uid=" + r.callingUid + ")"
12575 + " requires " + info.activityInfo.permission
12576 + " due to receiver " + info.activityInfo.packageName
12577 + "/" + info.activityInfo.name);
12578 skip = true;
12579 }
12580 if (r.callingUid != Process.SYSTEM_UID &&
12581 r.requiredPermission != null) {
12582 try {
12583 perm = ActivityThread.getPackageManager().
12584 checkPermission(r.requiredPermission,
12585 info.activityInfo.applicationInfo.packageName);
12586 } catch (RemoteException e) {
12587 perm = PackageManager.PERMISSION_DENIED;
12588 }
12589 if (perm != PackageManager.PERMISSION_GRANTED) {
12590 Log.w(TAG, "Permission Denial: receiving "
12591 + r.intent + " to "
12592 + info.activityInfo.applicationInfo.packageName
12593 + " requires " + r.requiredPermission
12594 + " due to sender " + r.callerPackage
12595 + " (uid " + r.callingUid + ")");
12596 skip = true;
12597 }
12598 }
12599 if (r.curApp != null && r.curApp.crashing) {
12600 // If the target process is crashing, just skip it.
12601 skip = true;
12602 }
12603
12604 if (skip) {
12605 r.receiver = null;
12606 r.curFilter = null;
12607 r.state = BroadcastRecord.IDLE;
12608 scheduleBroadcastsLocked();
12609 return;
12610 }
12611
12612 r.state = BroadcastRecord.APP_RECEIVE;
12613 String targetProcess = info.activityInfo.processName;
12614 r.curComponent = new ComponentName(
12615 info.activityInfo.applicationInfo.packageName,
12616 info.activityInfo.name);
12617 r.curReceiver = info.activityInfo;
12618
12619 // Is this receiver's application already running?
12620 ProcessRecord app = getProcessRecordLocked(targetProcess,
12621 info.activityInfo.applicationInfo.uid);
12622 if (app != null && app.thread != null) {
12623 try {
12624 processCurBroadcastLocked(r, app);
12625 return;
12626 } catch (RemoteException e) {
12627 Log.w(TAG, "Exception when sending broadcast to "
12628 + r.curComponent, e);
12629 }
12630
12631 // If a dead object exception was thrown -- fall through to
12632 // restart the application.
12633 }
12634
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012635 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012636 if ((r.curApp=startProcessLocked(targetProcess,
12637 info.activityInfo.applicationInfo, true,
12638 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012639 "broadcast", r.curComponent,
12640 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12641 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012642 // Ah, this recipient is unavailable. Finish it if necessary,
12643 // and mark the broadcast record as ready for the next.
12644 Log.w(TAG, "Unable to launch app "
12645 + info.activityInfo.applicationInfo.packageName + "/"
12646 + info.activityInfo.applicationInfo.uid + " for broadcast "
12647 + r.intent + ": process is bad");
12648 logBroadcastReceiverDiscard(r);
12649 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12650 r.resultExtras, r.resultAbort, true);
12651 scheduleBroadcastsLocked();
12652 r.state = BroadcastRecord.IDLE;
12653 return;
12654 }
12655
12656 mPendingBroadcast = r;
12657 }
12658 }
12659
12660 // =========================================================
12661 // INSTRUMENTATION
12662 // =========================================================
12663
12664 public boolean startInstrumentation(ComponentName className,
12665 String profileFile, int flags, Bundle arguments,
12666 IInstrumentationWatcher watcher) {
12667 // Refuse possible leaked file descriptors
12668 if (arguments != null && arguments.hasFileDescriptors()) {
12669 throw new IllegalArgumentException("File descriptors passed in Bundle");
12670 }
12671
12672 synchronized(this) {
12673 InstrumentationInfo ii = null;
12674 ApplicationInfo ai = null;
12675 try {
12676 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012677 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012678 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012679 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012680 } catch (PackageManager.NameNotFoundException e) {
12681 }
12682 if (ii == null) {
12683 reportStartInstrumentationFailure(watcher, className,
12684 "Unable to find instrumentation info for: " + className);
12685 return false;
12686 }
12687 if (ai == null) {
12688 reportStartInstrumentationFailure(watcher, className,
12689 "Unable to find instrumentation target package: " + ii.targetPackage);
12690 return false;
12691 }
12692
12693 int match = mContext.getPackageManager().checkSignatures(
12694 ii.targetPackage, ii.packageName);
12695 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12696 String msg = "Permission Denial: starting instrumentation "
12697 + className + " from pid="
12698 + Binder.getCallingPid()
12699 + ", uid=" + Binder.getCallingPid()
12700 + " not allowed because package " + ii.packageName
12701 + " does not have a signature matching the target "
12702 + ii.targetPackage;
12703 reportStartInstrumentationFailure(watcher, className, msg);
12704 throw new SecurityException(msg);
12705 }
12706
12707 final long origId = Binder.clearCallingIdentity();
12708 uninstallPackageLocked(ii.targetPackage, -1, true);
12709 ProcessRecord app = addAppLocked(ai);
12710 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012711 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012712 app.instrumentationProfileFile = profileFile;
12713 app.instrumentationArguments = arguments;
12714 app.instrumentationWatcher = watcher;
12715 app.instrumentationResultClass = className;
12716 Binder.restoreCallingIdentity(origId);
12717 }
12718
12719 return true;
12720 }
12721
12722 /**
12723 * Report errors that occur while attempting to start Instrumentation. Always writes the
12724 * error to the logs, but if somebody is watching, send the report there too. This enables
12725 * the "am" command to report errors with more information.
12726 *
12727 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12728 * @param cn The component name of the instrumentation.
12729 * @param report The error report.
12730 */
12731 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12732 ComponentName cn, String report) {
12733 Log.w(TAG, report);
12734 try {
12735 if (watcher != null) {
12736 Bundle results = new Bundle();
12737 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12738 results.putString("Error", report);
12739 watcher.instrumentationStatus(cn, -1, results);
12740 }
12741 } catch (RemoteException e) {
12742 Log.w(TAG, e);
12743 }
12744 }
12745
12746 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12747 if (app.instrumentationWatcher != null) {
12748 try {
12749 // NOTE: IInstrumentationWatcher *must* be oneway here
12750 app.instrumentationWatcher.instrumentationFinished(
12751 app.instrumentationClass,
12752 resultCode,
12753 results);
12754 } catch (RemoteException e) {
12755 }
12756 }
12757 app.instrumentationWatcher = null;
12758 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012759 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012760 app.instrumentationProfileFile = null;
12761 app.instrumentationArguments = null;
12762
12763 uninstallPackageLocked(app.processName, -1, false);
12764 }
12765
12766 public void finishInstrumentation(IApplicationThread target,
12767 int resultCode, Bundle results) {
12768 // Refuse possible leaked file descriptors
12769 if (results != null && results.hasFileDescriptors()) {
12770 throw new IllegalArgumentException("File descriptors passed in Intent");
12771 }
12772
12773 synchronized(this) {
12774 ProcessRecord app = getRecordForAppLocked(target);
12775 if (app == null) {
12776 Log.w(TAG, "finishInstrumentation: no app for " + target);
12777 return;
12778 }
12779 final long origId = Binder.clearCallingIdentity();
12780 finishInstrumentationLocked(app, resultCode, results);
12781 Binder.restoreCallingIdentity(origId);
12782 }
12783 }
12784
12785 // =========================================================
12786 // CONFIGURATION
12787 // =========================================================
12788
12789 public ConfigurationInfo getDeviceConfigurationInfo() {
12790 ConfigurationInfo config = new ConfigurationInfo();
12791 synchronized (this) {
12792 config.reqTouchScreen = mConfiguration.touchscreen;
12793 config.reqKeyboardType = mConfiguration.keyboard;
12794 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012795 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12796 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012797 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12798 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012799 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12800 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012801 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12802 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012803 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012804 }
12805 return config;
12806 }
12807
12808 public Configuration getConfiguration() {
12809 Configuration ci;
12810 synchronized(this) {
12811 ci = new Configuration(mConfiguration);
12812 }
12813 return ci;
12814 }
12815
12816 public void updateConfiguration(Configuration values) {
12817 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12818 "updateConfiguration()");
12819
12820 synchronized(this) {
12821 if (values == null && mWindowManager != null) {
12822 // sentinel: fetch the current configuration from the window manager
12823 values = mWindowManager.computeNewConfiguration();
12824 }
12825
12826 final long origId = Binder.clearCallingIdentity();
12827 updateConfigurationLocked(values, null);
12828 Binder.restoreCallingIdentity(origId);
12829 }
12830 }
12831
12832 /**
12833 * Do either or both things: (1) change the current configuration, and (2)
12834 * make sure the given activity is running with the (now) current
12835 * configuration. Returns true if the activity has been left running, or
12836 * false if <var>starting</var> is being destroyed to match the new
12837 * configuration.
12838 */
12839 public boolean updateConfigurationLocked(Configuration values,
12840 HistoryRecord starting) {
12841 int changes = 0;
12842
12843 boolean kept = true;
12844
12845 if (values != null) {
12846 Configuration newConfig = new Configuration(mConfiguration);
12847 changes = newConfig.updateFrom(values);
12848 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012849 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012850 Log.i(TAG, "Updating configuration to: " + values);
12851 }
12852
Doug Zongker2bec3d42009-12-04 12:52:44 -080012853 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012854
12855 if (values.locale != null) {
12856 saveLocaleLocked(values.locale,
12857 !values.locale.equals(mConfiguration.locale),
12858 values.userSetLocale);
12859 }
12860
12861 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012862 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080012863
12864 AttributeCache ac = AttributeCache.instance();
12865 if (ac != null) {
12866 ac.updateConfiguration(mConfiguration);
12867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012868
12869 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12870 msg.obj = new Configuration(mConfiguration);
12871 mHandler.sendMessage(msg);
12872
12873 final int N = mLRUProcesses.size();
12874 for (int i=0; i<N; i++) {
12875 ProcessRecord app = mLRUProcesses.get(i);
12876 try {
12877 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012878 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12879 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012880 app.thread.scheduleConfigurationChanged(mConfiguration);
12881 }
12882 } catch (Exception e) {
12883 }
12884 }
12885 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012886 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012887 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12888 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012889 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
12890 broadcastIntentLocked(null, null,
12891 new Intent(Intent.ACTION_LOCALE_CHANGED),
12892 null, null, 0, null, null,
12893 null, false, false, MY_PID, Process.SYSTEM_UID);
12894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012895 }
12896 }
12897
12898 if (changes != 0 && starting == null) {
12899 // If the configuration changed, and the caller is not already
12900 // in the process of starting an activity, then find the top
12901 // activity to check if its configuration needs to change.
12902 starting = topRunningActivityLocked(null);
12903 }
12904
12905 if (starting != null) {
12906 kept = ensureActivityConfigurationLocked(starting, changes);
12907 if (kept) {
12908 // If this didn't result in the starting activity being
12909 // destroyed, then we need to make sure at this point that all
12910 // other activities are made visible.
12911 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12912 + ", ensuring others are correct.");
12913 ensureActivitiesVisibleLocked(starting, changes);
12914 }
12915 }
12916
12917 return kept;
12918 }
12919
12920 private final boolean relaunchActivityLocked(HistoryRecord r,
12921 int changes, boolean andResume) {
12922 List<ResultInfo> results = null;
12923 List<Intent> newIntents = null;
12924 if (andResume) {
12925 results = r.results;
12926 newIntents = r.newIntents;
12927 }
12928 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12929 + " with results=" + results + " newIntents=" + newIntents
12930 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012931 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
12932 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012933 r.task.taskId, r.shortComponentName);
12934
12935 r.startFreezingScreenLocked(r.app, 0);
12936
12937 try {
12938 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12939 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12940 changes, !andResume);
12941 // Note: don't need to call pauseIfSleepingLocked() here, because
12942 // the caller will only pass in 'andResume' if this activity is
12943 // currently resumed, which implies we aren't sleeping.
12944 } catch (RemoteException e) {
12945 return false;
12946 }
12947
12948 if (andResume) {
12949 r.results = null;
12950 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012951 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012952 }
12953
12954 return true;
12955 }
12956
12957 /**
12958 * Make sure the given activity matches the current configuration. Returns
12959 * false if the activity had to be destroyed. Returns true if the
12960 * configuration is the same, or the activity will remain running as-is
12961 * for whatever reason. Ensures the HistoryRecord is updated with the
12962 * correct configuration and all other bookkeeping is handled.
12963 */
12964 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12965 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012966 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12967 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012968
12969 // Short circuit: if the two configurations are the exact same
12970 // object (the common case), then there is nothing to do.
12971 Configuration newConfig = mConfiguration;
12972 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012973 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12974 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012975 return true;
12976 }
12977
12978 // We don't worry about activities that are finishing.
12979 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012980 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012981 "Configuration doesn't matter in finishing " + r);
12982 r.stopFreezingScreenLocked(false);
12983 return true;
12984 }
12985
12986 // Okay we now are going to make this activity have the new config.
12987 // But then we need to figure out how it needs to deal with that.
12988 Configuration oldConfig = r.configuration;
12989 r.configuration = newConfig;
12990
12991 // If the activity isn't currently running, just leave the new
12992 // configuration and it will pick that up next time it starts.
12993 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012994 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012995 "Configuration doesn't matter not running " + r);
12996 r.stopFreezingScreenLocked(false);
12997 return true;
12998 }
12999
13000 // If the activity isn't persistent, there is a chance we will
13001 // need to restart it.
13002 if (!r.persistent) {
13003
13004 // Figure out what has changed between the two configurations.
13005 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013006 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13007 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013008 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013009 + Integer.toHexString(r.info.configChanges)
13010 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013011 }
13012 if ((changes&(~r.info.configChanges)) != 0) {
13013 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13014 r.configChangeFlags |= changes;
13015 r.startFreezingScreenLocked(r.app, globalChanges);
13016 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013017 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13018 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013019 destroyActivityLocked(r, true);
13020 } else if (r.state == ActivityState.PAUSING) {
13021 // A little annoying: we are waiting for this activity to
13022 // finish pausing. Let's not do anything now, but just
13023 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013024 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13025 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013026 r.configDestroy = true;
13027 return true;
13028 } else if (r.state == ActivityState.RESUMED) {
13029 // Try to optimize this case: the configuration is changing
13030 // and we need to restart the top, resumed activity.
13031 // Instead of doing the normal handshaking, just say
13032 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013033 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13034 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013035 relaunchActivityLocked(r, r.configChangeFlags, true);
13036 r.configChangeFlags = 0;
13037 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013038 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13039 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013040 relaunchActivityLocked(r, r.configChangeFlags, false);
13041 r.configChangeFlags = 0;
13042 }
13043
13044 // All done... tell the caller we weren't able to keep this
13045 // activity around.
13046 return false;
13047 }
13048 }
13049
13050 // Default case: the activity can handle this new configuration, so
13051 // hand it over. Note that we don't need to give it the new
13052 // configuration, since we always send configuration changes to all
13053 // process when they happen so it can just use whatever configuration
13054 // it last got.
13055 if (r.app != null && r.app.thread != null) {
13056 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013057 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013058 r.app.thread.scheduleActivityConfigurationChanged(r);
13059 } catch (RemoteException e) {
13060 // If process died, whatever.
13061 }
13062 }
13063 r.stopFreezingScreenLocked(false);
13064
13065 return true;
13066 }
13067
13068 /**
13069 * Save the locale. You must be inside a synchronized (this) block.
13070 */
13071 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13072 if(isDiff) {
13073 SystemProperties.set("user.language", l.getLanguage());
13074 SystemProperties.set("user.region", l.getCountry());
13075 }
13076
13077 if(isPersist) {
13078 SystemProperties.set("persist.sys.language", l.getLanguage());
13079 SystemProperties.set("persist.sys.country", l.getCountry());
13080 SystemProperties.set("persist.sys.localevar", l.getVariant());
13081 }
13082 }
13083
13084 // =========================================================
13085 // LIFETIME MANAGEMENT
13086 // =========================================================
13087
13088 private final int computeOomAdjLocked(
13089 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13090 if (mAdjSeq == app.adjSeq) {
13091 // This adjustment has already been computed.
13092 return app.curAdj;
13093 }
13094
13095 if (app.thread == null) {
13096 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013097 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013098 return (app.curAdj=EMPTY_APP_ADJ);
13099 }
13100
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013101 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13102 // The max adjustment doesn't allow this app to be anything
13103 // below foreground, so it is not worth doing work for it.
13104 app.adjType = "fixed";
13105 app.adjSeq = mAdjSeq;
13106 app.curRawAdj = app.maxAdj;
13107 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13108 return (app.curAdj=app.maxAdj);
13109 }
13110
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013111 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013112 app.adjSource = null;
13113 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013114
The Android Open Source Project4df24232009-03-05 14:34:35 -080013115 // Determine the importance of the process, starting with most
13116 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013117 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013118 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013119 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013120 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013121 // The last app on the list is the foreground app.
13122 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013123 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013124 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013125 } else if (app.instrumentationClass != null) {
13126 // Don't want to kill running instrumentation.
13127 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013128 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013129 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013130 } else if (app.persistentActivities > 0) {
13131 // Special persistent activities... shouldn't be used these days.
13132 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013133 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013134 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013135 } else if (app.curReceiver != null ||
13136 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13137 // An app that is currently receiving a broadcast also
13138 // counts as being in the foreground.
13139 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013140 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013141 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013142 } else if (app.executingServices.size() > 0) {
13143 // An app that is currently executing a service callback also
13144 // counts as being in the foreground.
13145 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013146 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013147 app.adjType = "exec-service";
13148 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013149 // The user is aware of this app, so make it visible.
13150 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013151 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013152 app.adjType = "foreground-service";
13153 } else if (app.forcingToForeground != null) {
13154 // The user is aware of this app, so make it visible.
13155 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013156 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013157 app.adjType = "force-foreground";
13158 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013159 } else if (app == mHomeProcess) {
13160 // This process is hosting what we currently consider to be the
13161 // home app, so we don't want to let it go into the background.
13162 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013163 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013164 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013165 } else if ((N=app.activities.size()) != 0) {
13166 // This app is in the background with paused activities.
13167 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013168 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013169 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013170 for (int j=0; j<N; j++) {
13171 if (((HistoryRecord)app.activities.get(j)).visible) {
13172 // This app has a visible activity!
13173 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013174 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013175 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013176 break;
13177 }
13178 }
13179 } else {
13180 // A very not-needed process.
13181 adj = EMPTY_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013182 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013183 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013184 }
13185
The Android Open Source Project4df24232009-03-05 14:34:35 -080013186 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013187 // there are applications dependent on our services or providers, but
13188 // this gives us a baseline and makes sure we don't get into an
13189 // infinite recursion.
13190 app.adjSeq = mAdjSeq;
13191 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013192
Christopher Tate6fa95972009-06-05 18:43:55 -070013193 if (mBackupTarget != null && app == mBackupTarget.app) {
13194 // If possible we want to avoid killing apps while they're being backed up
13195 if (adj > BACKUP_APP_ADJ) {
13196 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13197 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013198 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013199 }
13200 }
13201
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013202 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13203 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013204 final long now = SystemClock.uptimeMillis();
13205 // This process is more important if the top activity is
13206 // bound to the service.
13207 Iterator jt = app.services.iterator();
13208 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13209 ServiceRecord s = (ServiceRecord)jt.next();
13210 if (s.startRequested) {
13211 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13212 // This service has seen some activity within
13213 // recent memory, so we will keep its process ahead
13214 // of the background processes.
13215 if (adj > SECONDARY_SERVER_ADJ) {
13216 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013217 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013218 }
13219 }
13220 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013221 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13222 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013223 Iterator<ConnectionRecord> kt
13224 = s.connections.values().iterator();
13225 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13226 // XXX should compute this based on the max of
13227 // all connected clients.
13228 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013229 if (cr.binding.client == app) {
13230 // Binding to ourself is not interesting.
13231 continue;
13232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013233 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13234 ProcessRecord client = cr.binding.client;
13235 int myHiddenAdj = hiddenAdj;
13236 if (myHiddenAdj > client.hiddenAdj) {
13237 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13238 myHiddenAdj = client.hiddenAdj;
13239 } else {
13240 myHiddenAdj = VISIBLE_APP_ADJ;
13241 }
13242 }
13243 int clientAdj = computeOomAdjLocked(
13244 client, myHiddenAdj, TOP_APP);
13245 if (adj > clientAdj) {
13246 adj = clientAdj > VISIBLE_APP_ADJ
13247 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013248 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013249 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13250 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013251 app.adjSource = cr.binding.client;
13252 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013253 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013254 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13255 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13256 schedGroup = Process.THREAD_GROUP_DEFAULT;
13257 }
13258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013259 }
13260 HistoryRecord a = cr.activity;
13261 //if (a != null) {
13262 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13263 //}
13264 if (a != null && adj > FOREGROUND_APP_ADJ &&
13265 (a.state == ActivityState.RESUMED
13266 || a.state == ActivityState.PAUSING)) {
13267 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013268 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013269 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013270 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13271 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013272 app.adjSource = a;
13273 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013274 }
13275 }
13276 }
13277 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013278
13279 // Finally, f this process has active services running in it, we
13280 // would like to avoid killing it unless it would prevent the current
13281 // application from running. By default we put the process in
13282 // with the rest of the background processes; as we scan through
13283 // its services we may bump it up from there.
13284 if (adj > hiddenAdj) {
13285 adj = hiddenAdj;
13286 app.adjType = "bg-services";
13287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013288 }
13289
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013290 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13291 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013292 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013293 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13294 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013295 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13296 if (cpr.clients.size() != 0) {
13297 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13298 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13299 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013300 if (client == app) {
13301 // Being our own client is not interesting.
13302 continue;
13303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013304 int myHiddenAdj = hiddenAdj;
13305 if (myHiddenAdj > client.hiddenAdj) {
13306 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13307 myHiddenAdj = client.hiddenAdj;
13308 } else {
13309 myHiddenAdj = FOREGROUND_APP_ADJ;
13310 }
13311 }
13312 int clientAdj = computeOomAdjLocked(
13313 client, myHiddenAdj, TOP_APP);
13314 if (adj > clientAdj) {
13315 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013316 ? clientAdj : FOREGROUND_APP_ADJ;
13317 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013318 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13319 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013320 app.adjSource = client;
13321 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013322 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013323 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13324 schedGroup = Process.THREAD_GROUP_DEFAULT;
13325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013326 }
13327 }
13328 // If the provider has external (non-framework) process
13329 // dependencies, ensure that its adjustment is at least
13330 // FOREGROUND_APP_ADJ.
13331 if (cpr.externals != 0) {
13332 if (adj > FOREGROUND_APP_ADJ) {
13333 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013334 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013335 app.adjType = "provider";
13336 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013337 }
13338 }
13339 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013340
13341 // Finally, if this process has published any content providers,
13342 // then its adjustment makes it at least as important as any of the
13343 // processes using those providers, and no less important than
13344 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13345 if (adj > CONTENT_PROVIDER_ADJ) {
13346 adj = CONTENT_PROVIDER_ADJ;
13347 app.adjType = "pub-providers";
13348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013349 }
13350
13351 app.curRawAdj = adj;
13352
13353 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13354 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13355 if (adj > app.maxAdj) {
13356 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013357 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13358 schedGroup = Process.THREAD_GROUP_DEFAULT;
13359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013360 }
13361
13362 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013363 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013365 return adj;
13366 }
13367
13368 /**
13369 * Ask a given process to GC right now.
13370 */
13371 final void performAppGcLocked(ProcessRecord app) {
13372 try {
13373 app.lastRequestedGc = SystemClock.uptimeMillis();
13374 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013375 if (app.reportLowMemory) {
13376 app.reportLowMemory = false;
13377 app.thread.scheduleLowMemory();
13378 } else {
13379 app.thread.processInBackground();
13380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013381 }
13382 } catch (Exception e) {
13383 // whatever.
13384 }
13385 }
13386
13387 /**
13388 * Returns true if things are idle enough to perform GCs.
13389 */
13390 private final boolean canGcNow() {
13391 return mParallelBroadcasts.size() == 0
13392 && mOrderedBroadcasts.size() == 0
13393 && (mSleeping || (mResumedActivity != null &&
13394 mResumedActivity.idle));
13395 }
13396
13397 /**
13398 * Perform GCs on all processes that are waiting for it, but only
13399 * if things are idle.
13400 */
13401 final void performAppGcsLocked() {
13402 final int N = mProcessesToGc.size();
13403 if (N <= 0) {
13404 return;
13405 }
13406 if (canGcNow()) {
13407 while (mProcessesToGc.size() > 0) {
13408 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013409 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13410 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13411 <= SystemClock.uptimeMillis()) {
13412 // To avoid spamming the system, we will GC processes one
13413 // at a time, waiting a few seconds between each.
13414 performAppGcLocked(proc);
13415 scheduleAppGcsLocked();
13416 return;
13417 } else {
13418 // It hasn't been long enough since we last GCed this
13419 // process... put it in the list to wait for its time.
13420 addProcessToGcListLocked(proc);
13421 break;
13422 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013423 }
13424 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013425
13426 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013427 }
13428 }
13429
13430 /**
13431 * If all looks good, perform GCs on all processes waiting for them.
13432 */
13433 final void performAppGcsIfAppropriateLocked() {
13434 if (canGcNow()) {
13435 performAppGcsLocked();
13436 return;
13437 }
13438 // Still not idle, wait some more.
13439 scheduleAppGcsLocked();
13440 }
13441
13442 /**
13443 * Schedule the execution of all pending app GCs.
13444 */
13445 final void scheduleAppGcsLocked() {
13446 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013447
13448 if (mProcessesToGc.size() > 0) {
13449 // Schedule a GC for the time to the next process.
13450 ProcessRecord proc = mProcessesToGc.get(0);
13451 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13452
13453 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13454 long now = SystemClock.uptimeMillis();
13455 if (when < (now+GC_TIMEOUT)) {
13456 when = now + GC_TIMEOUT;
13457 }
13458 mHandler.sendMessageAtTime(msg, when);
13459 }
13460 }
13461
13462 /**
13463 * Add a process to the array of processes waiting to be GCed. Keeps the
13464 * list in sorted order by the last GC time. The process can't already be
13465 * on the list.
13466 */
13467 final void addProcessToGcListLocked(ProcessRecord proc) {
13468 boolean added = false;
13469 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13470 if (mProcessesToGc.get(i).lastRequestedGc <
13471 proc.lastRequestedGc) {
13472 added = true;
13473 mProcessesToGc.add(i+1, proc);
13474 break;
13475 }
13476 }
13477 if (!added) {
13478 mProcessesToGc.add(0, proc);
13479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013480 }
13481
13482 /**
13483 * Set up to ask a process to GC itself. This will either do it
13484 * immediately, or put it on the list of processes to gc the next
13485 * time things are idle.
13486 */
13487 final void scheduleAppGcLocked(ProcessRecord app) {
13488 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013489 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013490 return;
13491 }
13492 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013493 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013494 scheduleAppGcsLocked();
13495 }
13496 }
13497
13498 private final boolean updateOomAdjLocked(
13499 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13500 app.hiddenAdj = hiddenAdj;
13501
13502 if (app.thread == null) {
13503 return true;
13504 }
13505
13506 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13507
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013508 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013509 if (app.curRawAdj != app.setRawAdj) {
13510 if (app.curRawAdj > FOREGROUND_APP_ADJ
13511 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13512 // If this app is transitioning from foreground to
13513 // non-foreground, have it do a gc.
13514 scheduleAppGcLocked(app);
13515 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13516 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13517 // Likewise do a gc when an app is moving in to the
13518 // background (such as a service stopping).
13519 scheduleAppGcLocked(app);
13520 }
13521 app.setRawAdj = app.curRawAdj;
13522 }
13523 if (adj != app.setAdj) {
13524 if (Process.setOomAdj(app.pid, adj)) {
13525 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13526 TAG, "Set app " + app.processName +
13527 " oom adj to " + adj);
13528 app.setAdj = adj;
13529 } else {
13530 return false;
13531 }
13532 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013533 if (app.setSchedGroup != app.curSchedGroup) {
13534 app.setSchedGroup = app.curSchedGroup;
13535 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13536 "Setting process group of " + app.processName
13537 + " to " + app.curSchedGroup);
13538 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013539 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013540 try {
13541 Process.setProcessGroup(app.pid, app.curSchedGroup);
13542 } catch (Exception e) {
13543 Log.w(TAG, "Failed setting process group of " + app.pid
13544 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013545 e.printStackTrace();
13546 } finally {
13547 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013548 }
13549 }
13550 if (false) {
13551 if (app.thread != null) {
13552 try {
13553 app.thread.setSchedulingGroup(app.curSchedGroup);
13554 } catch (RemoteException e) {
13555 }
13556 }
13557 }
13558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013559 }
13560
13561 return true;
13562 }
13563
13564 private final HistoryRecord resumedAppLocked() {
13565 HistoryRecord resumedActivity = mResumedActivity;
13566 if (resumedActivity == null || resumedActivity.app == null) {
13567 resumedActivity = mPausingActivity;
13568 if (resumedActivity == null || resumedActivity.app == null) {
13569 resumedActivity = topRunningActivityLocked(null);
13570 }
13571 }
13572 return resumedActivity;
13573 }
13574
13575 private final boolean updateOomAdjLocked(ProcessRecord app) {
13576 final HistoryRecord TOP_ACT = resumedAppLocked();
13577 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13578 int curAdj = app.curAdj;
13579 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13580 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13581
13582 mAdjSeq++;
13583
13584 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13585 if (res) {
13586 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13587 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13588 if (nowHidden != wasHidden) {
13589 // Changed to/from hidden state, so apps after it in the LRU
13590 // list may also be changed.
13591 updateOomAdjLocked();
13592 }
13593 }
13594 return res;
13595 }
13596
13597 private final boolean updateOomAdjLocked() {
13598 boolean didOomAdj = true;
13599 final HistoryRecord TOP_ACT = resumedAppLocked();
13600 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13601
13602 if (false) {
13603 RuntimeException e = new RuntimeException();
13604 e.fillInStackTrace();
13605 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13606 }
13607
13608 mAdjSeq++;
13609
13610 // First try updating the OOM adjustment for each of the
13611 // application processes based on their current state.
13612 int i = mLRUProcesses.size();
13613 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13614 while (i > 0) {
13615 i--;
13616 ProcessRecord app = mLRUProcesses.get(i);
13617 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13618 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13619 && app.curAdj == curHiddenAdj) {
13620 curHiddenAdj++;
13621 }
13622 } else {
13623 didOomAdj = false;
13624 }
13625 }
13626
13627 // todo: for now pretend like OOM ADJ didn't work, because things
13628 // aren't behaving as expected on Linux -- it's not killing processes.
13629 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13630 }
13631
13632 private final void trimApplications() {
13633 synchronized (this) {
13634 int i;
13635
13636 // First remove any unused application processes whose package
13637 // has been removed.
13638 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13639 final ProcessRecord app = mRemovedProcesses.get(i);
13640 if (app.activities.size() == 0
13641 && app.curReceiver == null && app.services.size() == 0) {
13642 Log.i(
13643 TAG, "Exiting empty application process "
13644 + app.processName + " ("
13645 + (app.thread != null ? app.thread.asBinder() : null)
13646 + ")\n");
13647 if (app.pid > 0 && app.pid != MY_PID) {
13648 Process.killProcess(app.pid);
13649 } else {
13650 try {
13651 app.thread.scheduleExit();
13652 } catch (Exception e) {
13653 // Ignore exceptions.
13654 }
13655 }
13656 cleanUpApplicationRecordLocked(app, false, -1);
13657 mRemovedProcesses.remove(i);
13658
13659 if (app.persistent) {
13660 if (app.persistent) {
13661 addAppLocked(app.info);
13662 }
13663 }
13664 }
13665 }
13666
13667 // Now try updating the OOM adjustment for each of the
13668 // application processes based on their current state.
13669 // If the setOomAdj() API is not supported, then go with our
13670 // back-up plan...
13671 if (!updateOomAdjLocked()) {
13672
13673 // Count how many processes are running services.
13674 int numServiceProcs = 0;
13675 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13676 final ProcessRecord app = mLRUProcesses.get(i);
13677
13678 if (app.persistent || app.services.size() != 0
13679 || app.curReceiver != null
13680 || app.persistentActivities > 0) {
13681 // Don't count processes holding services against our
13682 // maximum process count.
13683 if (localLOGV) Log.v(
13684 TAG, "Not trimming app " + app + " with services: "
13685 + app.services);
13686 numServiceProcs++;
13687 }
13688 }
13689
13690 int curMaxProcs = mProcessLimit;
13691 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13692 if (mAlwaysFinishActivities) {
13693 curMaxProcs = 1;
13694 }
13695 curMaxProcs += numServiceProcs;
13696
13697 // Quit as many processes as we can to get down to the desired
13698 // process count. First remove any processes that no longer
13699 // have activites running in them.
13700 for ( i=0;
13701 i<mLRUProcesses.size()
13702 && mLRUProcesses.size() > curMaxProcs;
13703 i++) {
13704 final ProcessRecord app = mLRUProcesses.get(i);
13705 // Quit an application only if it is not currently
13706 // running any activities.
13707 if (!app.persistent && app.activities.size() == 0
13708 && app.curReceiver == null && app.services.size() == 0) {
13709 Log.i(
13710 TAG, "Exiting empty application process "
13711 + app.processName + " ("
13712 + (app.thread != null ? app.thread.asBinder() : null)
13713 + ")\n");
13714 if (app.pid > 0 && app.pid != MY_PID) {
13715 Process.killProcess(app.pid);
13716 } else {
13717 try {
13718 app.thread.scheduleExit();
13719 } catch (Exception e) {
13720 // Ignore exceptions.
13721 }
13722 }
13723 // todo: For now we assume the application is not buggy
13724 // or evil, and will quit as a result of our request.
13725 // Eventually we need to drive this off of the death
13726 // notification, and kill the process if it takes too long.
13727 cleanUpApplicationRecordLocked(app, false, i);
13728 i--;
13729 }
13730 }
13731
13732 // If we still have too many processes, now from the least
13733 // recently used process we start finishing activities.
13734 if (Config.LOGV) Log.v(
13735 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13736 " of " + curMaxProcs + " processes");
13737 for ( i=0;
13738 i<mLRUProcesses.size()
13739 && mLRUProcesses.size() > curMaxProcs;
13740 i++) {
13741 final ProcessRecord app = mLRUProcesses.get(i);
13742 // Quit the application only if we have a state saved for
13743 // all of its activities.
13744 boolean canQuit = !app.persistent && app.curReceiver == null
13745 && app.services.size() == 0
13746 && app.persistentActivities == 0;
13747 int NUMA = app.activities.size();
13748 int j;
13749 if (Config.LOGV) Log.v(
13750 TAG, "Looking to quit " + app.processName);
13751 for (j=0; j<NUMA && canQuit; j++) {
13752 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13753 if (Config.LOGV) Log.v(
13754 TAG, " " + r.intent.getComponent().flattenToShortString()
13755 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13756 canQuit = (r.haveState || !r.stateNotNeeded)
13757 && !r.visible && r.stopped;
13758 }
13759 if (canQuit) {
13760 // Finish all of the activities, and then the app itself.
13761 for (j=0; j<NUMA; j++) {
13762 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13763 if (!r.finishing) {
13764 destroyActivityLocked(r, false);
13765 }
13766 r.resultTo = null;
13767 }
13768 Log.i(TAG, "Exiting application process "
13769 + app.processName + " ("
13770 + (app.thread != null ? app.thread.asBinder() : null)
13771 + ")\n");
13772 if (app.pid > 0 && app.pid != MY_PID) {
13773 Process.killProcess(app.pid);
13774 } else {
13775 try {
13776 app.thread.scheduleExit();
13777 } catch (Exception e) {
13778 // Ignore exceptions.
13779 }
13780 }
13781 // todo: For now we assume the application is not buggy
13782 // or evil, and will quit as a result of our request.
13783 // Eventually we need to drive this off of the death
13784 // notification, and kill the process if it takes too long.
13785 cleanUpApplicationRecordLocked(app, false, i);
13786 i--;
13787 //dump();
13788 }
13789 }
13790
13791 }
13792
13793 int curMaxActivities = MAX_ACTIVITIES;
13794 if (mAlwaysFinishActivities) {
13795 curMaxActivities = 1;
13796 }
13797
13798 // Finally, if there are too many activities now running, try to
13799 // finish as many as we can to get back down to the limit.
13800 for ( i=0;
13801 i<mLRUActivities.size()
13802 && mLRUActivities.size() > curMaxActivities;
13803 i++) {
13804 final HistoryRecord r
13805 = (HistoryRecord)mLRUActivities.get(i);
13806
13807 // We can finish this one if we have its icicle saved and
13808 // it is not persistent.
13809 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13810 && r.stopped && !r.persistent && !r.finishing) {
13811 final int origSize = mLRUActivities.size();
13812 destroyActivityLocked(r, true);
13813
13814 // This will remove it from the LRU list, so keep
13815 // our index at the same value. Note that this check to
13816 // see if the size changes is just paranoia -- if
13817 // something unexpected happens, we don't want to end up
13818 // in an infinite loop.
13819 if (origSize > mLRUActivities.size()) {
13820 i--;
13821 }
13822 }
13823 }
13824 }
13825 }
13826
13827 /** This method sends the specified signal to each of the persistent apps */
13828 public void signalPersistentProcesses(int sig) throws RemoteException {
13829 if (sig != Process.SIGNAL_USR1) {
13830 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13831 }
13832
13833 synchronized (this) {
13834 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13835 != PackageManager.PERMISSION_GRANTED) {
13836 throw new SecurityException("Requires permission "
13837 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13838 }
13839
13840 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13841 ProcessRecord r = mLRUProcesses.get(i);
13842 if (r.thread != null && r.persistent) {
13843 Process.sendSignal(r.pid, sig);
13844 }
13845 }
13846 }
13847 }
13848
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013849 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013850 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013851
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013852 try {
13853 synchronized (this) {
13854 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13855 // its own permission.
13856 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13857 != PackageManager.PERMISSION_GRANTED) {
13858 throw new SecurityException("Requires permission "
13859 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013860 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013861
13862 if (start && fd == null) {
13863 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013864 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013865
13866 ProcessRecord proc = null;
13867 try {
13868 int pid = Integer.parseInt(process);
13869 synchronized (mPidsSelfLocked) {
13870 proc = mPidsSelfLocked.get(pid);
13871 }
13872 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013873 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013874
13875 if (proc == null) {
13876 HashMap<String, SparseArray<ProcessRecord>> all
13877 = mProcessNames.getMap();
13878 SparseArray<ProcessRecord> procs = all.get(process);
13879 if (procs != null && procs.size() > 0) {
13880 proc = procs.valueAt(0);
13881 }
13882 }
13883
13884 if (proc == null || proc.thread == null) {
13885 throw new IllegalArgumentException("Unknown process: " + process);
13886 }
13887
13888 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13889 if (isSecure) {
13890 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13891 throw new SecurityException("Process not debuggable: " + proc);
13892 }
13893 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013894
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013895 proc.thread.profilerControl(start, path, fd);
13896 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013897 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013898 }
13899 } catch (RemoteException e) {
13900 throw new IllegalStateException("Process disappeared");
13901 } finally {
13902 if (fd != null) {
13903 try {
13904 fd.close();
13905 } catch (IOException e) {
13906 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013907 }
13908 }
13909 }
13910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013911 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13912 public void monitor() {
13913 synchronized (this) { }
13914 }
13915}