blob: 23eb7c17b69b802a033fb008f0fa8f0dafab6ffd [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.pm.ActivityInfo;
56import android.content.pm.ApplicationInfo;
57import android.content.pm.ConfigurationInfo;
58import android.content.pm.IPackageDataObserver;
59import android.content.pm.IPackageManager;
60import android.content.pm.InstrumentationInfo;
61import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070062import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.content.pm.ProviderInfo;
64import android.content.pm.ResolveInfo;
65import android.content.pm.ServiceInfo;
66import android.content.res.Configuration;
67import android.graphics.Bitmap;
68import android.net.Uri;
69import android.os.Binder;
70import android.os.Bundle;
71import android.os.Environment;
72import android.os.FileUtils;
73import android.os.Handler;
74import android.os.IBinder;
75import android.os.IPermissionController;
76import android.os.Looper;
77import android.os.Message;
78import android.os.Parcel;
79import android.os.ParcelFileDescriptor;
80import android.os.PowerManager;
81import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070082import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.os.RemoteException;
84import android.os.ServiceManager;
85import android.os.SystemClock;
86import android.os.SystemProperties;
87import android.provider.Checkin;
88import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020089import android.server.data.CrashData;
90import android.server.data.StackTraceElementData;
91import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.text.TextUtils;
93import android.util.Config;
94import android.util.EventLog;
95import android.util.Log;
96import android.util.PrintWriterPrinter;
97import android.util.SparseArray;
98import android.view.Gravity;
99import android.view.LayoutInflater;
100import android.view.View;
101import android.view.WindowManager;
102import android.view.WindowManagerPolicy;
103
104import dalvik.system.Zygote;
105
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200106import java.io.ByteArrayInputStream;
107import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileDescriptor;
110import java.io.FileInputStream;
111import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200112import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.io.PrintWriter;
114import java.lang.IllegalStateException;
115import java.lang.ref.WeakReference;
116import java.util.ArrayList;
117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.Iterator;
120import java.util.List;
121import java.util.Locale;
122import java.util.Map;
123
124public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
125 static final String TAG = "ActivityManager";
126 static final boolean DEBUG = false;
127 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
128 static final boolean DEBUG_SWITCH = localLOGV || false;
129 static final boolean DEBUG_TASKS = localLOGV || false;
130 static final boolean DEBUG_PAUSE = localLOGV || false;
131 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
132 static final boolean DEBUG_TRANSITION = localLOGV || false;
133 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700134 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 static final boolean DEBUG_SERVICE = localLOGV || false;
136 static final boolean DEBUG_VISBILITY = localLOGV || false;
137 static final boolean DEBUG_PROCESSES = localLOGV || false;
138 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700139 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700140 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean VALIDATE_TOKENS = false;
142 static final boolean SHOW_ACTIVITY_START_TIME = true;
143
144 // Control over CPU and battery monitoring.
145 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
146 static final boolean MONITOR_CPU_USAGE = true;
147 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
148 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
149 static final boolean MONITOR_THREAD_CPU_USAGE = false;
150
151 // Event log tags
152 static final int LOG_CONFIGURATION_CHANGED = 2719;
153 static final int LOG_CPU = 2721;
154 static final int LOG_AM_FINISH_ACTIVITY = 30001;
155 static final int LOG_TASK_TO_FRONT = 30002;
156 static final int LOG_AM_NEW_INTENT = 30003;
157 static final int LOG_AM_CREATE_TASK = 30004;
158 static final int LOG_AM_CREATE_ACTIVITY = 30005;
159 static final int LOG_AM_RESTART_ACTIVITY = 30006;
160 static final int LOG_AM_RESUME_ACTIVITY = 30007;
161 static final int LOG_ANR = 30008;
162 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
163 static final int LOG_AM_PROCESS_BOUND = 30010;
164 static final int LOG_AM_PROCESS_DIED = 30011;
165 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
166 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
167 static final int LOG_AM_PROCESS_START = 30014;
168 static final int LOG_AM_PROCESS_BAD = 30015;
169 static final int LOG_AM_PROCESS_GOOD = 30016;
170 static final int LOG_AM_LOW_MEMORY = 30017;
171 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
172 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
173 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
174 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
175 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
176 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
177 static final int LOG_AM_CREATE_SERVICE = 30030;
178 static final int LOG_AM_DESTROY_SERVICE = 30031;
179 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
180 static final int LOG_AM_DROP_PROCESS = 30033;
181 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
182 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
183 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
184
185 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
186 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
187
Dianne Hackborn1655be42009-05-08 14:29:01 -0700188 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700189 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 private static final String SYSTEM_SECURE = "ro.secure";
192
193 // This is the maximum number of application processes we would like
194 // to have running. Due to the asynchronous nature of things, we can
195 // temporarily go beyond this limit.
196 static final int MAX_PROCESSES = 2;
197
198 // Set to false to leave processes running indefinitely, relying on
199 // the kernel killing them as resources are required.
200 static final boolean ENFORCE_PROCESS_LIMIT = false;
201
202 // This is the maximum number of activities that we would like to have
203 // running at a given time.
204 static final int MAX_ACTIVITIES = 20;
205
206 // Maximum number of recent tasks that we can remember.
207 static final int MAX_RECENT_TASKS = 20;
208
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700209 // Amount of time after a call to stopAppSwitches() during which we will
210 // prevent further untrusted switches from happening.
211 static final long APP_SWITCH_DELAY_TIME = 5*1000;
212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 // How long until we reset a task when the user returns to it. Currently
214 // 30 minutes.
215 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
216
217 // Set to true to disable the icon that is shown while a new activity
218 // is being started.
219 static final boolean SHOW_APP_STARTING_ICON = true;
220
221 // How long we wait until giving up on the last activity to pause. This
222 // is short because it directly impacts the responsiveness of starting the
223 // next activity.
224 static final int PAUSE_TIMEOUT = 500;
225
226 /**
227 * How long we can hold the launch wake lock before giving up.
228 */
229 static final int LAUNCH_TIMEOUT = 10*1000;
230
231 // How long we wait for a launched process to attach to the activity manager
232 // before we decide it's never going to come up for real.
233 static final int PROC_START_TIMEOUT = 10*1000;
234
235 // How long we wait until giving up on the last activity telling us it
236 // is idle.
237 static final int IDLE_TIMEOUT = 10*1000;
238
239 // How long to wait after going idle before forcing apps to GC.
240 static final int GC_TIMEOUT = 5*1000;
241
242 // How long we wait until giving up on an activity telling us it has
243 // finished destroying itself.
244 static final int DESTROY_TIMEOUT = 10*1000;
245
246 // How long we allow a receiver to run before giving up on it.
247 static final int BROADCAST_TIMEOUT = 10*1000;
248
249 // How long we wait for a service to finish executing.
250 static final int SERVICE_TIMEOUT = 20*1000;
251
252 // How long a service needs to be running until restarting its process
253 // is no longer considered to be a relaunch of the service.
254 static final int SERVICE_RESTART_DURATION = 5*1000;
255
256 // Maximum amount of time for there to be no activity on a service before
257 // we consider it non-essential and allow its process to go on the
258 // LRU background list.
259 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
260
261 // How long we wait until we timeout on key dispatching.
262 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
263
264 // The minimum time we allow between crashes, for us to consider this
265 // application to be bad and stop and its services and reject broadcasts.
266 static final int MIN_CRASH_INTERVAL = 60*1000;
267
268 // How long we wait until we timeout on key dispatching during instrumentation.
269 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
270
271 // OOM adjustments for processes in various states:
272
273 // This is a process without anything currently running in it. Definitely
274 // the first to go! Value set in system/rootdir/init.rc on startup.
275 // This value is initalized in the constructor, careful when refering to
276 // this static variable externally.
277 static int EMPTY_APP_ADJ;
278
279 // This is a process with a content provider that does not have any clients
280 // attached to it. If it did have any clients, its adjustment would be the
281 // one for the highest-priority of those processes.
282 static int CONTENT_PROVIDER_ADJ;
283
284 // This is a process only hosting activities that are not visible,
285 // so it can be killed without any disruption. Value set in
286 // system/rootdir/init.rc on startup.
287 final int HIDDEN_APP_MAX_ADJ;
288 static int HIDDEN_APP_MIN_ADJ;
289
The Android Open Source Project4df24232009-03-05 14:34:35 -0800290 // This is a process holding the home application -- we want to try
291 // avoiding killing it, even if it would normally be in the background,
292 // because the user interacts with it so much.
293 final int HOME_APP_ADJ;
294
Christopher Tate6fa95972009-06-05 18:43:55 -0700295 // This is a process currently hosting a backup operation. Killing it
296 // is not entirely fatal but is generally a bad idea.
297 final int BACKUP_APP_ADJ;
298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 // This is a process holding a secondary server -- killing it will not
300 // have much of an impact as far as the user is concerned. Value set in
301 // system/rootdir/init.rc on startup.
302 final int SECONDARY_SERVER_ADJ;
303
304 // This is a process only hosting activities that are visible to the
305 // user, so we'd prefer they don't disappear. Value set in
306 // system/rootdir/init.rc on startup.
307 final int VISIBLE_APP_ADJ;
308
309 // This is the process running the current foreground app. We'd really
310 // rather not kill it! Value set in system/rootdir/init.rc on startup.
311 final int FOREGROUND_APP_ADJ;
312
313 // This is a process running a core server, such as telephony. Definitely
314 // don't want to kill it, but doing so is not completely fatal.
315 static final int CORE_SERVER_ADJ = -12;
316
317 // The system process runs at the default adjustment.
318 static final int SYSTEM_ADJ = -16;
319
320 // Memory pages are 4K.
321 static final int PAGE_SIZE = 4*1024;
322
Jacek Surazski82a73df2009-06-17 14:33:18 +0200323 // System property defining error report receiver for system apps
324 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
325
326 // System property defining default error report receiver
327 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 // Corresponding memory levels for above adjustments.
330 final int EMPTY_APP_MEM;
331 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800332 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700333 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 final int SECONDARY_SERVER_MEM;
335 final int VISIBLE_APP_MEM;
336 final int FOREGROUND_APP_MEM;
337
338 final int MY_PID;
339
340 static final String[] EMPTY_STRING_ARRAY = new String[0];
341
342 enum ActivityState {
343 INITIALIZING,
344 RESUMED,
345 PAUSING,
346 PAUSED,
347 STOPPING,
348 STOPPED,
349 FINISHING,
350 DESTROYING,
351 DESTROYED
352 }
353
354 /**
355 * The back history of all previous (and possibly still
356 * running) activities. It contains HistoryRecord objects.
357 */
358 final ArrayList mHistory = new ArrayList();
359
360 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700361 * Description of a request to start a new activity, which has been held
362 * due to app switches being disabled.
363 */
364 class PendingActivityLaunch {
365 HistoryRecord r;
366 HistoryRecord sourceRecord;
367 Uri[] grantedUriPermissions;
368 int grantedMode;
369 boolean onlyIfNeeded;
370 }
371
372 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
373 = new ArrayList<PendingActivityLaunch>();
374
375 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 * List of all active broadcasts that are to be executed immediately
377 * (without waiting for another broadcast to finish). Currently this only
378 * contains broadcasts to registered receivers, to avoid spinning up
379 * a bunch of processes to execute IntentReceiver components.
380 */
381 final ArrayList<BroadcastRecord> mParallelBroadcasts
382 = new ArrayList<BroadcastRecord>();
383
384 /**
385 * List of all active broadcasts that are to be executed one at a time.
386 * The object at the top of the list is the currently activity broadcasts;
387 * those after it are waiting for the top to finish..
388 */
389 final ArrayList<BroadcastRecord> mOrderedBroadcasts
390 = new ArrayList<BroadcastRecord>();
391
392 /**
393 * Set when we current have a BROADCAST_INTENT_MSG in flight.
394 */
395 boolean mBroadcastsScheduled = false;
396
397 /**
398 * Set to indicate whether to issue an onUserLeaving callback when a
399 * newly launched activity is being brought in front of us.
400 */
401 boolean mUserLeaving = false;
402
403 /**
404 * When we are in the process of pausing an activity, before starting the
405 * next one, this variable holds the activity that is currently being paused.
406 */
407 HistoryRecord mPausingActivity = null;
408
409 /**
410 * Current activity that is resumed, or null if there is none.
411 */
412 HistoryRecord mResumedActivity = null;
413
414 /**
415 * Activity we have told the window manager to have key focus.
416 */
417 HistoryRecord mFocusedActivity = null;
418
419 /**
420 * This is the last activity that we put into the paused state. This is
421 * used to determine if we need to do an activity transition while sleeping,
422 * when we normally hold the top activity paused.
423 */
424 HistoryRecord mLastPausedActivity = null;
425
426 /**
427 * List of activities that are waiting for a new activity
428 * to become visible before completing whatever operation they are
429 * supposed to do.
430 */
431 final ArrayList mWaitingVisibleActivities = new ArrayList();
432
433 /**
434 * List of activities that are ready to be stopped, but waiting
435 * for the next activity to settle down before doing so. It contains
436 * HistoryRecord objects.
437 */
438 final ArrayList<HistoryRecord> mStoppingActivities
439 = new ArrayList<HistoryRecord>();
440
441 /**
442 * List of intents that were used to start the most recent tasks.
443 */
444 final ArrayList<TaskRecord> mRecentTasks
445 = new ArrayList<TaskRecord>();
446
447 /**
448 * List of activities that are ready to be finished, but waiting
449 * for the previous activity to settle down before doing so. It contains
450 * HistoryRecord objects.
451 */
452 final ArrayList mFinishingActivities = new ArrayList();
453
454 /**
455 * All of the applications we currently have running organized by name.
456 * The keys are strings of the application package name (as
457 * returned by the package manager), and the keys are ApplicationRecord
458 * objects.
459 */
460 final ProcessMap<ProcessRecord> mProcessNames
461 = new ProcessMap<ProcessRecord>();
462
463 /**
464 * The last time that various processes have crashed.
465 */
466 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
467
468 /**
469 * Set of applications that we consider to be bad, and will reject
470 * incoming broadcasts from (which the user has no control over).
471 * Processes are added to this set when they have crashed twice within
472 * a minimum amount of time; they are removed from it when they are
473 * later restarted (hopefully due to some user action). The value is the
474 * time it was added to the list.
475 */
476 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
477
478 /**
479 * All of the processes we currently have running organized by pid.
480 * The keys are the pid running the application.
481 *
482 * <p>NOTE: This object is protected by its own lock, NOT the global
483 * activity manager lock!
484 */
485 final SparseArray<ProcessRecord> mPidsSelfLocked
486 = new SparseArray<ProcessRecord>();
487
488 /**
489 * All of the processes that have been forced to be foreground. The key
490 * is the pid of the caller who requested it (we hold a death
491 * link on it).
492 */
493 abstract class ForegroundToken implements IBinder.DeathRecipient {
494 int pid;
495 IBinder token;
496 }
497 final SparseArray<ForegroundToken> mForegroundProcesses
498 = new SparseArray<ForegroundToken>();
499
500 /**
501 * List of records for processes that someone had tried to start before the
502 * system was ready. We don't start them at that point, but ensure they
503 * are started by the time booting is complete.
504 */
505 final ArrayList<ProcessRecord> mProcessesOnHold
506 = new ArrayList<ProcessRecord>();
507
508 /**
509 * List of records for processes that we have started and are waiting
510 * for them to call back. This is really only needed when running in
511 * single processes mode, in which case we do not have a unique pid for
512 * each process.
513 */
514 final ArrayList<ProcessRecord> mStartingProcesses
515 = new ArrayList<ProcessRecord>();
516
517 /**
518 * List of persistent applications that are in the process
519 * of being started.
520 */
521 final ArrayList<ProcessRecord> mPersistentStartingProcesses
522 = new ArrayList<ProcessRecord>();
523
524 /**
525 * Processes that are being forcibly torn down.
526 */
527 final ArrayList<ProcessRecord> mRemovedProcesses
528 = new ArrayList<ProcessRecord>();
529
530 /**
531 * List of running applications, sorted by recent usage.
532 * The first entry in the list is the least recently used.
533 * It contains ApplicationRecord objects. This list does NOT include
534 * any persistent application records (since we never want to exit them).
535 */
536 final ArrayList<ProcessRecord> mLRUProcesses
537 = new ArrayList<ProcessRecord>();
538
539 /**
540 * List of processes that should gc as soon as things are idle.
541 */
542 final ArrayList<ProcessRecord> mProcessesToGc
543 = new ArrayList<ProcessRecord>();
544
545 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800546 * This is the process holding what we currently consider to be
547 * the "home" activity.
548 */
549 private ProcessRecord mHomeProcess;
550
551 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 * List of running activities, sorted by recent usage.
553 * The first entry in the list is the least recently used.
554 * It contains HistoryRecord objects.
555 */
556 private final ArrayList mLRUActivities = new ArrayList();
557
558 /**
559 * Set of PendingResultRecord objects that are currently active.
560 */
561 final HashSet mPendingResultRecords = new HashSet();
562
563 /**
564 * Set of IntentSenderRecord objects that are currently active.
565 */
566 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
567 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
568
569 /**
570 * Intent broadcast that we have tried to start, but are
571 * waiting for its application's process to be created. We only
572 * need one (instead of a list) because we always process broadcasts
573 * one at a time, so no others can be started while waiting for this
574 * one.
575 */
576 BroadcastRecord mPendingBroadcast = null;
577
578 /**
579 * Keeps track of all IIntentReceivers that have been registered for
580 * broadcasts. Hash keys are the receiver IBinder, hash value is
581 * a ReceiverList.
582 */
583 final HashMap mRegisteredReceivers = new HashMap();
584
585 /**
586 * Resolver for broadcast intents to registered receivers.
587 * Holds BroadcastFilter (subclass of IntentFilter).
588 */
589 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
590 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
591 @Override
592 protected boolean allowFilterResult(
593 BroadcastFilter filter, List<BroadcastFilter> dest) {
594 IBinder target = filter.receiverList.receiver.asBinder();
595 for (int i=dest.size()-1; i>=0; i--) {
596 if (dest.get(i).receiverList.receiver.asBinder() == target) {
597 return false;
598 }
599 }
600 return true;
601 }
602 };
603
604 /**
605 * State of all active sticky broadcasts. Keys are the action of the
606 * sticky Intent, values are an ArrayList of all broadcasted intents with
607 * that action (which should usually be one).
608 */
609 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
610 new HashMap<String, ArrayList<Intent>>();
611
612 /**
613 * All currently running services.
614 */
615 final HashMap<ComponentName, ServiceRecord> mServices =
616 new HashMap<ComponentName, ServiceRecord>();
617
618 /**
619 * All currently running services indexed by the Intent used to start them.
620 */
621 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
622 new HashMap<Intent.FilterComparison, ServiceRecord>();
623
624 /**
625 * All currently bound service connections. Keys are the IBinder of
626 * the client's IServiceConnection.
627 */
628 final HashMap<IBinder, ConnectionRecord> mServiceConnections
629 = new HashMap<IBinder, ConnectionRecord>();
630
631 /**
632 * List of services that we have been asked to start,
633 * but haven't yet been able to. It is used to hold start requests
634 * while waiting for their corresponding application thread to get
635 * going.
636 */
637 final ArrayList<ServiceRecord> mPendingServices
638 = new ArrayList<ServiceRecord>();
639
640 /**
641 * List of services that are scheduled to restart following a crash.
642 */
643 final ArrayList<ServiceRecord> mRestartingServices
644 = new ArrayList<ServiceRecord>();
645
646 /**
647 * List of services that are in the process of being stopped.
648 */
649 final ArrayList<ServiceRecord> mStoppingServices
650 = new ArrayList<ServiceRecord>();
651
652 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700653 * Backup/restore process management
654 */
655 String mBackupAppName = null;
656 BackupRecord mBackupTarget = null;
657
658 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 * List of PendingThumbnailsRecord objects of clients who are still
660 * waiting to receive all of the thumbnails for a task.
661 */
662 final ArrayList mPendingThumbnails = new ArrayList();
663
664 /**
665 * List of HistoryRecord objects that have been finished and must
666 * still report back to a pending thumbnail receiver.
667 */
668 final ArrayList mCancelledThumbnails = new ArrayList();
669
670 /**
671 * All of the currently running global content providers. Keys are a
672 * string containing the provider name and values are a
673 * ContentProviderRecord object containing the data about it. Note
674 * that a single provider may be published under multiple names, so
675 * there may be multiple entries here for a single one in mProvidersByClass.
676 */
677 final HashMap mProvidersByName = new HashMap();
678
679 /**
680 * All of the currently running global content providers. Keys are a
681 * string containing the provider's implementation class and values are a
682 * ContentProviderRecord object containing the data about it.
683 */
684 final HashMap mProvidersByClass = new HashMap();
685
686 /**
687 * List of content providers who have clients waiting for them. The
688 * application is currently being launched and the provider will be
689 * removed from this list once it is published.
690 */
691 final ArrayList mLaunchingProviders = new ArrayList();
692
693 /**
694 * Global set of specific Uri permissions that have been granted.
695 */
696 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
697 = new SparseArray<HashMap<Uri, UriPermission>>();
698
699 /**
700 * Thread-local storage used to carry caller permissions over through
701 * indirect content-provider access.
702 * @see #ActivityManagerService.openContentUri()
703 */
704 private class Identity {
705 public int pid;
706 public int uid;
707
708 Identity(int _pid, int _uid) {
709 pid = _pid;
710 uid = _uid;
711 }
712 }
713 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
714
715 /**
716 * All information we have collected about the runtime performance of
717 * any user id that can impact battery performance.
718 */
719 final BatteryStatsService mBatteryStatsService;
720
721 /**
722 * information about component usage
723 */
724 final UsageStatsService mUsageStatsService;
725
726 /**
727 * Current configuration information. HistoryRecord objects are given
728 * a reference to this object to indicate which configuration they are
729 * currently running in, so this object must be kept immutable.
730 */
731 Configuration mConfiguration = new Configuration();
732
733 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700734 * Hardware-reported OpenGLES version.
735 */
736 final int GL_ES_VERSION;
737
738 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 * List of initialization arguments to pass to all processes when binding applications to them.
740 * For example, references to the commonly used services.
741 */
742 HashMap<String, IBinder> mAppBindArgs;
743
744 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700745 * Temporary to avoid allocations. Protected by main lock.
746 */
747 final StringBuilder mStringBuilder = new StringBuilder(256);
748
749 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 * Used to control how we initialize the service.
751 */
752 boolean mStartRunning = false;
753 ComponentName mTopComponent;
754 String mTopAction;
755 String mTopData;
756 boolean mSystemReady = false;
757 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700758 boolean mWaitingUpdate = false;
759 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760
761 Context mContext;
762
763 int mFactoryTest;
764
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700765 boolean mCheckedForSetup;
766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700768 * The time at which we will allow normal application switches again,
769 * after a call to {@link #stopAppSwitches()}.
770 */
771 long mAppSwitchesAllowedTime;
772
773 /**
774 * This is set to true after the first switch after mAppSwitchesAllowedTime
775 * is set; any switches after that will clear the time.
776 */
777 boolean mDidAppSwitch;
778
779 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 * Set while we are wanting to sleep, to prevent any
781 * activities from being started/resumed.
782 */
783 boolean mSleeping = false;
784
785 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700786 * Set if we are shutting down the system, similar to sleeping.
787 */
788 boolean mShuttingDown = false;
789
790 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 * Set when the system is going to sleep, until we have
792 * successfully paused the current activity and released our wake lock.
793 * At that point the system is allowed to actually sleep.
794 */
795 PowerManager.WakeLock mGoingToSleep;
796
797 /**
798 * We don't want to allow the device to go to sleep while in the process
799 * of launching an activity. This is primarily to allow alarm intent
800 * receivers to launch an activity and get that to run before the device
801 * goes back to sleep.
802 */
803 PowerManager.WakeLock mLaunchingActivity;
804
805 /**
806 * Task identifier that activities are currently being started
807 * in. Incremented each time a new task is created.
808 * todo: Replace this with a TokenSpace class that generates non-repeating
809 * integers that won't wrap.
810 */
811 int mCurTask = 1;
812
813 /**
814 * Current sequence id for oom_adj computation traversal.
815 */
816 int mAdjSeq = 0;
817
818 /**
819 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
820 * is set, indicating the user wants processes started in such a way
821 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
822 * running in each process (thus no pre-initialized process, etc).
823 */
824 boolean mSimpleProcessManagement = false;
825
826 /**
827 * System monitoring: number of processes that died since the last
828 * N procs were started.
829 */
830 int[] mProcDeaths = new int[20];
831
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700832 /**
833 * This is set if we had to do a delayed dexopt of an app before launching
834 * it, to increasing the ANR timeouts in that case.
835 */
836 boolean mDidDexOpt;
837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 String mDebugApp = null;
839 boolean mWaitForDebugger = false;
840 boolean mDebugTransient = false;
841 String mOrigDebugApp = null;
842 boolean mOrigWaitForDebugger = false;
843 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700844 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700846 final RemoteCallbackList<IActivityWatcher> mWatchers
847 = new RemoteCallbackList<IActivityWatcher>();
848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 /**
850 * Callback of last caller to {@link #requestPss}.
851 */
852 Runnable mRequestPssCallback;
853
854 /**
855 * Remaining processes for which we are waiting results from the last
856 * call to {@link #requestPss}.
857 */
858 final ArrayList<ProcessRecord> mRequestPssList
859 = new ArrayList<ProcessRecord>();
860
861 /**
862 * Runtime statistics collection thread. This object's lock is used to
863 * protect all related state.
864 */
865 final Thread mProcessStatsThread;
866
867 /**
868 * Used to collect process stats when showing not responding dialog.
869 * Protected by mProcessStatsThread.
870 */
871 final ProcessStats mProcessStats = new ProcessStats(
872 MONITOR_THREAD_CPU_USAGE);
873 long mLastCpuTime = 0;
874 long mLastWriteTime = 0;
875
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700876 long mInitialStartTime = 0;
877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 /**
879 * Set to true after the system has finished booting.
880 */
881 boolean mBooted = false;
882
883 int mProcessLimit = 0;
884
885 WindowManagerService mWindowManager;
886
887 static ActivityManagerService mSelf;
888 static ActivityThread mSystemThread;
889
890 private final class AppDeathRecipient implements IBinder.DeathRecipient {
891 final ProcessRecord mApp;
892 final int mPid;
893 final IApplicationThread mAppThread;
894
895 AppDeathRecipient(ProcessRecord app, int pid,
896 IApplicationThread thread) {
897 if (localLOGV) Log.v(
898 TAG, "New death recipient " + this
899 + " for thread " + thread.asBinder());
900 mApp = app;
901 mPid = pid;
902 mAppThread = thread;
903 }
904
905 public void binderDied() {
906 if (localLOGV) Log.v(
907 TAG, "Death received in " + this
908 + " for thread " + mAppThread.asBinder());
909 removeRequestedPss(mApp);
910 synchronized(ActivityManagerService.this) {
911 appDiedLocked(mApp, mPid, mAppThread);
912 }
913 }
914 }
915
916 static final int SHOW_ERROR_MSG = 1;
917 static final int SHOW_NOT_RESPONDING_MSG = 2;
918 static final int SHOW_FACTORY_ERROR_MSG = 3;
919 static final int UPDATE_CONFIGURATION_MSG = 4;
920 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
921 static final int WAIT_FOR_DEBUGGER_MSG = 6;
922 static final int BROADCAST_INTENT_MSG = 7;
923 static final int BROADCAST_TIMEOUT_MSG = 8;
924 static final int PAUSE_TIMEOUT_MSG = 9;
925 static final int IDLE_TIMEOUT_MSG = 10;
926 static final int IDLE_NOW_MSG = 11;
927 static final int SERVICE_TIMEOUT_MSG = 12;
928 static final int UPDATE_TIME_ZONE = 13;
929 static final int SHOW_UID_ERROR_MSG = 14;
930 static final int IM_FEELING_LUCKY_MSG = 15;
931 static final int LAUNCH_TIMEOUT_MSG = 16;
932 static final int DESTROY_TIMEOUT_MSG = 17;
933 static final int SERVICE_ERROR_MSG = 18;
934 static final int RESUME_TOP_ACTIVITY_MSG = 19;
935 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700936 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700937 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938
939 AlertDialog mUidAlert;
940
941 final Handler mHandler = new Handler() {
942 //public Handler() {
943 // if (localLOGV) Log.v(TAG, "Handler started!");
944 //}
945
946 public void handleMessage(Message msg) {
947 switch (msg.what) {
948 case SHOW_ERROR_MSG: {
949 HashMap data = (HashMap) msg.obj;
950 byte[] crashData = (byte[])data.get("crashData");
951 if (crashData != null) {
952 // This needs to be *un*synchronized to avoid deadlock.
953 ContentResolver resolver = mContext.getContentResolver();
954 Checkin.reportCrash(resolver, crashData);
955 }
956 synchronized (ActivityManagerService.this) {
957 ProcessRecord proc = (ProcessRecord)data.get("app");
958 if (proc != null && proc.crashDialog != null) {
959 Log.e(TAG, "App already has crash dialog: " + proc);
960 return;
961 }
962 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700963 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 Dialog d = new AppErrorDialog(
965 mContext, res, proc,
966 (Integer)data.get("flags"),
967 (String)data.get("shortMsg"),
968 (String)data.get("longMsg"));
969 d.show();
970 proc.crashDialog = d;
971 } else {
972 // The device is asleep, so just pretend that the user
973 // saw a crash dialog and hit "force quit".
974 res.set(0);
975 }
976 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700977
978 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 } break;
980 case SHOW_NOT_RESPONDING_MSG: {
981 synchronized (ActivityManagerService.this) {
982 HashMap data = (HashMap) msg.obj;
983 ProcessRecord proc = (ProcessRecord)data.get("app");
984 if (proc != null && proc.anrDialog != null) {
985 Log.e(TAG, "App already has anr dialog: " + proc);
986 return;
987 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800988
989 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
990 null, null, 0, null, null, null,
991 false, false, MY_PID, Process.SYSTEM_UID);
992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
994 mContext, proc, (HistoryRecord)data.get("activity"));
995 d.show();
996 proc.anrDialog = d;
997 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700998
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700999 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 } break;
1001 case SHOW_FACTORY_ERROR_MSG: {
1002 Dialog d = new FactoryErrorDialog(
1003 mContext, msg.getData().getCharSequence("msg"));
1004 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001005 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 } break;
1007 case UPDATE_CONFIGURATION_MSG: {
1008 final ContentResolver resolver = mContext.getContentResolver();
1009 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1010 } break;
1011 case GC_BACKGROUND_PROCESSES_MSG: {
1012 synchronized (ActivityManagerService.this) {
1013 performAppGcsIfAppropriateLocked();
1014 }
1015 } break;
1016 case WAIT_FOR_DEBUGGER_MSG: {
1017 synchronized (ActivityManagerService.this) {
1018 ProcessRecord app = (ProcessRecord)msg.obj;
1019 if (msg.arg1 != 0) {
1020 if (!app.waitedForDebugger) {
1021 Dialog d = new AppWaitingForDebuggerDialog(
1022 ActivityManagerService.this,
1023 mContext, app);
1024 app.waitDialog = d;
1025 app.waitedForDebugger = true;
1026 d.show();
1027 }
1028 } else {
1029 if (app.waitDialog != null) {
1030 app.waitDialog.dismiss();
1031 app.waitDialog = null;
1032 }
1033 }
1034 }
1035 } break;
1036 case BROADCAST_INTENT_MSG: {
1037 if (DEBUG_BROADCAST) Log.v(
1038 TAG, "Received BROADCAST_INTENT_MSG");
1039 processNextBroadcast(true);
1040 } break;
1041 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001042 if (mDidDexOpt) {
1043 mDidDexOpt = false;
1044 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1045 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1046 return;
1047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 broadcastTimeout();
1049 } break;
1050 case PAUSE_TIMEOUT_MSG: {
1051 IBinder token = (IBinder)msg.obj;
1052 // We don't at this point know if the activity is fullscreen,
1053 // so we need to be conservative and assume it isn't.
1054 Log.w(TAG, "Activity pause timeout for " + token);
1055 activityPaused(token, null, true);
1056 } break;
1057 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001058 if (mDidDexOpt) {
1059 mDidDexOpt = false;
1060 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1061 nmsg.obj = msg.obj;
1062 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1063 return;
1064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 // We don't at this point know if the activity is fullscreen,
1066 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001067 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 Log.w(TAG, "Activity idle timeout for " + token);
1069 activityIdleInternal(token, true);
1070 } break;
1071 case DESTROY_TIMEOUT_MSG: {
1072 IBinder token = (IBinder)msg.obj;
1073 // We don't at this point know if the activity is fullscreen,
1074 // so we need to be conservative and assume it isn't.
1075 Log.w(TAG, "Activity destroy timeout for " + token);
1076 activityDestroyed(token);
1077 } break;
1078 case IDLE_NOW_MSG: {
1079 IBinder token = (IBinder)msg.obj;
1080 activityIdle(token);
1081 } break;
1082 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001083 if (mDidDexOpt) {
1084 mDidDexOpt = false;
1085 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1086 nmsg.obj = msg.obj;
1087 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1088 return;
1089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 serviceTimeout((ProcessRecord)msg.obj);
1091 } break;
1092 case UPDATE_TIME_ZONE: {
1093 synchronized (ActivityManagerService.this) {
1094 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1095 ProcessRecord r = mLRUProcesses.get(i);
1096 if (r.thread != null) {
1097 try {
1098 r.thread.updateTimeZone();
1099 } catch (RemoteException ex) {
1100 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1101 }
1102 }
1103 }
1104 }
1105 break;
1106 }
1107 case SHOW_UID_ERROR_MSG: {
1108 // XXX This is a temporary dialog, no need to localize.
1109 AlertDialog d = new BaseErrorDialog(mContext);
1110 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1111 d.setCancelable(false);
1112 d.setTitle("System UIDs Inconsistent");
1113 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1114 d.setButton("I'm Feeling Lucky",
1115 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1116 mUidAlert = d;
1117 d.show();
1118 } break;
1119 case IM_FEELING_LUCKY_MSG: {
1120 if (mUidAlert != null) {
1121 mUidAlert.dismiss();
1122 mUidAlert = null;
1123 }
1124 } break;
1125 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001126 if (mDidDexOpt) {
1127 mDidDexOpt = false;
1128 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1129 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1130 return;
1131 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 synchronized (ActivityManagerService.this) {
1133 if (mLaunchingActivity.isHeld()) {
1134 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1135 mLaunchingActivity.release();
1136 }
1137 }
1138 } break;
1139 case SERVICE_ERROR_MSG: {
1140 ServiceRecord srv = (ServiceRecord)msg.obj;
1141 // This needs to be *un*synchronized to avoid deadlock.
1142 Checkin.logEvent(mContext.getContentResolver(),
1143 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1144 srv.name.toShortString());
1145 } break;
1146 case RESUME_TOP_ACTIVITY_MSG: {
1147 synchronized (ActivityManagerService.this) {
1148 resumeTopActivityLocked(null);
1149 }
1150 }
1151 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001152 if (mDidDexOpt) {
1153 mDidDexOpt = false;
1154 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1155 nmsg.obj = msg.obj;
1156 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1157 return;
1158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 ProcessRecord app = (ProcessRecord)msg.obj;
1160 synchronized (ActivityManagerService.this) {
1161 processStartTimedOutLocked(app);
1162 }
1163 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001164 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1165 synchronized (ActivityManagerService.this) {
1166 doPendingActivityLaunchesLocked(true);
1167 }
1168 }
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001169 case KILL_APPLICATION_MSG: {
1170 synchronized (ActivityManagerService.this) {
1171 int uid = msg.arg1;
1172 boolean restart = (msg.arg2 == 1);
1173 String pkg = (String) msg.obj;
1174 uninstallPackageLocked(pkg, uid, restart);
1175 }
1176 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 }
1178 }
1179 };
1180
1181 public static void setSystemProcess() {
1182 try {
1183 ActivityManagerService m = mSelf;
1184
1185 ServiceManager.addService("activity", m);
1186 ServiceManager.addService("meminfo", new MemBinder(m));
1187 if (MONITOR_CPU_USAGE) {
1188 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1189 }
1190 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1191 ServiceManager.addService("activity.services", new ServicesBinder(m));
1192 ServiceManager.addService("activity.senders", new SendersBinder(m));
1193 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1194 ServiceManager.addService("permission", new PermissionController(m));
1195
1196 ApplicationInfo info =
1197 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001198 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199 synchronized (mSelf) {
1200 ProcessRecord app = mSelf.newProcessRecordLocked(
1201 mSystemThread.getApplicationThread(), info,
1202 info.processName);
1203 app.persistent = true;
1204 app.pid = Process.myPid();
1205 app.maxAdj = SYSTEM_ADJ;
1206 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1207 synchronized (mSelf.mPidsSelfLocked) {
1208 mSelf.mPidsSelfLocked.put(app.pid, app);
1209 }
1210 mSelf.updateLRUListLocked(app, true);
1211 }
1212 } catch (PackageManager.NameNotFoundException e) {
1213 throw new RuntimeException(
1214 "Unable to find android system package", e);
1215 }
1216 }
1217
1218 public void setWindowManager(WindowManagerService wm) {
1219 mWindowManager = wm;
1220 }
1221
1222 public static final Context main(int factoryTest) {
1223 AThread thr = new AThread();
1224 thr.start();
1225
1226 synchronized (thr) {
1227 while (thr.mService == null) {
1228 try {
1229 thr.wait();
1230 } catch (InterruptedException e) {
1231 }
1232 }
1233 }
1234
1235 ActivityManagerService m = thr.mService;
1236 mSelf = m;
1237 ActivityThread at = ActivityThread.systemMain();
1238 mSystemThread = at;
1239 Context context = at.getSystemContext();
1240 m.mContext = context;
1241 m.mFactoryTest = factoryTest;
1242 PowerManager pm =
1243 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1244 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1245 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1246 m.mLaunchingActivity.setReferenceCounted(false);
1247
1248 m.mBatteryStatsService.publish(context);
1249 m.mUsageStatsService.publish(context);
1250
1251 synchronized (thr) {
1252 thr.mReady = true;
1253 thr.notifyAll();
1254 }
1255
1256 m.startRunning(null, null, null, null);
1257
1258 return context;
1259 }
1260
1261 public static ActivityManagerService self() {
1262 return mSelf;
1263 }
1264
1265 static class AThread extends Thread {
1266 ActivityManagerService mService;
1267 boolean mReady = false;
1268
1269 public AThread() {
1270 super("ActivityManager");
1271 }
1272
1273 public void run() {
1274 Looper.prepare();
1275
1276 android.os.Process.setThreadPriority(
1277 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1278
1279 ActivityManagerService m = new ActivityManagerService();
1280
1281 synchronized (this) {
1282 mService = m;
1283 notifyAll();
1284 }
1285
1286 synchronized (this) {
1287 while (!mReady) {
1288 try {
1289 wait();
1290 } catch (InterruptedException e) {
1291 }
1292 }
1293 }
1294
1295 Looper.loop();
1296 }
1297 }
1298
1299 static class BroadcastsBinder extends Binder {
1300 ActivityManagerService mActivityManagerService;
1301 BroadcastsBinder(ActivityManagerService activityManagerService) {
1302 mActivityManagerService = activityManagerService;
1303 }
1304
1305 @Override
1306 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1307 mActivityManagerService.dumpBroadcasts(pw);
1308 }
1309 }
1310
1311 static class ServicesBinder extends Binder {
1312 ActivityManagerService mActivityManagerService;
1313 ServicesBinder(ActivityManagerService activityManagerService) {
1314 mActivityManagerService = activityManagerService;
1315 }
1316
1317 @Override
1318 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1319 mActivityManagerService.dumpServices(pw);
1320 }
1321 }
1322
1323 static class SendersBinder extends Binder {
1324 ActivityManagerService mActivityManagerService;
1325 SendersBinder(ActivityManagerService activityManagerService) {
1326 mActivityManagerService = activityManagerService;
1327 }
1328
1329 @Override
1330 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1331 mActivityManagerService.dumpSenders(pw);
1332 }
1333 }
1334
1335 static class ProvidersBinder extends Binder {
1336 ActivityManagerService mActivityManagerService;
1337 ProvidersBinder(ActivityManagerService activityManagerService) {
1338 mActivityManagerService = activityManagerService;
1339 }
1340
1341 @Override
1342 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1343 mActivityManagerService.dumpProviders(pw);
1344 }
1345 }
1346
1347 static class MemBinder extends Binder {
1348 ActivityManagerService mActivityManagerService;
1349 MemBinder(ActivityManagerService activityManagerService) {
1350 mActivityManagerService = activityManagerService;
1351 }
1352
1353 @Override
1354 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1355 ActivityManagerService service = mActivityManagerService;
1356 ArrayList<ProcessRecord> procs;
1357 synchronized (mActivityManagerService) {
1358 if (args != null && args.length > 0
1359 && args[0].charAt(0) != '-') {
1360 procs = new ArrayList<ProcessRecord>();
1361 int pid = -1;
1362 try {
1363 pid = Integer.parseInt(args[0]);
1364 } catch (NumberFormatException e) {
1365
1366 }
1367 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1368 ProcessRecord proc = service.mLRUProcesses.get(i);
1369 if (proc.pid == pid) {
1370 procs.add(proc);
1371 } else if (proc.processName.equals(args[0])) {
1372 procs.add(proc);
1373 }
1374 }
1375 if (procs.size() <= 0) {
1376 pw.println("No process found for: " + args[0]);
1377 return;
1378 }
1379 } else {
1380 procs = service.mLRUProcesses;
1381 }
1382 }
1383 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1384 }
1385 }
1386
1387 static class CpuBinder extends Binder {
1388 ActivityManagerService mActivityManagerService;
1389 CpuBinder(ActivityManagerService activityManagerService) {
1390 mActivityManagerService = activityManagerService;
1391 }
1392
1393 @Override
1394 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1395 synchronized (mActivityManagerService.mProcessStatsThread) {
1396 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1397 }
1398 }
1399 }
1400
1401 private ActivityManagerService() {
1402 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1403 if (v != null && Integer.getInteger(v) != 0) {
1404 mSimpleProcessManagement = true;
1405 }
1406 v = System.getenv("ANDROID_DEBUG_APP");
1407 if (v != null) {
1408 mSimpleProcessManagement = true;
1409 }
1410
1411 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
1547 EventLog.writeEvent(LOG_CPU,
1548 ((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 Yamasani819f9282009-06-24 23:18:15 -07001557 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001558 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 synchronized(mPidsSelfLocked) {
1560 if (haveNewCpuStats) {
1561 if (mBatteryStatsService.isOnBattery()) {
1562 final int N = mProcessStats.countWorkingStats();
1563 for (int i=0; i<N; i++) {
1564 ProcessStats.Stats st
1565 = mProcessStats.getWorkingStats(i);
1566 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1567 if (pr != null) {
1568 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1569 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001570 } else {
1571 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001572 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001573 if (ps != null) {
1574 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 }
1577 }
1578 }
1579 }
1580 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1583 mLastWriteTime = now;
1584 mBatteryStatsService.getActiveStatistics().writeLocked();
1585 }
1586 }
1587 }
1588 }
1589
1590 /**
1591 * Initialize the application bind args. These are passed to each
1592 * process when the bindApplication() IPC is sent to the process. They're
1593 * lazily setup to make sure the services are running when they're asked for.
1594 */
1595 private HashMap<String, IBinder> getCommonServicesLocked() {
1596 if (mAppBindArgs == null) {
1597 mAppBindArgs = new HashMap<String, IBinder>();
1598
1599 // Setup the application init args
1600 mAppBindArgs.put("package", ServiceManager.getService("package"));
1601 mAppBindArgs.put("window", ServiceManager.getService("window"));
1602 mAppBindArgs.put(Context.ALARM_SERVICE,
1603 ServiceManager.getService(Context.ALARM_SERVICE));
1604 }
1605 return mAppBindArgs;
1606 }
1607
1608 private final void setFocusedActivityLocked(HistoryRecord r) {
1609 if (mFocusedActivity != r) {
1610 mFocusedActivity = r;
1611 mWindowManager.setFocusedApp(r, true);
1612 }
1613 }
1614
1615 private final void updateLRUListLocked(ProcessRecord app,
1616 boolean oomAdj) {
1617 // put it on the LRU to keep track of when it should be exited.
1618 int lrui = mLRUProcesses.indexOf(app);
1619 if (lrui >= 0) mLRUProcesses.remove(lrui);
1620 mLRUProcesses.add(app);
1621 //Log.i(TAG, "Putting proc to front: " + app.processName);
1622 if (oomAdj) {
1623 updateOomAdjLocked();
1624 }
1625 }
1626
1627 private final boolean updateLRUListLocked(HistoryRecord r) {
1628 final boolean hadit = mLRUActivities.remove(r);
1629 mLRUActivities.add(r);
1630 return hadit;
1631 }
1632
1633 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1634 int i = mHistory.size()-1;
1635 while (i >= 0) {
1636 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1637 if (!r.finishing && r != notTop) {
1638 return r;
1639 }
1640 i--;
1641 }
1642 return null;
1643 }
1644
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001645 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1646 int i = mHistory.size()-1;
1647 while (i >= 0) {
1648 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1649 if (!r.finishing && !r.delayedResume && r != notTop) {
1650 return r;
1651 }
1652 i--;
1653 }
1654 return null;
1655 }
1656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 /**
1658 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001659 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 *
1661 * @param token If non-null, any history records matching this token will be skipped.
1662 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1663 *
1664 * @return Returns the HistoryRecord of the next activity on the stack.
1665 */
1666 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1667 int i = mHistory.size()-1;
1668 while (i >= 0) {
1669 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1670 // Note: the taskId check depends on real taskId fields being non-zero
1671 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1672 return r;
1673 }
1674 i--;
1675 }
1676 return null;
1677 }
1678
1679 private final ProcessRecord getProcessRecordLocked(
1680 String processName, int uid) {
1681 if (uid == Process.SYSTEM_UID) {
1682 // The system gets to run in any process. If there are multiple
1683 // processes with the same uid, just pick the first (this
1684 // should never happen).
1685 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1686 processName);
1687 return procs != null ? procs.valueAt(0) : null;
1688 }
1689 ProcessRecord proc = mProcessNames.get(processName, uid);
1690 return proc;
1691 }
1692
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001693 private void ensurePackageDexOpt(String packageName) {
1694 IPackageManager pm = ActivityThread.getPackageManager();
1695 try {
1696 if (pm.performDexOpt(packageName)) {
1697 mDidDexOpt = true;
1698 }
1699 } catch (RemoteException e) {
1700 }
1701 }
1702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 private boolean isNextTransitionForward() {
1704 int transit = mWindowManager.getPendingAppTransition();
1705 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1706 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1707 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1708 }
1709
1710 private final boolean realStartActivityLocked(HistoryRecord r,
1711 ProcessRecord app, boolean andResume, boolean checkConfig)
1712 throws RemoteException {
1713
1714 r.startFreezingScreenLocked(app, 0);
1715 mWindowManager.setAppVisibility(r, true);
1716
1717 // Have the window manager re-evaluate the orientation of
1718 // the screen based on the new activity order. Note that
1719 // as a result of this, it can call back into the activity
1720 // manager with a new orientation. We don't care about that,
1721 // because the activity is not currently running so we are
1722 // just restarting it anyway.
1723 if (checkConfig) {
1724 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001725 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 r.mayFreezeScreenLocked(app) ? r : null);
1727 updateConfigurationLocked(config, r);
1728 }
1729
1730 r.app = app;
1731
1732 if (localLOGV) Log.v(TAG, "Launching: " + r);
1733
1734 int idx = app.activities.indexOf(r);
1735 if (idx < 0) {
1736 app.activities.add(r);
1737 }
1738 updateLRUListLocked(app, true);
1739
1740 try {
1741 if (app.thread == null) {
1742 throw new RemoteException();
1743 }
1744 List<ResultInfo> results = null;
1745 List<Intent> newIntents = null;
1746 if (andResume) {
1747 results = r.results;
1748 newIntents = r.newIntents;
1749 }
1750 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1751 + " icicle=" + r.icicle
1752 + " with results=" + results + " newIntents=" + newIntents
1753 + " andResume=" + andResume);
1754 if (andResume) {
1755 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1756 System.identityHashCode(r),
1757 r.task.taskId, r.shortComponentName);
1758 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001759 if (r.isHomeActivity) {
1760 mHomeProcess = app;
1761 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001762 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001764 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 r.info, r.icicle, results, newIntents, !andResume,
1766 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 } catch (RemoteException e) {
1768 if (r.launchFailed) {
1769 // This is the second time we failed -- finish activity
1770 // and give up.
1771 Log.e(TAG, "Second failure launching "
1772 + r.intent.getComponent().flattenToShortString()
1773 + ", giving up", e);
1774 appDiedLocked(app, app.pid, app.thread);
1775 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1776 "2nd-crash");
1777 return false;
1778 }
1779
1780 // This is the first time we failed -- restart process and
1781 // retry.
1782 app.activities.remove(r);
1783 throw e;
1784 }
1785
1786 r.launchFailed = false;
1787 if (updateLRUListLocked(r)) {
1788 Log.w(TAG, "Activity " + r
1789 + " being launched, but already in LRU list");
1790 }
1791
1792 if (andResume) {
1793 // As part of the process of launching, ActivityThread also performs
1794 // a resume.
1795 r.state = ActivityState.RESUMED;
1796 r.icicle = null;
1797 r.haveState = false;
1798 r.stopped = false;
1799 mResumedActivity = r;
1800 r.task.touchActiveTime();
1801 completeResumeLocked(r);
1802 pauseIfSleepingLocked();
1803 } else {
1804 // This activity is not starting in the resumed state... which
1805 // should look like we asked it to pause+stop (but remain visible),
1806 // and it has done so and reported back the current icicle and
1807 // other state.
1808 r.state = ActivityState.STOPPED;
1809 r.stopped = true;
1810 }
1811
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001812 // Launch the new version setup screen if needed. We do this -after-
1813 // launching the initial activity (that is, home), so that it can have
1814 // a chance to initialize itself while in the background, making the
1815 // switch back to it faster and look better.
1816 startSetupActivityLocked();
1817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 return true;
1819 }
1820
1821 private final void startSpecificActivityLocked(HistoryRecord r,
1822 boolean andResume, boolean checkConfig) {
1823 // Is this activity's application already running?
1824 ProcessRecord app = getProcessRecordLocked(r.processName,
1825 r.info.applicationInfo.uid);
1826
1827 if (r.startTime == 0) {
1828 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001829 if (mInitialStartTime == 0) {
1830 mInitialStartTime = r.startTime;
1831 }
1832 } else if (mInitialStartTime == 0) {
1833 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
1835
1836 if (app != null && app.thread != null) {
1837 try {
1838 realStartActivityLocked(r, app, andResume, checkConfig);
1839 return;
1840 } catch (RemoteException e) {
1841 Log.w(TAG, "Exception when starting activity "
1842 + r.intent.getComponent().flattenToShortString(), e);
1843 }
1844
1845 // If a dead object exception was thrown -- fall through to
1846 // restart the application.
1847 }
1848
1849 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001850 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 }
1852
1853 private final ProcessRecord startProcessLocked(String processName,
1854 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001855 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1857 // We don't have to do anything more if:
1858 // (1) There is an existing application record; and
1859 // (2) The caller doesn't think it is dead, OR there is no thread
1860 // object attached to it so we know it couldn't have crashed; and
1861 // (3) There is a pid assigned to it, so it is either starting or
1862 // already running.
1863 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1864 + " app=" + app + " knownToBeDead=" + knownToBeDead
1865 + " thread=" + (app != null ? app.thread : null)
1866 + " pid=" + (app != null ? app.pid : -1));
1867 if (app != null &&
1868 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1869 return app;
1870 }
1871
1872 String hostingNameStr = hostingName != null
1873 ? hostingName.flattenToShortString() : null;
1874
1875 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1876 // If we are in the background, then check to see if this process
1877 // is bad. If so, we will just silently fail.
1878 if (mBadProcesses.get(info.processName, info.uid) != null) {
1879 return null;
1880 }
1881 } else {
1882 // When the user is explicitly starting a process, then clear its
1883 // crash count so that we won't make it bad until they see at
1884 // least one crash dialog again, and make the process good again
1885 // if it had been bad.
1886 mProcessCrashTimes.remove(info.processName, info.uid);
1887 if (mBadProcesses.get(info.processName, info.uid) != null) {
1888 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1889 info.processName);
1890 mBadProcesses.remove(info.processName, info.uid);
1891 if (app != null) {
1892 app.bad = false;
1893 }
1894 }
1895 }
1896
1897 if (app == null) {
1898 app = newProcessRecordLocked(null, info, processName);
1899 mProcessNames.put(processName, info.uid, app);
1900 } else {
1901 // If this is a new package in the process, add the package to the list
1902 app.addPackage(info.packageName);
1903 }
1904
1905 // If the system is not ready yet, then hold off on starting this
1906 // process until it is.
1907 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001908 && !isAllowedWhileBooting(info)
1909 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 if (!mProcessesOnHold.contains(app)) {
1911 mProcessesOnHold.add(app);
1912 }
1913 return app;
1914 }
1915
1916 startProcessLocked(app, hostingType, hostingNameStr);
1917 return (app.pid != 0) ? app : null;
1918 }
1919
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001920 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1921 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1922 }
1923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 private final void startProcessLocked(ProcessRecord app,
1925 String hostingType, String hostingNameStr) {
1926 if (app.pid > 0 && app.pid != MY_PID) {
1927 synchronized (mPidsSelfLocked) {
1928 mPidsSelfLocked.remove(app.pid);
1929 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1930 }
1931 app.pid = 0;
1932 }
1933
1934 mProcessesOnHold.remove(app);
1935
1936 updateCpuStats();
1937
1938 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1939 mProcDeaths[0] = 0;
1940
1941 try {
1942 int uid = app.info.uid;
1943 int[] gids = null;
1944 try {
1945 gids = mContext.getPackageManager().getPackageGids(
1946 app.info.packageName);
1947 } catch (PackageManager.NameNotFoundException e) {
1948 Log.w(TAG, "Unable to retrieve gids", e);
1949 }
1950 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1951 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1952 && mTopComponent != null
1953 && app.processName.equals(mTopComponent.getPackageName())) {
1954 uid = 0;
1955 }
1956 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1957 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1958 uid = 0;
1959 }
1960 }
1961 int debugFlags = 0;
1962 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1963 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1964 }
1965 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1966 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1967 }
1968 if ("1".equals(SystemProperties.get("debug.assert"))) {
1969 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1970 }
1971 int pid = Process.start("android.app.ActivityThread",
1972 mSimpleProcessManagement ? app.processName : null, uid, uid,
1973 gids, debugFlags, null);
1974 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1975 synchronized (bs) {
1976 if (bs.isOnBattery()) {
1977 app.batteryStats.incStartsLocked();
1978 }
1979 }
1980
1981 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1982 app.processName, hostingType,
1983 hostingNameStr != null ? hostingNameStr : "");
1984
1985 if (app.persistent) {
1986 Watchdog.getInstance().processStarted(app, app.processName, pid);
1987 }
1988
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001989 StringBuilder buf = mStringBuilder;
1990 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 buf.append("Start proc ");
1992 buf.append(app.processName);
1993 buf.append(" for ");
1994 buf.append(hostingType);
1995 if (hostingNameStr != null) {
1996 buf.append(" ");
1997 buf.append(hostingNameStr);
1998 }
1999 buf.append(": pid=");
2000 buf.append(pid);
2001 buf.append(" uid=");
2002 buf.append(uid);
2003 buf.append(" gids={");
2004 if (gids != null) {
2005 for (int gi=0; gi<gids.length; gi++) {
2006 if (gi != 0) buf.append(", ");
2007 buf.append(gids[gi]);
2008
2009 }
2010 }
2011 buf.append("}");
2012 Log.i(TAG, buf.toString());
2013 if (pid == 0 || pid == MY_PID) {
2014 // Processes are being emulated with threads.
2015 app.pid = MY_PID;
2016 app.removed = false;
2017 mStartingProcesses.add(app);
2018 } else if (pid > 0) {
2019 app.pid = pid;
2020 app.removed = false;
2021 synchronized (mPidsSelfLocked) {
2022 this.mPidsSelfLocked.put(pid, app);
2023 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2024 msg.obj = app;
2025 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2026 }
2027 } else {
2028 app.pid = 0;
2029 RuntimeException e = new RuntimeException(
2030 "Failure starting process " + app.processName
2031 + ": returned pid=" + pid);
2032 Log.e(TAG, e.getMessage(), e);
2033 }
2034 } catch (RuntimeException e) {
2035 // XXX do better error recovery.
2036 app.pid = 0;
2037 Log.e(TAG, "Failure starting process " + app.processName, e);
2038 }
2039 }
2040
2041 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2042 if (mPausingActivity != null) {
2043 RuntimeException e = new RuntimeException();
2044 Log.e(TAG, "Trying to pause when pause is already pending for "
2045 + mPausingActivity, e);
2046 }
2047 HistoryRecord prev = mResumedActivity;
2048 if (prev == null) {
2049 RuntimeException e = new RuntimeException();
2050 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2051 resumeTopActivityLocked(null);
2052 return;
2053 }
2054 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2055 mResumedActivity = null;
2056 mPausingActivity = prev;
2057 mLastPausedActivity = prev;
2058 prev.state = ActivityState.PAUSING;
2059 prev.task.touchActiveTime();
2060
2061 updateCpuStats();
2062
2063 if (prev.app != null && prev.app.thread != null) {
2064 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2065 try {
2066 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2067 System.identityHashCode(prev),
2068 prev.shortComponentName);
2069 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2070 prev.configChangeFlags);
2071 updateUsageStats(prev, false);
2072 } catch (Exception e) {
2073 // Ignore exception, if process died other code will cleanup.
2074 Log.w(TAG, "Exception thrown during pause", e);
2075 mPausingActivity = null;
2076 mLastPausedActivity = null;
2077 }
2078 } else {
2079 mPausingActivity = null;
2080 mLastPausedActivity = null;
2081 }
2082
2083 // If we are not going to sleep, we want to ensure the device is
2084 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002085 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 mLaunchingActivity.acquire();
2087 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2088 // To be safe, don't allow the wake lock to be held for too long.
2089 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2090 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2091 }
2092 }
2093
2094
2095 if (mPausingActivity != null) {
2096 // Have the window manager pause its key dispatching until the new
2097 // activity has started. If we're pausing the activity just because
2098 // the screen is being turned off and the UI is sleeping, don't interrupt
2099 // key dispatch; the same activity will pick it up again on wakeup.
2100 if (!uiSleeping) {
2101 prev.pauseKeyDispatchingLocked();
2102 } else {
2103 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2104 }
2105
2106 // Schedule a pause timeout in case the app doesn't respond.
2107 // We don't give it much time because this directly impacts the
2108 // responsiveness seen by the user.
2109 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2110 msg.obj = prev;
2111 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2112 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2113 } else {
2114 // This activity failed to schedule the
2115 // pause, so just treat it as being paused now.
2116 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2117 resumeTopActivityLocked(null);
2118 }
2119 }
2120
2121 private final void completePauseLocked() {
2122 HistoryRecord prev = mPausingActivity;
2123 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2124
2125 if (prev != null) {
2126 if (prev.finishing) {
2127 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2128 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2129 } else if (prev.app != null) {
2130 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2131 if (prev.waitingVisible) {
2132 prev.waitingVisible = false;
2133 mWaitingVisibleActivities.remove(prev);
2134 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2135 TAG, "Complete pause, no longer waiting: " + prev);
2136 }
2137 if (prev.configDestroy) {
2138 // The previous is being paused because the configuration
2139 // is changing, which means it is actually stopping...
2140 // To juggle the fact that we are also starting a new
2141 // instance right now, we need to first completely stop
2142 // the current instance before starting the new one.
2143 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2144 destroyActivityLocked(prev, true);
2145 } else {
2146 mStoppingActivities.add(prev);
2147 if (mStoppingActivities.size() > 3) {
2148 // If we already have a few activities waiting to stop,
2149 // then give up on things going idle and start clearing
2150 // them out.
2151 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2152 Message msg = Message.obtain();
2153 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2154 mHandler.sendMessage(msg);
2155 }
2156 }
2157 } else {
2158 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2159 prev = null;
2160 }
2161 mPausingActivity = null;
2162 }
2163
Dianne Hackborn55280a92009-05-07 15:53:46 -07002164 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002165 resumeTopActivityLocked(prev);
2166 } else {
2167 if (mGoingToSleep.isHeld()) {
2168 mGoingToSleep.release();
2169 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002170 if (mShuttingDown) {
2171 notifyAll();
2172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 }
2174
2175 if (prev != null) {
2176 prev.resumeKeyDispatchingLocked();
2177 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002178
2179 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2180 long diff = 0;
2181 synchronized (mProcessStatsThread) {
2182 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2183 }
2184 if (diff > 0) {
2185 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2186 synchronized (bsi) {
2187 BatteryStatsImpl.Uid.Proc ps =
2188 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2189 prev.info.packageName);
2190 if (ps != null) {
2191 ps.addForegroundTimeLocked(diff);
2192 }
2193 }
2194 }
2195 }
2196 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197 }
2198
2199 /**
2200 * Once we know that we have asked an application to put an activity in
2201 * the resumed state (either by launching it or explicitly telling it),
2202 * this function updates the rest of our state to match that fact.
2203 */
2204 private final void completeResumeLocked(HistoryRecord next) {
2205 next.idle = false;
2206 next.results = null;
2207 next.newIntents = null;
2208
2209 // schedule an idle timeout in case the app doesn't do it for us.
2210 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2211 msg.obj = next;
2212 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2213
2214 if (false) {
2215 // The activity was never told to pause, so just keep
2216 // things going as-is. To maintain our own state,
2217 // we need to emulate it coming back and saying it is
2218 // idle.
2219 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2220 msg.obj = next;
2221 mHandler.sendMessage(msg);
2222 }
2223
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002224 reportResumedActivity(next);
2225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 next.thumbnail = null;
2227 setFocusedActivityLocked(next);
2228 next.resumeKeyDispatchingLocked();
2229 ensureActivitiesVisibleLocked(null, 0);
2230 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002231
2232 // Mark the point when the activity is resuming
2233 // TODO: To be more accurate, the mark should be before the onCreate,
2234 // not after the onResume. But for subsequent starts, onResume is fine.
2235 if (next.app != null) {
2236 synchronized (mProcessStatsThread) {
2237 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2238 }
2239 } else {
2240 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2241 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 }
2243
2244 /**
2245 * Make sure that all activities that need to be visible (that is, they
2246 * currently can be seen by the user) actually are.
2247 */
2248 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2249 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2250 if (DEBUG_VISBILITY) Log.v(
2251 TAG, "ensureActivitiesVisible behind " + top
2252 + " configChanges=0x" + Integer.toHexString(configChanges));
2253
2254 // If the top activity is not fullscreen, then we need to
2255 // make sure any activities under it are now visible.
2256 final int count = mHistory.size();
2257 int i = count-1;
2258 while (mHistory.get(i) != top) {
2259 i--;
2260 }
2261 HistoryRecord r;
2262 boolean behindFullscreen = false;
2263 for (; i>=0; i--) {
2264 r = (HistoryRecord)mHistory.get(i);
2265 if (DEBUG_VISBILITY) Log.v(
2266 TAG, "Make visible? " + r + " finishing=" + r.finishing
2267 + " state=" + r.state);
2268 if (r.finishing) {
2269 continue;
2270 }
2271
2272 final boolean doThisProcess = onlyThisProcess == null
2273 || onlyThisProcess.equals(r.processName);
2274
2275 // First: if this is not the current activity being started, make
2276 // sure it matches the current configuration.
2277 if (r != starting && doThisProcess) {
2278 ensureActivityConfigurationLocked(r, 0);
2279 }
2280
2281 if (r.app == null || r.app.thread == null) {
2282 if (onlyThisProcess == null
2283 || onlyThisProcess.equals(r.processName)) {
2284 // This activity needs to be visible, but isn't even
2285 // running... get it started, but don't resume it
2286 // at this point.
2287 if (DEBUG_VISBILITY) Log.v(
2288 TAG, "Start and freeze screen for " + r);
2289 if (r != starting) {
2290 r.startFreezingScreenLocked(r.app, configChanges);
2291 }
2292 if (!r.visible) {
2293 if (DEBUG_VISBILITY) Log.v(
2294 TAG, "Starting and making visible: " + r);
2295 mWindowManager.setAppVisibility(r, true);
2296 }
2297 if (r != starting) {
2298 startSpecificActivityLocked(r, false, false);
2299 }
2300 }
2301
2302 } else if (r.visible) {
2303 // If this activity is already visible, then there is nothing
2304 // else to do here.
2305 if (DEBUG_VISBILITY) Log.v(
2306 TAG, "Skipping: already visible at " + r);
2307 r.stopFreezingScreenLocked(false);
2308
2309 } else if (onlyThisProcess == null) {
2310 // This activity is not currently visible, but is running.
2311 // Tell it to become visible.
2312 r.visible = true;
2313 if (r.state != ActivityState.RESUMED && r != starting) {
2314 // If this activity is paused, tell it
2315 // to now show its window.
2316 if (DEBUG_VISBILITY) Log.v(
2317 TAG, "Making visible and scheduling visibility: " + r);
2318 try {
2319 mWindowManager.setAppVisibility(r, true);
2320 r.app.thread.scheduleWindowVisibility(r, true);
2321 r.stopFreezingScreenLocked(false);
2322 } catch (Exception e) {
2323 // Just skip on any failure; we'll make it
2324 // visible when it next restarts.
2325 Log.w(TAG, "Exception thrown making visibile: "
2326 + r.intent.getComponent(), e);
2327 }
2328 }
2329 }
2330
2331 // Aggregate current change flags.
2332 configChanges |= r.configChangeFlags;
2333
2334 if (r.fullscreen) {
2335 // At this point, nothing else needs to be shown
2336 if (DEBUG_VISBILITY) Log.v(
2337 TAG, "Stopping: fullscreen at " + r);
2338 behindFullscreen = true;
2339 i--;
2340 break;
2341 }
2342 }
2343
2344 // Now for any activities that aren't visible to the user, make
2345 // sure they no longer are keeping the screen frozen.
2346 while (i >= 0) {
2347 r = (HistoryRecord)mHistory.get(i);
2348 if (DEBUG_VISBILITY) Log.v(
2349 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2350 + " state=" + r.state
2351 + " behindFullscreen=" + behindFullscreen);
2352 if (!r.finishing) {
2353 if (behindFullscreen) {
2354 if (r.visible) {
2355 if (DEBUG_VISBILITY) Log.v(
2356 TAG, "Making invisible: " + r);
2357 r.visible = false;
2358 try {
2359 mWindowManager.setAppVisibility(r, false);
2360 if ((r.state == ActivityState.STOPPING
2361 || r.state == ActivityState.STOPPED)
2362 && r.app != null && r.app.thread != null) {
2363 if (DEBUG_VISBILITY) Log.v(
2364 TAG, "Scheduling invisibility: " + r);
2365 r.app.thread.scheduleWindowVisibility(r, false);
2366 }
2367 } catch (Exception e) {
2368 // Just skip on any failure; we'll make it
2369 // visible when it next restarts.
2370 Log.w(TAG, "Exception thrown making hidden: "
2371 + r.intent.getComponent(), e);
2372 }
2373 } else {
2374 if (DEBUG_VISBILITY) Log.v(
2375 TAG, "Already invisible: " + r);
2376 }
2377 } else if (r.fullscreen) {
2378 if (DEBUG_VISBILITY) Log.v(
2379 TAG, "Now behindFullscreen: " + r);
2380 behindFullscreen = true;
2381 }
2382 }
2383 i--;
2384 }
2385 }
2386
2387 /**
2388 * Version of ensureActivitiesVisible that can easily be called anywhere.
2389 */
2390 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2391 int configChanges) {
2392 HistoryRecord r = topRunningActivityLocked(null);
2393 if (r != null) {
2394 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2395 }
2396 }
2397
2398 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2399 if (resumed) {
2400 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2401 } else {
2402 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2403 }
2404 }
2405
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002406 private boolean startHomeActivityLocked() {
2407 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2408 && mTopAction == null) {
2409 // We are running in factory test mode, but unable to find
2410 // the factory test app, so just sit around displaying the
2411 // error message and don't try to start anything.
2412 return false;
2413 }
2414 Intent intent = new Intent(
2415 mTopAction,
2416 mTopData != null ? Uri.parse(mTopData) : null);
2417 intent.setComponent(mTopComponent);
2418 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2419 intent.addCategory(Intent.CATEGORY_HOME);
2420 }
2421 ActivityInfo aInfo =
2422 intent.resolveActivityInfo(mContext.getPackageManager(),
2423 STOCK_PM_FLAGS);
2424 if (aInfo != null) {
2425 intent.setComponent(new ComponentName(
2426 aInfo.applicationInfo.packageName, aInfo.name));
2427 // Don't do this if the home app is currently being
2428 // instrumented.
2429 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2430 aInfo.applicationInfo.uid);
2431 if (app == null || app.instrumentationClass == null) {
2432 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2433 startActivityLocked(null, intent, null, null, 0, aInfo,
2434 null, null, 0, 0, 0, false, false);
2435 }
2436 }
2437
2438
2439 return true;
2440 }
2441
2442 /**
2443 * Starts the "new version setup screen" if appropriate.
2444 */
2445 private void startSetupActivityLocked() {
2446 // Only do this once per boot.
2447 if (mCheckedForSetup) {
2448 return;
2449 }
2450
2451 // We will show this screen if the current one is a different
2452 // version than the last one shown, and we are not running in
2453 // low-level factory test mode.
2454 final ContentResolver resolver = mContext.getContentResolver();
2455 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2456 Settings.Secure.getInt(resolver,
2457 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2458 mCheckedForSetup = true;
2459
2460 // See if we should be showing the platform update setup UI.
2461 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2462 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2463 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2464
2465 // We don't allow third party apps to replace this.
2466 ResolveInfo ri = null;
2467 for (int i=0; ris != null && i<ris.size(); i++) {
2468 if ((ris.get(i).activityInfo.applicationInfo.flags
2469 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2470 ri = ris.get(i);
2471 break;
2472 }
2473 }
2474
2475 if (ri != null) {
2476 String vers = ri.activityInfo.metaData != null
2477 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2478 : null;
2479 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2480 vers = ri.activityInfo.applicationInfo.metaData.getString(
2481 Intent.METADATA_SETUP_VERSION);
2482 }
2483 String lastVers = Settings.Secure.getString(
2484 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2485 if (vers != null && !vers.equals(lastVers)) {
2486 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2487 intent.setComponent(new ComponentName(
2488 ri.activityInfo.packageName, ri.activityInfo.name));
2489 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2490 null, null, 0, 0, 0, false, false);
2491 }
2492 }
2493 }
2494 }
2495
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002496 private void reportResumedActivity(HistoryRecord r) {
2497 //Log.i(TAG, "**** REPORT RESUME: " + r);
2498
2499 final int identHash = System.identityHashCode(r);
2500 updateUsageStats(r, true);
2501
2502 int i = mWatchers.beginBroadcast();
2503 while (i > 0) {
2504 i--;
2505 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2506 if (w != null) {
2507 try {
2508 w.activityResuming(identHash);
2509 } catch (RemoteException e) {
2510 }
2511 }
2512 }
2513 mWatchers.finishBroadcast();
2514 }
2515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 /**
2517 * Ensure that the top activity in the stack is resumed.
2518 *
2519 * @param prev The previously resumed activity, for when in the process
2520 * of pausing; can be null to call from elsewhere.
2521 *
2522 * @return Returns true if something is being resumed, or false if
2523 * nothing happened.
2524 */
2525 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2526 // Find the first activity that is not finishing.
2527 HistoryRecord next = topRunningActivityLocked(null);
2528
2529 // Remember how we'll process this pause/resume situation, and ensure
2530 // that the state is reset however we wind up proceeding.
2531 final boolean userLeaving = mUserLeaving;
2532 mUserLeaving = false;
2533
2534 if (next == null) {
2535 // There are no more activities! Let's just start up the
2536 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002537 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002538 }
2539
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002540 next.delayedResume = false;
2541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002542 // If the top activity is the resumed one, nothing to do.
2543 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2544 // Make sure we have executed any pending transitions, since there
2545 // should be nothing left to do at this point.
2546 mWindowManager.executeAppTransition();
2547 return false;
2548 }
2549
2550 // If we are sleeping, and there is no resumed activity, and the top
2551 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002552 if ((mSleeping || mShuttingDown)
2553 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 // Make sure we have executed any pending transitions, since there
2555 // should be nothing left to do at this point.
2556 mWindowManager.executeAppTransition();
2557 return false;
2558 }
2559
2560 // The activity may be waiting for stop, but that is no longer
2561 // appropriate for it.
2562 mStoppingActivities.remove(next);
2563 mWaitingVisibleActivities.remove(next);
2564
2565 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2566
2567 // If we are currently pausing an activity, then don't do anything
2568 // until that is done.
2569 if (mPausingActivity != null) {
2570 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2571 return false;
2572 }
2573
2574 // We need to start pausing the current activity so the top one
2575 // can be resumed...
2576 if (mResumedActivity != null) {
2577 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2578 startPausingLocked(userLeaving, false);
2579 return true;
2580 }
2581
2582 if (prev != null && prev != next) {
2583 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2584 prev.waitingVisible = true;
2585 mWaitingVisibleActivities.add(prev);
2586 if (DEBUG_SWITCH) Log.v(
2587 TAG, "Resuming top, waiting visible to hide: " + prev);
2588 } else {
2589 // The next activity is already visible, so hide the previous
2590 // activity's windows right now so we can show the new one ASAP.
2591 // We only do this if the previous is finishing, which should mean
2592 // it is on top of the one being resumed so hiding it quickly
2593 // is good. Otherwise, we want to do the normal route of allowing
2594 // the resumed activity to be shown so we can decide if the
2595 // previous should actually be hidden depending on whether the
2596 // new one is found to be full-screen or not.
2597 if (prev.finishing) {
2598 mWindowManager.setAppVisibility(prev, false);
2599 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2600 + prev + ", waitingVisible="
2601 + (prev != null ? prev.waitingVisible : null)
2602 + ", nowVisible=" + next.nowVisible);
2603 } else {
2604 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2605 + prev + ", waitingVisible="
2606 + (prev != null ? prev.waitingVisible : null)
2607 + ", nowVisible=" + next.nowVisible);
2608 }
2609 }
2610 }
2611
2612 // We are starting up the next activity, so tell the window manager
2613 // that the previous one will be hidden soon. This way it can know
2614 // to ignore it when computing the desired screen orientation.
2615 if (prev != null) {
2616 if (prev.finishing) {
2617 if (DEBUG_TRANSITION) Log.v(TAG,
2618 "Prepare close transition: prev=" + prev);
2619 mWindowManager.prepareAppTransition(prev.task == next.task
2620 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2621 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2622 mWindowManager.setAppWillBeHidden(prev);
2623 mWindowManager.setAppVisibility(prev, false);
2624 } else {
2625 if (DEBUG_TRANSITION) Log.v(TAG,
2626 "Prepare open transition: prev=" + prev);
2627 mWindowManager.prepareAppTransition(prev.task == next.task
2628 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2629 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2630 }
2631 if (false) {
2632 mWindowManager.setAppWillBeHidden(prev);
2633 mWindowManager.setAppVisibility(prev, false);
2634 }
2635 } else if (mHistory.size() > 1) {
2636 if (DEBUG_TRANSITION) Log.v(TAG,
2637 "Prepare open transition: no previous");
2638 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2639 }
2640
2641 if (next.app != null && next.app.thread != null) {
2642 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2643
2644 // This activity is now becoming visible.
2645 mWindowManager.setAppVisibility(next, true);
2646
2647 HistoryRecord lastResumedActivity = mResumedActivity;
2648 ActivityState lastState = next.state;
2649
2650 updateCpuStats();
2651
2652 next.state = ActivityState.RESUMED;
2653 mResumedActivity = next;
2654 next.task.touchActiveTime();
2655 updateLRUListLocked(next.app, true);
2656 updateLRUListLocked(next);
2657
2658 // Have the window manager re-evaluate the orientation of
2659 // the screen based on the new activity order.
2660 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002661 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 next.mayFreezeScreenLocked(next.app) ? next : null);
2663 if (config != null) {
2664 next.frozenBeforeDestroy = true;
2665 }
2666 if (!updateConfigurationLocked(config, next)) {
2667 // The configuration update wasn't able to keep the existing
2668 // instance of the activity, and instead started a new one.
2669 // We should be all done, but let's just make sure our activity
2670 // is still at the top and schedule another run if something
2671 // weird happened.
2672 HistoryRecord nextNext = topRunningActivityLocked(null);
2673 if (DEBUG_SWITCH) Log.i(TAG,
2674 "Activity config changed during resume: " + next
2675 + ", new next: " + nextNext);
2676 if (nextNext != next) {
2677 // Do over!
2678 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2679 }
2680 mWindowManager.executeAppTransition();
2681 return true;
2682 }
2683
2684 try {
2685 // Deliver all pending results.
2686 ArrayList a = next.results;
2687 if (a != null) {
2688 final int N = a.size();
2689 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002690 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 TAG, "Delivering results to " + next
2692 + ": " + a);
2693 next.app.thread.scheduleSendResult(next, a);
2694 }
2695 }
2696
2697 if (next.newIntents != null) {
2698 next.app.thread.scheduleNewIntent(next.newIntents, next);
2699 }
2700
2701 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2702 System.identityHashCode(next),
2703 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704
2705 next.app.thread.scheduleResumeActivity(next,
2706 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 pauseIfSleepingLocked();
2709
2710 } catch (Exception e) {
2711 // Whoops, need to restart this activity!
2712 next.state = lastState;
2713 mResumedActivity = lastResumedActivity;
2714 if (Config.LOGD) Log.d(TAG,
2715 "Restarting because process died: " + next);
2716 if (!next.hasBeenLaunched) {
2717 next.hasBeenLaunched = true;
2718 } else {
2719 if (SHOW_APP_STARTING_ICON) {
2720 mWindowManager.setAppStartingWindow(
2721 next, next.packageName, next.theme,
2722 next.nonLocalizedLabel,
2723 next.labelRes, next.icon, null, true);
2724 }
2725 }
2726 startSpecificActivityLocked(next, true, false);
2727 return true;
2728 }
2729
2730 // From this point on, if something goes wrong there is no way
2731 // to recover the activity.
2732 try {
2733 next.visible = true;
2734 completeResumeLocked(next);
2735 } catch (Exception e) {
2736 // If any exception gets thrown, toss away this
2737 // activity and try the next one.
2738 Log.w(TAG, "Exception thrown during resume of " + next, e);
2739 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2740 "resume-exception");
2741 return true;
2742 }
2743
2744 // Didn't need to use the icicle, and it is now out of date.
2745 next.icicle = null;
2746 next.haveState = false;
2747 next.stopped = false;
2748
2749 } else {
2750 // Whoops, need to restart this activity!
2751 if (!next.hasBeenLaunched) {
2752 next.hasBeenLaunched = true;
2753 } else {
2754 if (SHOW_APP_STARTING_ICON) {
2755 mWindowManager.setAppStartingWindow(
2756 next, next.packageName, next.theme,
2757 next.nonLocalizedLabel,
2758 next.labelRes, next.icon, null, true);
2759 }
2760 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2761 }
2762 startSpecificActivityLocked(next, true, true);
2763 }
2764
2765 return true;
2766 }
2767
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002768 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2769 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002770 final int NH = mHistory.size();
2771
2772 int addPos = -1;
2773
2774 if (!newTask) {
2775 // If starting in an existing task, find where that is...
2776 HistoryRecord next = null;
2777 boolean startIt = true;
2778 for (int i = NH-1; i >= 0; i--) {
2779 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2780 if (p.finishing) {
2781 continue;
2782 }
2783 if (p.task == r.task) {
2784 // Here it is! Now, if this is not yet visible to the
2785 // user, then just add it without starting; it will
2786 // get started when the user navigates back to it.
2787 addPos = i+1;
2788 if (!startIt) {
2789 mHistory.add(addPos, r);
2790 r.inHistory = true;
2791 r.task.numActivities++;
2792 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2793 r.info.screenOrientation, r.fullscreen);
2794 if (VALIDATE_TOKENS) {
2795 mWindowManager.validateAppTokens(mHistory);
2796 }
2797 return;
2798 }
2799 break;
2800 }
2801 if (p.fullscreen) {
2802 startIt = false;
2803 }
2804 next = p;
2805 }
2806 }
2807
2808 // Place a new activity at top of stack, so it is next to interact
2809 // with the user.
2810 if (addPos < 0) {
2811 addPos = mHistory.size();
2812 }
2813
2814 // If we are not placing the new activity frontmost, we do not want
2815 // to deliver the onUserLeaving callback to the actual frontmost
2816 // activity
2817 if (addPos < NH) {
2818 mUserLeaving = false;
2819 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2820 }
2821
2822 // Slot the activity into the history stack and proceed
2823 mHistory.add(addPos, r);
2824 r.inHistory = true;
2825 r.frontOfTask = newTask;
2826 r.task.numActivities++;
2827 if (NH > 0) {
2828 // We want to show the starting preview window if we are
2829 // switching to a new task, or the next activity's process is
2830 // not currently running.
2831 boolean showStartingIcon = newTask;
2832 ProcessRecord proc = r.app;
2833 if (proc == null) {
2834 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2835 }
2836 if (proc == null || proc.thread == null) {
2837 showStartingIcon = true;
2838 }
2839 if (DEBUG_TRANSITION) Log.v(TAG,
2840 "Prepare open transition: starting " + r);
2841 mWindowManager.prepareAppTransition(newTask
2842 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2843 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2844 mWindowManager.addAppToken(
2845 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2846 boolean doShow = true;
2847 if (newTask) {
2848 // Even though this activity is starting fresh, we still need
2849 // to reset it to make sure we apply affinities to move any
2850 // existing activities from other tasks in to it.
2851 // If the caller has requested that the target task be
2852 // reset, then do so.
2853 if ((r.intent.getFlags()
2854 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2855 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002856 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 }
2858 }
2859 if (SHOW_APP_STARTING_ICON && doShow) {
2860 // Figure out if we are transitioning from another activity that is
2861 // "has the same starting icon" as the next one. This allows the
2862 // window manager to keep the previous window it had previously
2863 // created, if it still had one.
2864 HistoryRecord prev = mResumedActivity;
2865 if (prev != null) {
2866 // We don't want to reuse the previous starting preview if:
2867 // (1) The current activity is in a different task.
2868 if (prev.task != r.task) prev = null;
2869 // (2) The current activity is already displayed.
2870 else if (prev.nowVisible) prev = null;
2871 }
2872 mWindowManager.setAppStartingWindow(
2873 r, r.packageName, r.theme, r.nonLocalizedLabel,
2874 r.labelRes, r.icon, prev, showStartingIcon);
2875 }
2876 } else {
2877 // If this is the first activity, don't do any fancy animations,
2878 // because there is nothing for it to animate on top of.
2879 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2880 r.info.screenOrientation, r.fullscreen);
2881 }
2882 if (VALIDATE_TOKENS) {
2883 mWindowManager.validateAppTokens(mHistory);
2884 }
2885
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002886 if (doResume) {
2887 resumeTopActivityLocked(null);
2888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002889 }
2890
2891 /**
2892 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002893 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2894 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002895 * an instance of that activity in the stack and, if found, finish all
2896 * activities on top of it and return the instance.
2897 *
2898 * @param newR Description of the new activity being started.
2899 * @return Returns the old activity that should be continue to be used,
2900 * or null if none was found.
2901 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002902 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002903 HistoryRecord newR, boolean doClear) {
2904 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002905
2906 // First find the requested task.
2907 while (i > 0) {
2908 i--;
2909 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2910 if (r.task.taskId == taskId) {
2911 i++;
2912 break;
2913 }
2914 }
2915
2916 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 while (i > 0) {
2918 i--;
2919 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2920 if (r.finishing) {
2921 continue;
2922 }
2923 if (r.task.taskId != taskId) {
2924 return null;
2925 }
2926 if (r.realActivity.equals(newR.realActivity)) {
2927 // Here it is! Now finish everything in front...
2928 HistoryRecord ret = r;
2929 if (doClear) {
2930 while (i < (mHistory.size()-1)) {
2931 i++;
2932 r = (HistoryRecord)mHistory.get(i);
2933 if (r.finishing) {
2934 continue;
2935 }
2936 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2937 null, "clear")) {
2938 i--;
2939 }
2940 }
2941 }
2942
2943 // Finally, if this is a normal launch mode (that is, not
2944 // expecting onNewIntent()), then we will finish the current
2945 // instance of the activity so a new fresh one can be started.
2946 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2947 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002948 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002949 if (index >= 0) {
2950 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2951 null, "clear");
2952 }
2953 return null;
2954 }
2955 }
2956
2957 return ret;
2958 }
2959 }
2960
2961 return null;
2962 }
2963
2964 /**
2965 * Find the activity in the history stack within the given task. Returns
2966 * the index within the history at which it's found, or < 0 if not found.
2967 */
2968 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2969 int i = mHistory.size();
2970 while (i > 0) {
2971 i--;
2972 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2973 if (candidate.task.taskId != task) {
2974 break;
2975 }
2976 if (candidate.realActivity.equals(r.realActivity)) {
2977 return i;
2978 }
2979 }
2980
2981 return -1;
2982 }
2983
2984 /**
2985 * Reorder the history stack so that the activity at the given index is
2986 * brought to the front.
2987 */
2988 private final HistoryRecord moveActivityToFrontLocked(int where) {
2989 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2990 int top = mHistory.size();
2991 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2992 mHistory.add(top, newTop);
2993 oldTop.frontOfTask = false;
2994 newTop.frontOfTask = true;
2995 return newTop;
2996 }
2997
2998 /**
2999 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3000 * method will be called at the proper time.
3001 */
3002 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3003 boolean sent = false;
3004 if (r.state == ActivityState.RESUMED
3005 && r.app != null && r.app.thread != null) {
3006 try {
3007 ArrayList<Intent> ar = new ArrayList<Intent>();
3008 ar.add(new Intent(intent));
3009 r.app.thread.scheduleNewIntent(ar, r);
3010 sent = true;
3011 } catch (Exception e) {
3012 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3013 }
3014 }
3015 if (!sent) {
3016 r.addNewIntentLocked(new Intent(intent));
3017 }
3018 }
3019
3020 private final void logStartActivity(int tag, HistoryRecord r,
3021 TaskRecord task) {
3022 EventLog.writeEvent(tag,
3023 System.identityHashCode(r), task.taskId,
3024 r.shortComponentName, r.intent.getAction(),
3025 r.intent.getType(), r.intent.getDataString(),
3026 r.intent.getFlags());
3027 }
3028
3029 private final int startActivityLocked(IApplicationThread caller,
3030 Intent intent, String resolvedType,
3031 Uri[] grantedUriPermissions,
3032 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3033 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003034 int callingPid, int callingUid, boolean onlyIfNeeded,
3035 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 Log.i(TAG, "Starting activity: " + intent);
3037
3038 HistoryRecord sourceRecord = null;
3039 HistoryRecord resultRecord = null;
3040 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003041 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003042 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3044 if (index >= 0) {
3045 sourceRecord = (HistoryRecord)mHistory.get(index);
3046 if (requestCode >= 0 && !sourceRecord.finishing) {
3047 resultRecord = sourceRecord;
3048 }
3049 }
3050 }
3051
3052 int launchFlags = intent.getFlags();
3053
3054 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3055 && sourceRecord != null) {
3056 // Transfer the result target from the source activity to the new
3057 // one being started, including any failures.
3058 if (requestCode >= 0) {
3059 return START_FORWARD_AND_REQUEST_CONFLICT;
3060 }
3061 resultRecord = sourceRecord.resultTo;
3062 resultWho = sourceRecord.resultWho;
3063 requestCode = sourceRecord.requestCode;
3064 sourceRecord.resultTo = null;
3065 if (resultRecord != null) {
3066 resultRecord.removeResultsLocked(
3067 sourceRecord, resultWho, requestCode);
3068 }
3069 }
3070
3071 int err = START_SUCCESS;
3072
3073 if (intent.getComponent() == null) {
3074 // We couldn't find a class that can handle the given Intent.
3075 // That's the end of that!
3076 err = START_INTENT_NOT_RESOLVED;
3077 }
3078
3079 if (err == START_SUCCESS && aInfo == null) {
3080 // We couldn't find the specific class specified in the Intent.
3081 // Also the end of the line.
3082 err = START_CLASS_NOT_FOUND;
3083 }
3084
3085 ProcessRecord callerApp = null;
3086 if (err == START_SUCCESS && caller != null) {
3087 callerApp = getRecordForAppLocked(caller);
3088 if (callerApp != null) {
3089 callingPid = callerApp.pid;
3090 callingUid = callerApp.info.uid;
3091 } else {
3092 Log.w(TAG, "Unable to find app for caller " + caller
3093 + " (pid=" + callingPid + ") when starting: "
3094 + intent.toString());
3095 err = START_PERMISSION_DENIED;
3096 }
3097 }
3098
3099 if (err != START_SUCCESS) {
3100 if (resultRecord != null) {
3101 sendActivityResultLocked(-1,
3102 resultRecord, resultWho, requestCode,
3103 Activity.RESULT_CANCELED, null);
3104 }
3105 return err;
3106 }
3107
3108 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3109 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3110 if (perm != PackageManager.PERMISSION_GRANTED) {
3111 if (resultRecord != null) {
3112 sendActivityResultLocked(-1,
3113 resultRecord, resultWho, requestCode,
3114 Activity.RESULT_CANCELED, null);
3115 }
3116 String msg = "Permission Denial: starting " + intent.toString()
3117 + " from " + callerApp + " (pid=" + callingPid
3118 + ", uid=" + callingUid + ")"
3119 + " requires " + aInfo.permission;
3120 Log.w(TAG, msg);
3121 throw new SecurityException(msg);
3122 }
3123
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003124 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003125 boolean abort = false;
3126 try {
3127 // The Intent we give to the watcher has the extra data
3128 // stripped off, since it can contain private information.
3129 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003130 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003131 aInfo.applicationInfo.packageName);
3132 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003133 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003134 }
3135
3136 if (abort) {
3137 if (resultRecord != null) {
3138 sendActivityResultLocked(-1,
3139 resultRecord, resultWho, requestCode,
3140 Activity.RESULT_CANCELED, null);
3141 }
3142 // We pretend to the caller that it was really started, but
3143 // they will just get a cancel result.
3144 return START_SUCCESS;
3145 }
3146 }
3147
3148 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3149 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003150 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003152 if (mResumedActivity == null
3153 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3154 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3155 PendingActivityLaunch pal = new PendingActivityLaunch();
3156 pal.r = r;
3157 pal.sourceRecord = sourceRecord;
3158 pal.grantedUriPermissions = grantedUriPermissions;
3159 pal.grantedMode = grantedMode;
3160 pal.onlyIfNeeded = onlyIfNeeded;
3161 mPendingActivityLaunches.add(pal);
3162 return START_SWITCHES_CANCELED;
3163 }
3164 }
3165
3166 if (mDidAppSwitch) {
3167 // This is the second allowed switch since we stopped switches,
3168 // so now just generally allow switches. Use case: user presses
3169 // home (switches disabled, switch to home, mDidAppSwitch now true);
3170 // user taps a home icon (coming from home so allowed, we hit here
3171 // and now allow anyone to switch again).
3172 mAppSwitchesAllowedTime = 0;
3173 } else {
3174 mDidAppSwitch = true;
3175 }
3176
3177 doPendingActivityLaunchesLocked(false);
3178
3179 return startActivityUncheckedLocked(r, sourceRecord,
3180 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3181 }
3182
3183 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3184 final int N = mPendingActivityLaunches.size();
3185 if (N <= 0) {
3186 return;
3187 }
3188 for (int i=0; i<N; i++) {
3189 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3190 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3191 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3192 doResume && i == (N-1));
3193 }
3194 mPendingActivityLaunches.clear();
3195 }
3196
3197 private final int startActivityUncheckedLocked(HistoryRecord r,
3198 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3199 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3200 final Intent intent = r.intent;
3201 final int callingUid = r.launchedFromUid;
3202
3203 int launchFlags = intent.getFlags();
3204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003205 // We'll invoke onUserLeaving before onPause only if the launching
3206 // activity did not explicitly state that this is an automated launch.
3207 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3208 if (DEBUG_USER_LEAVING) Log.v(TAG,
3209 "startActivity() => mUserLeaving=" + mUserLeaving);
3210
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003211 // If the caller has asked not to resume at this point, we make note
3212 // of this in the record so that we can skip it when trying to find
3213 // the top running activity.
3214 if (!doResume) {
3215 r.delayedResume = true;
3216 }
3217
3218 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3219 != 0 ? r : null;
3220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003221 // If the onlyIfNeeded flag is set, then we can do this if the activity
3222 // being launched is the same as the one making the call... or, as
3223 // a special case, if we do not know the caller then we count the
3224 // current top activity as the caller.
3225 if (onlyIfNeeded) {
3226 HistoryRecord checkedCaller = sourceRecord;
3227 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003228 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003229 }
3230 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3231 // Caller is not the same as launcher, so always needed.
3232 onlyIfNeeded = false;
3233 }
3234 }
3235
3236 if (grantedUriPermissions != null && callingUid > 0) {
3237 for (int i=0; i<grantedUriPermissions.length; i++) {
3238 grantUriPermissionLocked(callingUid, r.packageName,
3239 grantedUriPermissions[i], grantedMode, r);
3240 }
3241 }
3242
3243 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3244 intent, r);
3245
3246 if (sourceRecord == null) {
3247 // This activity is not being started from another... in this
3248 // case we -always- start a new task.
3249 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3250 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3251 + intent);
3252 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3253 }
3254 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3255 // The original activity who is starting us is running as a single
3256 // instance... this new activity it is starting must go on its
3257 // own task.
3258 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3259 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3260 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3261 // The activity being started is a single instance... it always
3262 // gets launched into its own task.
3263 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3264 }
3265
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003266 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 // For whatever reason this activity is being launched into a new
3268 // task... yet the caller has requested a result back. Well, that
3269 // is pretty messed up, so instead immediately send back a cancel
3270 // and let the new task continue launched as normal without a
3271 // dependency on its originator.
3272 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3273 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003274 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 Activity.RESULT_CANCELED, null);
3276 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 }
3278
3279 boolean addingToTask = false;
3280 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3281 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3282 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3283 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3284 // If bring to front is requested, and no result is requested, and
3285 // we can find a task that was started with this same
3286 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003287 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003288 // See if there is a task to bring to the front. If this is
3289 // a SINGLE_INSTANCE activity, there can be one and only one
3290 // instance of it in the history, and it is always in its own
3291 // unique task, so we do a special search.
3292 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3293 ? findTaskLocked(intent, r.info)
3294 : findActivityLocked(intent, r.info);
3295 if (taskTop != null) {
3296 if (taskTop.task.intent == null) {
3297 // This task was started because of movement of
3298 // the activity based on affinity... now that we
3299 // are actually launching it, we can assign the
3300 // base intent.
3301 taskTop.task.setIntent(intent, r.info);
3302 }
3303 // If the target task is not in the front, then we need
3304 // to bring it to the front... except... well, with
3305 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3306 // to have the same behavior as if a new instance was
3307 // being started, which means not bringing it to the front
3308 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003309 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 if (curTop.task != taskTop.task) {
3311 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3312 boolean callerAtFront = sourceRecord == null
3313 || curTop.task == sourceRecord.task;
3314 if (callerAtFront) {
3315 // We really do want to push this one into the
3316 // user's face, right now.
3317 moveTaskToFrontLocked(taskTop.task);
3318 }
3319 }
3320 // If the caller has requested that the target task be
3321 // reset, then do so.
3322 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3323 taskTop = resetTaskIfNeededLocked(taskTop, r);
3324 }
3325 if (onlyIfNeeded) {
3326 // We don't need to start a new activity, and
3327 // the client said not to do anything if that
3328 // is the case, so this is it! And for paranoia, make
3329 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003330 if (doResume) {
3331 resumeTopActivityLocked(null);
3332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 return START_RETURN_INTENT_TO_CALLER;
3334 }
3335 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3336 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3337 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3338 // In this situation we want to remove all activities
3339 // from the task up to the one being started. In most
3340 // cases this means we are resetting the task to its
3341 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003342 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 taskTop.task.taskId, r, true);
3344 if (top != null) {
3345 if (top.frontOfTask) {
3346 // Activity aliases may mean we use different
3347 // intents for the top activity, so make sure
3348 // the task now has the identity of the new
3349 // intent.
3350 top.task.setIntent(r.intent, r.info);
3351 }
3352 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3353 deliverNewIntentLocked(top, r.intent);
3354 } else {
3355 // A special case: we need to
3356 // start the activity because it is not currently
3357 // running, and the caller has asked to clear the
3358 // current task to have this activity at the top.
3359 addingToTask = true;
3360 // Now pretend like this activity is being started
3361 // by the top of its task, so it is put in the
3362 // right place.
3363 sourceRecord = taskTop;
3364 }
3365 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3366 // In this case the top activity on the task is the
3367 // same as the one being launched, so we take that
3368 // as a request to bring the task to the foreground.
3369 // If the top activity in the task is the root
3370 // activity, deliver this new intent to it if it
3371 // desires.
3372 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3373 && taskTop.realActivity.equals(r.realActivity)) {
3374 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3375 if (taskTop.frontOfTask) {
3376 taskTop.task.setIntent(r.intent, r.info);
3377 }
3378 deliverNewIntentLocked(taskTop, r.intent);
3379 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3380 // In this case we are launching the root activity
3381 // of the task, but with a different intent. We
3382 // should start a new instance on top.
3383 addingToTask = true;
3384 sourceRecord = taskTop;
3385 }
3386 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3387 // In this case an activity is being launched in to an
3388 // existing task, without resetting that task. This
3389 // is typically the situation of launching an activity
3390 // from a notification or shortcut. We want to place
3391 // the new activity on top of the current task.
3392 addingToTask = true;
3393 sourceRecord = taskTop;
3394 } else if (!taskTop.task.rootWasReset) {
3395 // In this case we are launching in to an existing task
3396 // that has not yet been started from its front door.
3397 // The current task has been brought to the front.
3398 // Ideally, we'd probably like to place this new task
3399 // at the bottom of its stack, but that's a little hard
3400 // to do with the current organization of the code so
3401 // for now we'll just drop it.
3402 taskTop.task.setIntent(r.intent, r.info);
3403 }
3404 if (!addingToTask) {
3405 // We didn't do anything... but it was needed (a.k.a., client
3406 // don't use that intent!) And for paranoia, make
3407 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003408 if (doResume) {
3409 resumeTopActivityLocked(null);
3410 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 return START_TASK_TO_FRONT;
3412 }
3413 }
3414 }
3415 }
3416
3417 //String uri = r.intent.toURI();
3418 //Intent intent2 = new Intent(uri);
3419 //Log.i(TAG, "Given intent: " + r.intent);
3420 //Log.i(TAG, "URI is: " + uri);
3421 //Log.i(TAG, "To intent: " + intent2);
3422
3423 if (r.packageName != null) {
3424 // If the activity being launched is the same as the one currently
3425 // at the top, then we need to check if it should only be launched
3426 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003427 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3428 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 if (top.realActivity.equals(r.realActivity)) {
3430 if (top.app != null && top.app.thread != null) {
3431 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3432 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3433 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3434 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3435 // For paranoia, make sure we have correctly
3436 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003437 if (doResume) {
3438 resumeTopActivityLocked(null);
3439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 if (onlyIfNeeded) {
3441 // We don't need to start a new activity, and
3442 // the client said not to do anything if that
3443 // is the case, so this is it!
3444 return START_RETURN_INTENT_TO_CALLER;
3445 }
3446 deliverNewIntentLocked(top, r.intent);
3447 return START_DELIVERED_TO_TOP;
3448 }
3449 }
3450 }
3451 }
3452
3453 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003454 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003455 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003456 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003457 Activity.RESULT_CANCELED, null);
3458 }
3459 return START_CLASS_NOT_FOUND;
3460 }
3461
3462 boolean newTask = false;
3463
3464 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003465 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3467 // todo: should do better management of integers.
3468 mCurTask++;
3469 if (mCurTask <= 0) {
3470 mCurTask = 1;
3471 }
3472 r.task = new TaskRecord(mCurTask, r.info, intent,
3473 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3474 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3475 + " in new task " + r.task);
3476 newTask = true;
3477 addRecentTask(r.task);
3478
3479 } else if (sourceRecord != null) {
3480 if (!addingToTask &&
3481 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3482 // In this case, we are adding the activity to an existing
3483 // task, but the caller has asked to clear that task if the
3484 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003485 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 sourceRecord.task.taskId, r, true);
3487 if (top != null) {
3488 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3489 deliverNewIntentLocked(top, r.intent);
3490 // For paranoia, make sure we have correctly
3491 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003492 if (doResume) {
3493 resumeTopActivityLocked(null);
3494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003495 return START_DELIVERED_TO_TOP;
3496 }
3497 } else if (!addingToTask &&
3498 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3499 // In this case, we are launching an activity in our own task
3500 // that may already be running somewhere in the history, and
3501 // we want to shuffle it to the front of the stack if so.
3502 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3503 if (where >= 0) {
3504 HistoryRecord top = moveActivityToFrontLocked(where);
3505 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3506 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003507 if (doResume) {
3508 resumeTopActivityLocked(null);
3509 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003510 return START_DELIVERED_TO_TOP;
3511 }
3512 }
3513 // An existing activity is starting this new activity, so we want
3514 // to keep the new one in the same task as the one that is starting
3515 // it.
3516 r.task = sourceRecord.task;
3517 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3518 + " in existing task " + r.task);
3519
3520 } else {
3521 // This not being started from an existing activity, and not part
3522 // of a new task... just put it in the top task, though these days
3523 // this case should never happen.
3524 final int N = mHistory.size();
3525 HistoryRecord prev =
3526 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3527 r.task = prev != null
3528 ? prev.task
3529 : new TaskRecord(mCurTask, r.info, intent,
3530 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3531 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3532 + " in new guessed " + r.task);
3533 }
3534 if (newTask) {
3535 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3536 }
3537 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003538 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 return START_SUCCESS;
3540 }
3541
3542 public final int startActivity(IApplicationThread caller,
3543 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3544 int grantedMode, IBinder resultTo,
3545 String resultWho, int requestCode, boolean onlyIfNeeded,
3546 boolean debug) {
3547 // Refuse possible leaked file descriptors
3548 if (intent != null && intent.hasFileDescriptors()) {
3549 throw new IllegalArgumentException("File descriptors passed in Intent");
3550 }
3551
The Android Open Source Project4df24232009-03-05 14:34:35 -08003552 final boolean componentSpecified = intent.getComponent() != null;
3553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003554 // Don't modify the client's object!
3555 intent = new Intent(intent);
3556
3557 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 ActivityInfo aInfo;
3559 try {
3560 ResolveInfo rInfo =
3561 ActivityThread.getPackageManager().resolveIntent(
3562 intent, resolvedType,
3563 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003564 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003565 aInfo = rInfo != null ? rInfo.activityInfo : null;
3566 } catch (RemoteException e) {
3567 aInfo = null;
3568 }
3569
3570 if (aInfo != null) {
3571 // Store the found target back into the intent, because now that
3572 // we have it we never want to do this again. For example, if the
3573 // user navigates back to this point in the history, we should
3574 // always restart the exact same activity.
3575 intent.setComponent(new ComponentName(
3576 aInfo.applicationInfo.packageName, aInfo.name));
3577
3578 // Don't debug things in the system process
3579 if (debug) {
3580 if (!aInfo.processName.equals("system")) {
3581 setDebugApp(aInfo.processName, true, false);
3582 }
3583 }
3584 }
3585
3586 synchronized(this) {
3587 final long origId = Binder.clearCallingIdentity();
3588 int res = startActivityLocked(caller, intent, resolvedType,
3589 grantedUriPermissions, grantedMode, aInfo,
3590 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003591 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003592 Binder.restoreCallingIdentity(origId);
3593 return res;
3594 }
3595 }
3596
3597 public boolean startNextMatchingActivity(IBinder callingActivity,
3598 Intent intent) {
3599 // Refuse possible leaked file descriptors
3600 if (intent != null && intent.hasFileDescriptors() == true) {
3601 throw new IllegalArgumentException("File descriptors passed in Intent");
3602 }
3603
3604 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003605 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 if (index < 0) {
3607 return false;
3608 }
3609 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3610 if (r.app == null || r.app.thread == null) {
3611 // The caller is not running... d'oh!
3612 return false;
3613 }
3614 intent = new Intent(intent);
3615 // The caller is not allowed to change the data.
3616 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3617 // And we are resetting to find the next component...
3618 intent.setComponent(null);
3619
3620 ActivityInfo aInfo = null;
3621 try {
3622 List<ResolveInfo> resolves =
3623 ActivityThread.getPackageManager().queryIntentActivities(
3624 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003625 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003626
3627 // Look for the original activity in the list...
3628 final int N = resolves != null ? resolves.size() : 0;
3629 for (int i=0; i<N; i++) {
3630 ResolveInfo rInfo = resolves.get(i);
3631 if (rInfo.activityInfo.packageName.equals(r.packageName)
3632 && rInfo.activityInfo.name.equals(r.info.name)) {
3633 // We found the current one... the next matching is
3634 // after it.
3635 i++;
3636 if (i<N) {
3637 aInfo = resolves.get(i).activityInfo;
3638 }
3639 break;
3640 }
3641 }
3642 } catch (RemoteException e) {
3643 }
3644
3645 if (aInfo == null) {
3646 // Nobody who is next!
3647 return false;
3648 }
3649
3650 intent.setComponent(new ComponentName(
3651 aInfo.applicationInfo.packageName, aInfo.name));
3652 intent.setFlags(intent.getFlags()&~(
3653 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3654 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3655 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3656 Intent.FLAG_ACTIVITY_NEW_TASK));
3657
3658 // Okay now we need to start the new activity, replacing the
3659 // currently running activity. This is a little tricky because
3660 // we want to start the new one as if the current one is finished,
3661 // but not finish the current one first so that there is no flicker.
3662 // And thus...
3663 final boolean wasFinishing = r.finishing;
3664 r.finishing = true;
3665
3666 // Propagate reply information over to the new activity.
3667 final HistoryRecord resultTo = r.resultTo;
3668 final String resultWho = r.resultWho;
3669 final int requestCode = r.requestCode;
3670 r.resultTo = null;
3671 if (resultTo != null) {
3672 resultTo.removeResultsLocked(r, resultWho, requestCode);
3673 }
3674
3675 final long origId = Binder.clearCallingIdentity();
3676 // XXX we are not dealing with propagating grantedUriPermissions...
3677 // those are not yet exposed to user code, so there is no need.
3678 int res = startActivityLocked(r.app.thread, intent,
3679 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003680 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003681 Binder.restoreCallingIdentity(origId);
3682
3683 r.finishing = wasFinishing;
3684 if (res != START_SUCCESS) {
3685 return false;
3686 }
3687 return true;
3688 }
3689 }
3690
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003691 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 Intent intent, String resolvedType, IBinder resultTo,
3693 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003694
3695 // This is so super not safe, that only the system (or okay root)
3696 // can do it.
3697 final int callingUid = Binder.getCallingUid();
3698 if (callingUid != 0 && callingUid != Process.myUid()) {
3699 throw new SecurityException(
3700 "startActivityInPackage only available to the system");
3701 }
3702
The Android Open Source Project4df24232009-03-05 14:34:35 -08003703 final boolean componentSpecified = intent.getComponent() != null;
3704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 // Don't modify the client's object!
3706 intent = new Intent(intent);
3707
3708 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709 ActivityInfo aInfo;
3710 try {
3711 ResolveInfo rInfo =
3712 ActivityThread.getPackageManager().resolveIntent(
3713 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003714 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715 aInfo = rInfo != null ? rInfo.activityInfo : null;
3716 } catch (RemoteException e) {
3717 aInfo = null;
3718 }
3719
3720 if (aInfo != null) {
3721 // Store the found target back into the intent, because now that
3722 // we have it we never want to do this again. For example, if the
3723 // user navigates back to this point in the history, we should
3724 // always restart the exact same activity.
3725 intent.setComponent(new ComponentName(
3726 aInfo.applicationInfo.packageName, aInfo.name));
3727 }
3728
3729 synchronized(this) {
3730 return startActivityLocked(null, intent, resolvedType,
3731 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003732 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003733 }
3734 }
3735
3736 private final void addRecentTask(TaskRecord task) {
3737 // Remove any existing entries that are the same kind of task.
3738 int N = mRecentTasks.size();
3739 for (int i=0; i<N; i++) {
3740 TaskRecord tr = mRecentTasks.get(i);
3741 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3742 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3743 mRecentTasks.remove(i);
3744 i--;
3745 N--;
3746 if (task.intent == null) {
3747 // If the new recent task we are adding is not fully
3748 // specified, then replace it with the existing recent task.
3749 task = tr;
3750 }
3751 }
3752 }
3753 if (N >= MAX_RECENT_TASKS) {
3754 mRecentTasks.remove(N-1);
3755 }
3756 mRecentTasks.add(0, task);
3757 }
3758
3759 public void setRequestedOrientation(IBinder token,
3760 int requestedOrientation) {
3761 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003762 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003763 if (index < 0) {
3764 return;
3765 }
3766 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3767 final long origId = Binder.clearCallingIdentity();
3768 mWindowManager.setAppOrientation(r, requestedOrientation);
3769 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003770 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771 r.mayFreezeScreenLocked(r.app) ? r : null);
3772 if (config != null) {
3773 r.frozenBeforeDestroy = true;
3774 if (!updateConfigurationLocked(config, r)) {
3775 resumeTopActivityLocked(null);
3776 }
3777 }
3778 Binder.restoreCallingIdentity(origId);
3779 }
3780 }
3781
3782 public int getRequestedOrientation(IBinder token) {
3783 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003784 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003785 if (index < 0) {
3786 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3787 }
3788 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3789 return mWindowManager.getAppOrientation(r);
3790 }
3791 }
3792
3793 private final void stopActivityLocked(HistoryRecord r) {
3794 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3795 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3796 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3797 if (!r.finishing) {
3798 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3799 "no-history");
3800 }
3801 } else if (r.app != null && r.app.thread != null) {
3802 if (mFocusedActivity == r) {
3803 setFocusedActivityLocked(topRunningActivityLocked(null));
3804 }
3805 r.resumeKeyDispatchingLocked();
3806 try {
3807 r.stopped = false;
3808 r.state = ActivityState.STOPPING;
3809 if (DEBUG_VISBILITY) Log.v(
3810 TAG, "Stopping visible=" + r.visible + " for " + r);
3811 if (!r.visible) {
3812 mWindowManager.setAppVisibility(r, false);
3813 }
3814 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3815 } catch (Exception e) {
3816 // Maybe just ignore exceptions here... if the process
3817 // has crashed, our death notification will clean things
3818 // up.
3819 Log.w(TAG, "Exception thrown during pause", e);
3820 // Just in case, assume it to be stopped.
3821 r.stopped = true;
3822 r.state = ActivityState.STOPPED;
3823 if (r.configDestroy) {
3824 destroyActivityLocked(r, true);
3825 }
3826 }
3827 }
3828 }
3829
3830 /**
3831 * @return Returns true if the activity is being finished, false if for
3832 * some reason it is being left as-is.
3833 */
3834 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3835 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003836 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 TAG, "Finishing activity: token=" + token
3838 + ", result=" + resultCode + ", data=" + resultData);
3839
Dianne Hackborn75b03852009-06-12 15:43:26 -07003840 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003841 if (index < 0) {
3842 return false;
3843 }
3844 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3845
3846 // Is this the last activity left?
3847 boolean lastActivity = true;
3848 for (int i=mHistory.size()-1; i>=0; i--) {
3849 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3850 if (!p.finishing && p != r) {
3851 lastActivity = false;
3852 break;
3853 }
3854 }
3855
3856 // If this is the last activity, but it is the home activity, then
3857 // just don't finish it.
3858 if (lastActivity) {
3859 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3860 return false;
3861 }
3862 }
3863
3864 finishActivityLocked(r, index, resultCode, resultData, reason);
3865 return true;
3866 }
3867
3868 /**
3869 * @return Returns true if this activity has been removed from the history
3870 * list, or false if it is still in the list and will be removed later.
3871 */
3872 private final boolean finishActivityLocked(HistoryRecord r, int index,
3873 int resultCode, Intent resultData, String reason) {
3874 if (r.finishing) {
3875 Log.w(TAG, "Duplicate finish request for " + r);
3876 return false;
3877 }
3878
3879 r.finishing = true;
3880 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3881 System.identityHashCode(r),
3882 r.task.taskId, r.shortComponentName, reason);
3883 r.task.numActivities--;
3884 if (r.frontOfTask && index < (mHistory.size()-1)) {
3885 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3886 if (next.task == r.task) {
3887 next.frontOfTask = true;
3888 }
3889 }
3890
3891 r.pauseKeyDispatchingLocked();
3892 if (mFocusedActivity == r) {
3893 setFocusedActivityLocked(topRunningActivityLocked(null));
3894 }
3895
3896 // send the result
3897 HistoryRecord resultTo = r.resultTo;
3898 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003899 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3900 + " who=" + r.resultWho + " req=" + r.requestCode
3901 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003902 if (r.info.applicationInfo.uid > 0) {
3903 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3904 r.packageName, resultData, r);
3905 }
3906 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3907 resultData);
3908 r.resultTo = null;
3909 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003910 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003911
3912 // Make sure this HistoryRecord is not holding on to other resources,
3913 // because clients have remote IPC references to this object so we
3914 // can't assume that will go away and want to avoid circular IPC refs.
3915 r.results = null;
3916 r.pendingResults = null;
3917 r.newIntents = null;
3918 r.icicle = null;
3919
3920 if (mPendingThumbnails.size() > 0) {
3921 // There are clients waiting to receive thumbnails so, in case
3922 // this is an activity that someone is waiting for, add it
3923 // to the pending list so we can correctly update the clients.
3924 mCancelledThumbnails.add(r);
3925 }
3926
3927 if (mResumedActivity == r) {
3928 boolean endTask = index <= 0
3929 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3930 if (DEBUG_TRANSITION) Log.v(TAG,
3931 "Prepare close transition: finishing " + r);
3932 mWindowManager.prepareAppTransition(endTask
3933 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3934 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3935
3936 // Tell window manager to prepare for this one to be removed.
3937 mWindowManager.setAppVisibility(r, false);
3938
3939 if (mPausingActivity == null) {
3940 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3941 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3942 startPausingLocked(false, false);
3943 }
3944
3945 } else if (r.state != ActivityState.PAUSING) {
3946 // If the activity is PAUSING, we will complete the finish once
3947 // it is done pausing; else we can just directly finish it here.
3948 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3949 return finishCurrentActivityLocked(r, index,
3950 FINISH_AFTER_PAUSE) == null;
3951 } else {
3952 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3953 }
3954
3955 return false;
3956 }
3957
3958 private static final int FINISH_IMMEDIATELY = 0;
3959 private static final int FINISH_AFTER_PAUSE = 1;
3960 private static final int FINISH_AFTER_VISIBLE = 2;
3961
3962 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3963 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003964 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003965 if (index < 0) {
3966 return null;
3967 }
3968
3969 return finishCurrentActivityLocked(r, index, mode);
3970 }
3971
3972 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3973 int index, int mode) {
3974 // First things first: if this activity is currently visible,
3975 // and the resumed activity is not yet visible, then hold off on
3976 // finishing until the resumed one becomes visible.
3977 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3978 if (!mStoppingActivities.contains(r)) {
3979 mStoppingActivities.add(r);
3980 if (mStoppingActivities.size() > 3) {
3981 // If we already have a few activities waiting to stop,
3982 // then give up on things going idle and start clearing
3983 // them out.
3984 Message msg = Message.obtain();
3985 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3986 mHandler.sendMessage(msg);
3987 }
3988 }
3989 r.state = ActivityState.STOPPING;
3990 updateOomAdjLocked();
3991 return r;
3992 }
3993
3994 // make sure the record is cleaned out of other places.
3995 mStoppingActivities.remove(r);
3996 mWaitingVisibleActivities.remove(r);
3997 if (mResumedActivity == r) {
3998 mResumedActivity = null;
3999 }
4000 final ActivityState prevState = r.state;
4001 r.state = ActivityState.FINISHING;
4002
4003 if (mode == FINISH_IMMEDIATELY
4004 || prevState == ActivityState.STOPPED
4005 || prevState == ActivityState.INITIALIZING) {
4006 // If this activity is already stopped, we can just finish
4007 // it right now.
4008 return destroyActivityLocked(r, true) ? null : r;
4009 } else {
4010 // Need to go through the full pause cycle to get this
4011 // activity into the stopped state and then finish it.
4012 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4013 mFinishingActivities.add(r);
4014 resumeTopActivityLocked(null);
4015 }
4016 return r;
4017 }
4018
4019 /**
4020 * This is the internal entry point for handling Activity.finish().
4021 *
4022 * @param token The Binder token referencing the Activity we want to finish.
4023 * @param resultCode Result code, if any, from this Activity.
4024 * @param resultData Result data (Intent), if any, from this Activity.
4025 *
4026 * @result Returns true if the activity successfully finished, or false if it is still running.
4027 */
4028 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4029 // Refuse possible leaked file descriptors
4030 if (resultData != null && resultData.hasFileDescriptors() == true) {
4031 throw new IllegalArgumentException("File descriptors passed in Intent");
4032 }
4033
4034 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004035 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004036 // Find the first activity that is not finishing.
4037 HistoryRecord next = topRunningActivityLocked(token, 0);
4038 if (next != null) {
4039 // ask watcher if this is allowed
4040 boolean resumeOK = true;
4041 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004042 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004044 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004045 }
4046
4047 if (!resumeOK) {
4048 return false;
4049 }
4050 }
4051 }
4052 final long origId = Binder.clearCallingIdentity();
4053 boolean res = requestFinishActivityLocked(token, resultCode,
4054 resultData, "app-request");
4055 Binder.restoreCallingIdentity(origId);
4056 return res;
4057 }
4058 }
4059
4060 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4061 String resultWho, int requestCode, int resultCode, Intent data) {
4062
4063 if (callingUid > 0) {
4064 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4065 data, r);
4066 }
4067
The Android Open Source Project10592532009-03-18 17:39:46 -07004068 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4069 + " : who=" + resultWho + " req=" + requestCode
4070 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004071 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4072 try {
4073 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4074 list.add(new ResultInfo(resultWho, requestCode,
4075 resultCode, data));
4076 r.app.thread.scheduleSendResult(r, list);
4077 return;
4078 } catch (Exception e) {
4079 Log.w(TAG, "Exception thrown sending result to " + r, e);
4080 }
4081 }
4082
4083 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4084 }
4085
4086 public final void finishSubActivity(IBinder token, String resultWho,
4087 int requestCode) {
4088 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004089 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004090 if (index < 0) {
4091 return;
4092 }
4093 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4094
4095 final long origId = Binder.clearCallingIdentity();
4096
4097 int i;
4098 for (i=mHistory.size()-1; i>=0; i--) {
4099 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4100 if (r.resultTo == self && r.requestCode == requestCode) {
4101 if ((r.resultWho == null && resultWho == null) ||
4102 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4103 finishActivityLocked(r, i,
4104 Activity.RESULT_CANCELED, null, "request-sub");
4105 }
4106 }
4107 }
4108
4109 Binder.restoreCallingIdentity(origId);
4110 }
4111 }
4112
4113 /**
4114 * Perform clean-up of service connections in an activity record.
4115 */
4116 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4117 // Throw away any services that have been bound by this activity.
4118 if (r.connections != null) {
4119 Iterator<ConnectionRecord> it = r.connections.iterator();
4120 while (it.hasNext()) {
4121 ConnectionRecord c = it.next();
4122 removeConnectionLocked(c, null, r);
4123 }
4124 r.connections = null;
4125 }
4126 }
4127
4128 /**
4129 * Perform the common clean-up of an activity record. This is called both
4130 * as part of destroyActivityLocked() (when destroying the client-side
4131 * representation) and cleaning things up as a result of its hosting
4132 * processing going away, in which case there is no remaining client-side
4133 * state to destroy so only the cleanup here is needed.
4134 */
4135 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4136 if (mResumedActivity == r) {
4137 mResumedActivity = null;
4138 }
4139 if (mFocusedActivity == r) {
4140 mFocusedActivity = null;
4141 }
4142
4143 r.configDestroy = false;
4144 r.frozenBeforeDestroy = false;
4145
4146 // Make sure this record is no longer in the pending finishes list.
4147 // This could happen, for example, if we are trimming activities
4148 // down to the max limit while they are still waiting to finish.
4149 mFinishingActivities.remove(r);
4150 mWaitingVisibleActivities.remove(r);
4151
4152 // Remove any pending results.
4153 if (r.finishing && r.pendingResults != null) {
4154 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4155 PendingIntentRecord rec = apr.get();
4156 if (rec != null) {
4157 cancelIntentSenderLocked(rec, false);
4158 }
4159 }
4160 r.pendingResults = null;
4161 }
4162
4163 if (cleanServices) {
4164 cleanUpActivityServicesLocked(r);
4165 }
4166
4167 if (mPendingThumbnails.size() > 0) {
4168 // There are clients waiting to receive thumbnails so, in case
4169 // this is an activity that someone is waiting for, add it
4170 // to the pending list so we can correctly update the clients.
4171 mCancelledThumbnails.add(r);
4172 }
4173
4174 // Get rid of any pending idle timeouts.
4175 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4176 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4177 }
4178
4179 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4180 if (r.state != ActivityState.DESTROYED) {
4181 mHistory.remove(r);
4182 r.inHistory = false;
4183 r.state = ActivityState.DESTROYED;
4184 mWindowManager.removeAppToken(r);
4185 if (VALIDATE_TOKENS) {
4186 mWindowManager.validateAppTokens(mHistory);
4187 }
4188 cleanUpActivityServicesLocked(r);
4189 removeActivityUriPermissionsLocked(r);
4190 }
4191 }
4192
4193 /**
4194 * Destroy the current CLIENT SIDE instance of an activity. This may be
4195 * called both when actually finishing an activity, or when performing
4196 * a configuration switch where we destroy the current client-side object
4197 * but then create a new client-side object for this same HistoryRecord.
4198 */
4199 private final boolean destroyActivityLocked(HistoryRecord r,
4200 boolean removeFromApp) {
4201 if (DEBUG_SWITCH) Log.v(
4202 TAG, "Removing activity: token=" + r
4203 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4204 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4205 System.identityHashCode(r),
4206 r.task.taskId, r.shortComponentName);
4207
4208 boolean removedFromHistory = false;
4209
4210 cleanUpActivityLocked(r, false);
4211
4212 if (r.app != null) {
4213 if (removeFromApp) {
4214 int idx = r.app.activities.indexOf(r);
4215 if (idx >= 0) {
4216 r.app.activities.remove(idx);
4217 }
4218 if (r.persistent) {
4219 decPersistentCountLocked(r.app);
4220 }
4221 }
4222
4223 boolean skipDestroy = false;
4224
4225 try {
4226 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4227 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4228 r.configChangeFlags);
4229 } catch (Exception e) {
4230 // We can just ignore exceptions here... if the process
4231 // has crashed, our death notification will clean things
4232 // up.
4233 //Log.w(TAG, "Exception thrown during finish", e);
4234 if (r.finishing) {
4235 removeActivityFromHistoryLocked(r);
4236 removedFromHistory = true;
4237 skipDestroy = true;
4238 }
4239 }
4240
4241 r.app = null;
4242 r.nowVisible = false;
4243
4244 if (r.finishing && !skipDestroy) {
4245 r.state = ActivityState.DESTROYING;
4246 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4247 msg.obj = r;
4248 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4249 } else {
4250 r.state = ActivityState.DESTROYED;
4251 }
4252 } else {
4253 // remove this record from the history.
4254 if (r.finishing) {
4255 removeActivityFromHistoryLocked(r);
4256 removedFromHistory = true;
4257 } else {
4258 r.state = ActivityState.DESTROYED;
4259 }
4260 }
4261
4262 r.configChangeFlags = 0;
4263
4264 if (!mLRUActivities.remove(r)) {
4265 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4266 }
4267
4268 return removedFromHistory;
4269 }
4270
4271 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4272 ProcessRecord app)
4273 {
4274 int i = list.size();
4275 if (localLOGV) Log.v(
4276 TAG, "Removing app " + app + " from list " + list
4277 + " with " + i + " entries");
4278 while (i > 0) {
4279 i--;
4280 HistoryRecord r = (HistoryRecord)list.get(i);
4281 if (localLOGV) Log.v(
4282 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4283 if (r.app == app) {
4284 if (localLOGV) Log.v(TAG, "Removing this entry!");
4285 list.remove(i);
4286 }
4287 }
4288 }
4289
4290 /**
4291 * Main function for removing an existing process from the activity manager
4292 * as a result of that process going away. Clears out all connections
4293 * to the process.
4294 */
4295 private final void handleAppDiedLocked(ProcessRecord app,
4296 boolean restarting) {
4297 cleanUpApplicationRecordLocked(app, restarting, -1);
4298 if (!restarting) {
4299 mLRUProcesses.remove(app);
4300 }
4301
4302 // Just in case...
4303 if (mPausingActivity != null && mPausingActivity.app == app) {
4304 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4305 mPausingActivity = null;
4306 }
4307 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4308 mLastPausedActivity = null;
4309 }
4310
4311 // Remove this application's activities from active lists.
4312 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4313 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4314 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4315 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4316
4317 boolean atTop = true;
4318 boolean hasVisibleActivities = false;
4319
4320 // Clean out the history list.
4321 int i = mHistory.size();
4322 if (localLOGV) Log.v(
4323 TAG, "Removing app " + app + " from history with " + i + " entries");
4324 while (i > 0) {
4325 i--;
4326 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4327 if (localLOGV) Log.v(
4328 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4329 if (r.app == app) {
4330 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4331 if (localLOGV) Log.v(
4332 TAG, "Removing this entry! frozen=" + r.haveState
4333 + " finishing=" + r.finishing);
4334 mHistory.remove(i);
4335
4336 r.inHistory = false;
4337 mWindowManager.removeAppToken(r);
4338 if (VALIDATE_TOKENS) {
4339 mWindowManager.validateAppTokens(mHistory);
4340 }
4341 removeActivityUriPermissionsLocked(r);
4342
4343 } else {
4344 // We have the current state for this activity, so
4345 // it can be restarted later when needed.
4346 if (localLOGV) Log.v(
4347 TAG, "Keeping entry, setting app to null");
4348 if (r.visible) {
4349 hasVisibleActivities = true;
4350 }
4351 r.app = null;
4352 r.nowVisible = false;
4353 if (!r.haveState) {
4354 r.icicle = null;
4355 }
4356 }
4357
4358 cleanUpActivityLocked(r, true);
4359 r.state = ActivityState.STOPPED;
4360 }
4361 atTop = false;
4362 }
4363
4364 app.activities.clear();
4365
4366 if (app.instrumentationClass != null) {
4367 Log.w(TAG, "Crash of app " + app.processName
4368 + " running instrumentation " + app.instrumentationClass);
4369 Bundle info = new Bundle();
4370 info.putString("shortMsg", "Process crashed.");
4371 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4372 }
4373
4374 if (!restarting) {
4375 if (!resumeTopActivityLocked(null)) {
4376 // If there was nothing to resume, and we are not already
4377 // restarting this process, but there is a visible activity that
4378 // is hosted by the process... then make sure all visible
4379 // activities are running, taking care of restarting this
4380 // process.
4381 if (hasVisibleActivities) {
4382 ensureActivitiesVisibleLocked(null, 0);
4383 }
4384 }
4385 }
4386 }
4387
4388 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4389 IBinder threadBinder = thread.asBinder();
4390
4391 // Find the application record.
4392 int count = mLRUProcesses.size();
4393 int i;
4394 for (i=0; i<count; i++) {
4395 ProcessRecord rec = mLRUProcesses.get(i);
4396 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4397 return i;
4398 }
4399 }
4400 return -1;
4401 }
4402
4403 private final ProcessRecord getRecordForAppLocked(
4404 IApplicationThread thread) {
4405 if (thread == null) {
4406 return null;
4407 }
4408
4409 int appIndex = getLRURecordIndexForAppLocked(thread);
4410 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4411 }
4412
4413 private final void appDiedLocked(ProcessRecord app, int pid,
4414 IApplicationThread thread) {
4415
4416 mProcDeaths[0]++;
4417
4418 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4419 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4420 + ") has died.");
4421 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4422 if (localLOGV) Log.v(
4423 TAG, "Dying app: " + app + ", pid: " + pid
4424 + ", thread: " + thread.asBinder());
4425 boolean doLowMem = app.instrumentationClass == null;
4426 handleAppDiedLocked(app, false);
4427
4428 if (doLowMem) {
4429 // If there are no longer any background processes running,
4430 // and the app that died was not running instrumentation,
4431 // then tell everyone we are now low on memory.
4432 boolean haveBg = false;
4433 int count = mLRUProcesses.size();
4434 int i;
4435 for (i=0; i<count; i++) {
4436 ProcessRecord rec = mLRUProcesses.get(i);
4437 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4438 haveBg = true;
4439 break;
4440 }
4441 }
4442
4443 if (!haveBg) {
4444 Log.i(TAG, "Low Memory: No more background processes.");
4445 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4446 for (i=0; i<count; i++) {
4447 ProcessRecord rec = mLRUProcesses.get(i);
4448 if (rec.thread != null) {
4449 rec.lastRequestedGc = SystemClock.uptimeMillis();
4450 try {
4451 rec.thread.scheduleLowMemory();
4452 } catch (RemoteException e) {
4453 // Don't care if the process is gone.
4454 }
4455 }
4456 }
4457 }
4458 }
4459 } else if (Config.LOGD) {
4460 Log.d(TAG, "Received spurious death notification for thread "
4461 + thread.asBinder());
4462 }
4463 }
4464
4465 final String readFile(String filename) {
4466 try {
4467 FileInputStream fs = new FileInputStream(filename);
4468 byte[] inp = new byte[8192];
4469 int size = fs.read(inp);
4470 fs.close();
4471 return new String(inp, 0, 0, size);
4472 } catch (java.io.IOException e) {
4473 }
4474 return "";
4475 }
4476
4477 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004478 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004479 if (app.notResponding || app.crashing) {
4480 return;
4481 }
4482
4483 // Log the ANR to the event log.
4484 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4485
4486 // If we are on a secure build and the application is not interesting to the user (it is
4487 // not visible or in the background), just kill it instead of displaying a dialog.
4488 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4489 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4490 Process.killProcess(app.pid);
4491 return;
4492 }
4493
4494 // DeviceMonitor.start();
4495
4496 String processInfo = null;
4497 if (MONITOR_CPU_USAGE) {
4498 updateCpuStatsNow();
4499 synchronized (mProcessStatsThread) {
4500 processInfo = mProcessStats.printCurrentState();
4501 }
4502 }
4503
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004504 StringBuilder info = mStringBuilder;
4505 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004506 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004507 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004508 if (reportedActivity != null && reportedActivity.app != null) {
4509 info.append(" (last in ");
4510 info.append(reportedActivity.app.processName);
4511 info.append(")");
4512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004513 if (annotation != null) {
4514 info.append("\nAnnotation: ");
4515 info.append(annotation);
4516 }
4517 if (MONITOR_CPU_USAGE) {
4518 info.append("\nCPU usage:\n");
4519 info.append(processInfo);
4520 }
4521 Log.i(TAG, info.toString());
4522
4523 // The application is not responding. Dump as many thread traces as we can.
4524 boolean fileDump = prepareTraceFile(true);
4525 if (!fileDump) {
4526 // Dumping traces to the log, just dump the process that isn't responding so
4527 // we don't overflow the log
4528 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4529 } else {
4530 // Dumping traces to a file so dump all active processes we know about
4531 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004532 // First, these are the most important processes.
4533 final int[] imppids = new int[3];
4534 int i=0;
4535 imppids[0] = app.pid;
4536 i++;
4537 if (reportedActivity != null && reportedActivity.app != null
4538 && reportedActivity.app.thread != null
4539 && reportedActivity.app.pid != app.pid) {
4540 imppids[i] = reportedActivity.app.pid;
4541 i++;
4542 }
4543 imppids[i] = Process.myPid();
4544 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4545 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4546 synchronized (this) {
4547 try {
4548 wait(200);
4549 } catch (InterruptedException e) {
4550 }
4551 }
4552 }
4553 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004554 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004555 boolean done = false;
4556 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4557 if (imppids[j] == r.pid) {
4558 done = true;
4559 break;
4560 }
4561 }
4562 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004563 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004564 synchronized (this) {
4565 try {
4566 wait(200);
4567 } catch (InterruptedException e) {
4568 }
4569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004570 }
4571 }
4572 }
4573 }
4574
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004575 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004576 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004577 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004578 app.pid, info.toString());
4579 if (res != 0) {
4580 if (res < 0) {
4581 // wait until the SIGQUIT has had a chance to process before killing the
4582 // process.
4583 try {
4584 wait(2000);
4585 } catch (InterruptedException e) {
4586 }
4587
4588 Process.killProcess(app.pid);
4589 return;
4590 }
4591 }
4592 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004593 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004594 }
4595 }
4596
4597 makeAppNotRespondingLocked(app,
4598 activity != null ? activity.shortComponentName : null,
4599 annotation != null ? "ANR " + annotation : "ANR",
4600 info.toString(), null);
4601 Message msg = Message.obtain();
4602 HashMap map = new HashMap();
4603 msg.what = SHOW_NOT_RESPONDING_MSG;
4604 msg.obj = map;
4605 map.put("app", app);
4606 if (activity != null) {
4607 map.put("activity", activity);
4608 }
4609
4610 mHandler.sendMessage(msg);
4611 return;
4612 }
4613
4614 /**
4615 * If a stack trace file has been configured, prepare the filesystem
4616 * by creating the directory if it doesn't exist and optionally
4617 * removing the old trace file.
4618 *
4619 * @param removeExisting If set, the existing trace file will be removed.
4620 * @return Returns true if the trace file preparations succeeded
4621 */
4622 public static boolean prepareTraceFile(boolean removeExisting) {
4623 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4624 boolean fileReady = false;
4625 if (!TextUtils.isEmpty(tracesPath)) {
4626 File f = new File(tracesPath);
4627 if (!f.exists()) {
4628 // Ensure the enclosing directory exists
4629 File dir = f.getParentFile();
4630 if (!dir.exists()) {
4631 fileReady = dir.mkdirs();
4632 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004633 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 } else if (dir.isDirectory()) {
4635 fileReady = true;
4636 }
4637 } else if (removeExisting) {
4638 // Remove the previous traces file, so we don't fill the disk.
4639 // The VM will recreate it
4640 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4641 fileReady = f.delete();
4642 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004643
4644 if (removeExisting) {
4645 try {
4646 f.createNewFile();
4647 FileUtils.setPermissions(f.getAbsolutePath(),
4648 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4649 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4650 fileReady = true;
4651 } catch (IOException e) {
4652 Log.w(TAG, "Unable to make ANR traces file", e);
4653 }
4654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004655 }
4656
4657 return fileReady;
4658 }
4659
4660
4661 private final void decPersistentCountLocked(ProcessRecord app)
4662 {
4663 app.persistentActivities--;
4664 if (app.persistentActivities > 0) {
4665 // Still more of 'em...
4666 return;
4667 }
4668 if (app.persistent) {
4669 // Ah, but the application itself is persistent. Whatever!
4670 return;
4671 }
4672
4673 // App is no longer persistent... make sure it and the ones
4674 // following it in the LRU list have the correc oom_adj.
4675 updateOomAdjLocked();
4676 }
4677
4678 public void setPersistent(IBinder token, boolean isPersistent) {
4679 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4680 != PackageManager.PERMISSION_GRANTED) {
4681 String msg = "Permission Denial: setPersistent() from pid="
4682 + Binder.getCallingPid()
4683 + ", uid=" + Binder.getCallingUid()
4684 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4685 Log.w(TAG, msg);
4686 throw new SecurityException(msg);
4687 }
4688
4689 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004690 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004691 if (index < 0) {
4692 return;
4693 }
4694 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4695 ProcessRecord app = r.app;
4696
4697 if (localLOGV) Log.v(
4698 TAG, "Setting persistence " + isPersistent + ": " + r);
4699
4700 if (isPersistent) {
4701 if (r.persistent) {
4702 // Okay okay, I heard you already!
4703 if (localLOGV) Log.v(TAG, "Already persistent!");
4704 return;
4705 }
4706 r.persistent = true;
4707 app.persistentActivities++;
4708 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4709 if (app.persistentActivities > 1) {
4710 // We aren't the first...
4711 if (localLOGV) Log.v(TAG, "Not the first!");
4712 return;
4713 }
4714 if (app.persistent) {
4715 // This would be redundant.
4716 if (localLOGV) Log.v(TAG, "App is persistent!");
4717 return;
4718 }
4719
4720 // App is now persistent... make sure it and the ones
4721 // following it now have the correct oom_adj.
4722 final long origId = Binder.clearCallingIdentity();
4723 updateOomAdjLocked();
4724 Binder.restoreCallingIdentity(origId);
4725
4726 } else {
4727 if (!r.persistent) {
4728 // Okay okay, I heard you already!
4729 return;
4730 }
4731 r.persistent = false;
4732 final long origId = Binder.clearCallingIdentity();
4733 decPersistentCountLocked(app);
4734 Binder.restoreCallingIdentity(origId);
4735
4736 }
4737 }
4738 }
4739
4740 public boolean clearApplicationUserData(final String packageName,
4741 final IPackageDataObserver observer) {
4742 int uid = Binder.getCallingUid();
4743 int pid = Binder.getCallingPid();
4744 long callingId = Binder.clearCallingIdentity();
4745 try {
4746 IPackageManager pm = ActivityThread.getPackageManager();
4747 int pkgUid = -1;
4748 synchronized(this) {
4749 try {
4750 pkgUid = pm.getPackageUid(packageName);
4751 } catch (RemoteException e) {
4752 }
4753 if (pkgUid == -1) {
4754 Log.w(TAG, "Invalid packageName:" + packageName);
4755 return false;
4756 }
4757 if (uid == pkgUid || checkComponentPermission(
4758 android.Manifest.permission.CLEAR_APP_USER_DATA,
4759 pid, uid, -1)
4760 == PackageManager.PERMISSION_GRANTED) {
4761 restartPackageLocked(packageName, pkgUid);
4762 } else {
4763 throw new SecurityException(pid+" does not have permission:"+
4764 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4765 "for process:"+packageName);
4766 }
4767 }
4768
4769 try {
4770 //clear application user data
4771 pm.clearApplicationUserData(packageName, observer);
4772 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4773 Uri.fromParts("package", packageName, null));
4774 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4775 broadcastIntentLocked(null, null, intent,
4776 null, null, 0, null, null, null,
4777 false, false, MY_PID, Process.SYSTEM_UID);
4778 } catch (RemoteException e) {
4779 }
4780 } finally {
4781 Binder.restoreCallingIdentity(callingId);
4782 }
4783 return true;
4784 }
4785
4786 public void restartPackage(final String packageName) {
4787 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4788 != PackageManager.PERMISSION_GRANTED) {
4789 String msg = "Permission Denial: restartPackage() from pid="
4790 + Binder.getCallingPid()
4791 + ", uid=" + Binder.getCallingUid()
4792 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4793 Log.w(TAG, msg);
4794 throw new SecurityException(msg);
4795 }
4796
4797 long callingId = Binder.clearCallingIdentity();
4798 try {
4799 IPackageManager pm = ActivityThread.getPackageManager();
4800 int pkgUid = -1;
4801 synchronized(this) {
4802 try {
4803 pkgUid = pm.getPackageUid(packageName);
4804 } catch (RemoteException e) {
4805 }
4806 if (pkgUid == -1) {
4807 Log.w(TAG, "Invalid packageName: " + packageName);
4808 return;
4809 }
4810 restartPackageLocked(packageName, pkgUid);
4811 }
4812 } finally {
4813 Binder.restoreCallingIdentity(callingId);
4814 }
4815 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004816
4817 /*
4818 * The pkg name and uid have to be specified.
4819 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4820 */
4821 public void killApplicationWithUid(String pkg, int uid) {
4822 if (pkg == null) {
4823 return;
4824 }
4825 // Make sure the uid is valid.
4826 if (uid < 0) {
4827 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4828 return;
4829 }
4830 int callerUid = Binder.getCallingUid();
4831 // Only the system server can kill an application
4832 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004833 // Post an aysnc message to kill the application
4834 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4835 msg.arg1 = uid;
4836 msg.arg2 = 0;
4837 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004838 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004839 } else {
4840 throw new SecurityException(callerUid + " cannot kill pkg: " +
4841 pkg);
4842 }
4843 }
4844
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004845 public void closeSystemDialogs(String reason) {
4846 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4847 if (reason != null) {
4848 intent.putExtra("reason", reason);
4849 }
4850
4851 final int uid = Binder.getCallingUid();
4852 final long origId = Binder.clearCallingIdentity();
4853 synchronized (this) {
4854 int i = mWatchers.beginBroadcast();
4855 while (i > 0) {
4856 i--;
4857 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4858 if (w != null) {
4859 try {
4860 w.closingSystemDialogs(reason);
4861 } catch (RemoteException e) {
4862 }
4863 }
4864 }
4865 mWatchers.finishBroadcast();
4866
4867 broadcastIntentLocked(null, null, intent, null,
4868 null, 0, null, null, null, false, false, -1, uid);
4869 }
4870 Binder.restoreCallingIdentity(origId);
4871 }
4872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004873 private void restartPackageLocked(final String packageName, int uid) {
4874 uninstallPackageLocked(packageName, uid, false);
4875 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4876 Uri.fromParts("package", packageName, null));
4877 intent.putExtra(Intent.EXTRA_UID, uid);
4878 broadcastIntentLocked(null, null, intent,
4879 null, null, 0, null, null, null,
4880 false, false, MY_PID, Process.SYSTEM_UID);
4881 }
4882
4883 private final void uninstallPackageLocked(String name, int uid,
4884 boolean callerWillRestart) {
4885 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4886
4887 int i, N;
4888
4889 final String procNamePrefix = name + ":";
4890 if (uid < 0) {
4891 try {
4892 uid = ActivityThread.getPackageManager().getPackageUid(name);
4893 } catch (RemoteException e) {
4894 }
4895 }
4896
4897 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4898 while (badApps.hasNext()) {
4899 SparseArray<Long> ba = badApps.next();
4900 if (ba.get(uid) != null) {
4901 badApps.remove();
4902 }
4903 }
4904
4905 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4906
4907 // Remove all processes this package may have touched: all with the
4908 // same UID (except for the system or root user), and all whose name
4909 // matches the package name.
4910 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4911 final int NA = apps.size();
4912 for (int ia=0; ia<NA; ia++) {
4913 ProcessRecord app = apps.valueAt(ia);
4914 if (app.removed) {
4915 procs.add(app);
4916 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4917 || app.processName.equals(name)
4918 || app.processName.startsWith(procNamePrefix)) {
4919 app.removed = true;
4920 procs.add(app);
4921 }
4922 }
4923 }
4924
4925 N = procs.size();
4926 for (i=0; i<N; i++) {
4927 removeProcessLocked(procs.get(i), callerWillRestart);
4928 }
4929
4930 for (i=mHistory.size()-1; i>=0; i--) {
4931 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4932 if (r.packageName.equals(name)) {
4933 if (Config.LOGD) Log.d(
4934 TAG, " Force finishing activity "
4935 + r.intent.getComponent().flattenToShortString());
4936 if (r.app != null) {
4937 r.app.removed = true;
4938 }
4939 r.app = null;
4940 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4941 }
4942 }
4943
4944 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4945 for (ServiceRecord service : mServices.values()) {
4946 if (service.packageName.equals(name)) {
4947 if (service.app != null) {
4948 service.app.removed = true;
4949 }
4950 service.app = null;
4951 services.add(service);
4952 }
4953 }
4954
4955 N = services.size();
4956 for (i=0; i<N; i++) {
4957 bringDownServiceLocked(services.get(i), true);
4958 }
4959
4960 resumeTopActivityLocked(null);
4961 }
4962
4963 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4964 final String name = app.processName;
4965 final int uid = app.info.uid;
4966 if (Config.LOGD) Log.d(
4967 TAG, "Force removing process " + app + " (" + name
4968 + "/" + uid + ")");
4969
4970 mProcessNames.remove(name, uid);
4971 boolean needRestart = false;
4972 if (app.pid > 0 && app.pid != MY_PID) {
4973 int pid = app.pid;
4974 synchronized (mPidsSelfLocked) {
4975 mPidsSelfLocked.remove(pid);
4976 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4977 }
4978 handleAppDiedLocked(app, true);
4979 mLRUProcesses.remove(app);
4980 Process.killProcess(pid);
4981
4982 if (app.persistent) {
4983 if (!callerWillRestart) {
4984 addAppLocked(app.info);
4985 } else {
4986 needRestart = true;
4987 }
4988 }
4989 } else {
4990 mRemovedProcesses.add(app);
4991 }
4992
4993 return needRestart;
4994 }
4995
4996 private final void processStartTimedOutLocked(ProcessRecord app) {
4997 final int pid = app.pid;
4998 boolean gone = false;
4999 synchronized (mPidsSelfLocked) {
5000 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5001 if (knownApp != null && knownApp.thread == null) {
5002 mPidsSelfLocked.remove(pid);
5003 gone = true;
5004 }
5005 }
5006
5007 if (gone) {
5008 Log.w(TAG, "Process " + app + " failed to attach");
5009 mProcessNames.remove(app.processName, app.info.uid);
5010 Process.killProcess(pid);
5011 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5012 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5013 mPendingBroadcast = null;
5014 scheduleBroadcastsLocked();
5015 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005016 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5017 Log.w(TAG, "Unattached app died before backup, skipping");
5018 try {
5019 IBackupManager bm = IBackupManager.Stub.asInterface(
5020 ServiceManager.getService(Context.BACKUP_SERVICE));
5021 bm.agentDisconnected(app.info.packageName);
5022 } catch (RemoteException e) {
5023 // Can't happen; the backup manager is local
5024 }
5025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005026 } else {
5027 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5028 }
5029 }
5030
5031 private final boolean attachApplicationLocked(IApplicationThread thread,
5032 int pid) {
5033
5034 // Find the application record that is being attached... either via
5035 // the pid if we are running in multiple processes, or just pull the
5036 // next app record if we are emulating process with anonymous threads.
5037 ProcessRecord app;
5038 if (pid != MY_PID && pid >= 0) {
5039 synchronized (mPidsSelfLocked) {
5040 app = mPidsSelfLocked.get(pid);
5041 }
5042 } else if (mStartingProcesses.size() > 0) {
5043 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005044 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005045 } else {
5046 app = null;
5047 }
5048
5049 if (app == null) {
5050 Log.w(TAG, "No pending application record for pid " + pid
5051 + " (IApplicationThread " + thread + "); dropping process");
5052 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5053 if (pid > 0 && pid != MY_PID) {
5054 Process.killProcess(pid);
5055 } else {
5056 try {
5057 thread.scheduleExit();
5058 } catch (Exception e) {
5059 // Ignore exceptions.
5060 }
5061 }
5062 return false;
5063 }
5064
5065 // If this application record is still attached to a previous
5066 // process, clean it up now.
5067 if (app.thread != null) {
5068 handleAppDiedLocked(app, true);
5069 }
5070
5071 // Tell the process all about itself.
5072
5073 if (localLOGV) Log.v(
5074 TAG, "Binding process pid " + pid + " to record " + app);
5075
5076 String processName = app.processName;
5077 try {
5078 thread.asBinder().linkToDeath(new AppDeathRecipient(
5079 app, pid, thread), 0);
5080 } catch (RemoteException e) {
5081 app.resetPackageList();
5082 startProcessLocked(app, "link fail", processName);
5083 return false;
5084 }
5085
5086 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5087
5088 app.thread = thread;
5089 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005090 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005091 app.forcingToForeground = null;
5092 app.foregroundServices = false;
5093 app.debugging = false;
5094
5095 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5096
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005097 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5098 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005099
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005100 if (!normalMode) {
5101 Log.i(TAG, "Launching preboot mode app: " + app);
5102 }
5103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005104 if (localLOGV) Log.v(
5105 TAG, "New app record " + app
5106 + " thread=" + thread.asBinder() + " pid=" + pid);
5107 try {
5108 int testMode = IApplicationThread.DEBUG_OFF;
5109 if (mDebugApp != null && mDebugApp.equals(processName)) {
5110 testMode = mWaitForDebugger
5111 ? IApplicationThread.DEBUG_WAIT
5112 : IApplicationThread.DEBUG_ON;
5113 app.debugging = true;
5114 if (mDebugTransient) {
5115 mDebugApp = mOrigDebugApp;
5116 mWaitForDebugger = mOrigWaitForDebugger;
5117 }
5118 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005119
Christopher Tate181fafa2009-05-14 11:12:14 -07005120 // If the app is being launched for restore or full backup, set it up specially
5121 boolean isRestrictedBackupMode = false;
5122 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5123 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5124 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5125 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005126
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005127 ensurePackageDexOpt(app.instrumentationInfo != null
5128 ? app.instrumentationInfo.packageName
5129 : app.info.packageName);
5130 if (app.instrumentationClass != null) {
5131 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005132 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005133 thread.bindApplication(processName, app.instrumentationInfo != null
5134 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005135 app.instrumentationClass, app.instrumentationProfileFile,
5136 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005137 isRestrictedBackupMode || !normalMode,
5138 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005139 updateLRUListLocked(app, false);
5140 app.lastRequestedGc = SystemClock.uptimeMillis();
5141 } catch (Exception e) {
5142 // todo: Yikes! What should we do? For now we will try to
5143 // start another process, but that could easily get us in
5144 // an infinite loop of restarting processes...
5145 Log.w(TAG, "Exception thrown during bind!", e);
5146
5147 app.resetPackageList();
5148 startProcessLocked(app, "bind fail", processName);
5149 return false;
5150 }
5151
5152 // Remove this record from the list of starting applications.
5153 mPersistentStartingProcesses.remove(app);
5154 mProcessesOnHold.remove(app);
5155
5156 boolean badApp = false;
5157 boolean didSomething = false;
5158
5159 // See if the top visible activity is waiting to run in this process...
5160 HistoryRecord hr = topRunningActivityLocked(null);
5161 if (hr != null) {
5162 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5163 && processName.equals(hr.processName)) {
5164 try {
5165 if (realStartActivityLocked(hr, app, true, true)) {
5166 didSomething = true;
5167 }
5168 } catch (Exception e) {
5169 Log.w(TAG, "Exception in new application when starting activity "
5170 + hr.intent.getComponent().flattenToShortString(), e);
5171 badApp = true;
5172 }
5173 } else {
5174 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5175 }
5176 }
5177
5178 // Find any services that should be running in this process...
5179 if (!badApp && mPendingServices.size() > 0) {
5180 ServiceRecord sr = null;
5181 try {
5182 for (int i=0; i<mPendingServices.size(); i++) {
5183 sr = mPendingServices.get(i);
5184 if (app.info.uid != sr.appInfo.uid
5185 || !processName.equals(sr.processName)) {
5186 continue;
5187 }
5188
5189 mPendingServices.remove(i);
5190 i--;
5191 realStartServiceLocked(sr, app);
5192 didSomething = true;
5193 }
5194 } catch (Exception e) {
5195 Log.w(TAG, "Exception in new application when starting service "
5196 + sr.shortName, e);
5197 badApp = true;
5198 }
5199 }
5200
5201 // Check if the next broadcast receiver is in this process...
5202 BroadcastRecord br = mPendingBroadcast;
5203 if (!badApp && br != null && br.curApp == app) {
5204 try {
5205 mPendingBroadcast = null;
5206 processCurBroadcastLocked(br, app);
5207 didSomething = true;
5208 } catch (Exception e) {
5209 Log.w(TAG, "Exception in new application when starting receiver "
5210 + br.curComponent.flattenToShortString(), e);
5211 badApp = true;
5212 logBroadcastReceiverDiscard(br);
5213 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5214 br.resultExtras, br.resultAbort, true);
5215 scheduleBroadcastsLocked();
5216 }
5217 }
5218
Christopher Tate181fafa2009-05-14 11:12:14 -07005219 // Check whether the next backup agent is in this process...
5220 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5221 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005222 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005223 try {
5224 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5225 } catch (Exception e) {
5226 Log.w(TAG, "Exception scheduling backup agent creation: ");
5227 e.printStackTrace();
5228 }
5229 }
5230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005231 if (badApp) {
5232 // todo: Also need to kill application to deal with all
5233 // kinds of exceptions.
5234 handleAppDiedLocked(app, false);
5235 return false;
5236 }
5237
5238 if (!didSomething) {
5239 updateOomAdjLocked();
5240 }
5241
5242 return true;
5243 }
5244
5245 public final void attachApplication(IApplicationThread thread) {
5246 synchronized (this) {
5247 int callingPid = Binder.getCallingPid();
5248 final long origId = Binder.clearCallingIdentity();
5249 attachApplicationLocked(thread, callingPid);
5250 Binder.restoreCallingIdentity(origId);
5251 }
5252 }
5253
5254 public final void activityIdle(IBinder token) {
5255 final long origId = Binder.clearCallingIdentity();
5256 activityIdleInternal(token, false);
5257 Binder.restoreCallingIdentity(origId);
5258 }
5259
5260 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5261 boolean remove) {
5262 int N = mStoppingActivities.size();
5263 if (N <= 0) return null;
5264
5265 ArrayList<HistoryRecord> stops = null;
5266
5267 final boolean nowVisible = mResumedActivity != null
5268 && mResumedActivity.nowVisible
5269 && !mResumedActivity.waitingVisible;
5270 for (int i=0; i<N; i++) {
5271 HistoryRecord s = mStoppingActivities.get(i);
5272 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5273 + nowVisible + " waitingVisible=" + s.waitingVisible
5274 + " finishing=" + s.finishing);
5275 if (s.waitingVisible && nowVisible) {
5276 mWaitingVisibleActivities.remove(s);
5277 s.waitingVisible = false;
5278 if (s.finishing) {
5279 // If this activity is finishing, it is sitting on top of
5280 // everyone else but we now know it is no longer needed...
5281 // so get rid of it. Otherwise, we need to go through the
5282 // normal flow and hide it once we determine that it is
5283 // hidden by the activities in front of it.
5284 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5285 mWindowManager.setAppVisibility(s, false);
5286 }
5287 }
5288 if (!s.waitingVisible && remove) {
5289 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5290 if (stops == null) {
5291 stops = new ArrayList<HistoryRecord>();
5292 }
5293 stops.add(s);
5294 mStoppingActivities.remove(i);
5295 N--;
5296 i--;
5297 }
5298 }
5299
5300 return stops;
5301 }
5302
5303 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005304 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5305 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005306 mWindowManager.enableScreenAfterBoot();
5307 }
5308
5309 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5310 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5311
5312 ArrayList<HistoryRecord> stops = null;
5313 ArrayList<HistoryRecord> finishes = null;
5314 ArrayList<HistoryRecord> thumbnails = null;
5315 int NS = 0;
5316 int NF = 0;
5317 int NT = 0;
5318 IApplicationThread sendThumbnail = null;
5319 boolean booting = false;
5320 boolean enableScreen = false;
5321
5322 synchronized (this) {
5323 if (token != null) {
5324 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5325 }
5326
5327 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005328 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005329 if (index >= 0) {
5330 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5331
5332 // No longer need to keep the device awake.
5333 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5334 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5335 mLaunchingActivity.release();
5336 }
5337
5338 // We are now idle. If someone is waiting for a thumbnail from
5339 // us, we can now deliver.
5340 r.idle = true;
5341 scheduleAppGcsLocked();
5342 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5343 sendThumbnail = r.app.thread;
5344 r.thumbnailNeeded = false;
5345 }
5346
5347 // If this activity is fullscreen, set up to hide those under it.
5348
5349 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5350 ensureActivitiesVisibleLocked(null, 0);
5351
5352 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5353 if (!mBooted && !fromTimeout) {
5354 mBooted = true;
5355 enableScreen = true;
5356 }
5357 }
5358
5359 // Atomically retrieve all of the other things to do.
5360 stops = processStoppingActivitiesLocked(true);
5361 NS = stops != null ? stops.size() : 0;
5362 if ((NF=mFinishingActivities.size()) > 0) {
5363 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5364 mFinishingActivities.clear();
5365 }
5366 if ((NT=mCancelledThumbnails.size()) > 0) {
5367 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5368 mCancelledThumbnails.clear();
5369 }
5370
5371 booting = mBooting;
5372 mBooting = false;
5373 }
5374
5375 int i;
5376
5377 // Send thumbnail if requested.
5378 if (sendThumbnail != null) {
5379 try {
5380 sendThumbnail.requestThumbnail(token);
5381 } catch (Exception e) {
5382 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5383 sendPendingThumbnail(null, token, null, null, true);
5384 }
5385 }
5386
5387 // Stop any activities that are scheduled to do so but have been
5388 // waiting for the next one to start.
5389 for (i=0; i<NS; i++) {
5390 HistoryRecord r = (HistoryRecord)stops.get(i);
5391 synchronized (this) {
5392 if (r.finishing) {
5393 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5394 } else {
5395 stopActivityLocked(r);
5396 }
5397 }
5398 }
5399
5400 // Finish any activities that are scheduled to do so but have been
5401 // waiting for the next one to start.
5402 for (i=0; i<NF; i++) {
5403 HistoryRecord r = (HistoryRecord)finishes.get(i);
5404 synchronized (this) {
5405 destroyActivityLocked(r, true);
5406 }
5407 }
5408
5409 // Report back to any thumbnail receivers.
5410 for (i=0; i<NT; i++) {
5411 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5412 sendPendingThumbnail(r, null, null, null, true);
5413 }
5414
5415 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005416 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005417 }
5418
5419 trimApplications();
5420 //dump();
5421 //mWindowManager.dump();
5422
5423 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005424 enableScreenAfterBoot();
5425 }
5426 }
5427
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005428 final void finishBooting() {
5429 // Ensure that any processes we had put on hold are now started
5430 // up.
5431 final int NP = mProcessesOnHold.size();
5432 if (NP > 0) {
5433 ArrayList<ProcessRecord> procs =
5434 new ArrayList<ProcessRecord>(mProcessesOnHold);
5435 for (int ip=0; ip<NP; ip++) {
5436 this.startProcessLocked(procs.get(ip), "on-hold", null);
5437 }
5438 }
5439 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5440 // Tell anyone interested that we are done booting!
5441 synchronized (this) {
5442 broadcastIntentLocked(null, null,
5443 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5444 null, null, 0, null, null,
5445 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5446 false, false, MY_PID, Process.SYSTEM_UID);
5447 }
5448 }
5449 }
5450
5451 final void ensureBootCompleted() {
5452 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005453 boolean enableScreen;
5454 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005455 booting = mBooting;
5456 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005457 enableScreen = !mBooted;
5458 mBooted = true;
5459 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005460
5461 if (booting) {
5462 finishBooting();
5463 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005464
5465 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005466 enableScreenAfterBoot();
5467 }
5468 }
5469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005470 public final void activityPaused(IBinder token, Bundle icicle) {
5471 // Refuse possible leaked file descriptors
5472 if (icicle != null && icicle.hasFileDescriptors()) {
5473 throw new IllegalArgumentException("File descriptors passed in Bundle");
5474 }
5475
5476 final long origId = Binder.clearCallingIdentity();
5477 activityPaused(token, icicle, false);
5478 Binder.restoreCallingIdentity(origId);
5479 }
5480
5481 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5482 if (DEBUG_PAUSE) Log.v(
5483 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5484 + ", timeout=" + timeout);
5485
5486 HistoryRecord r = null;
5487
5488 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005489 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005490 if (index >= 0) {
5491 r = (HistoryRecord)mHistory.get(index);
5492 if (!timeout) {
5493 r.icicle = icicle;
5494 r.haveState = true;
5495 }
5496 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5497 if (mPausingActivity == r) {
5498 r.state = ActivityState.PAUSED;
5499 completePauseLocked();
5500 } else {
5501 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5502 System.identityHashCode(r), r.shortComponentName,
5503 mPausingActivity != null
5504 ? mPausingActivity.shortComponentName : "(none)");
5505 }
5506 }
5507 }
5508 }
5509
5510 public final void activityStopped(IBinder token, Bitmap thumbnail,
5511 CharSequence description) {
5512 if (localLOGV) Log.v(
5513 TAG, "Activity stopped: token=" + token);
5514
5515 HistoryRecord r = null;
5516
5517 final long origId = Binder.clearCallingIdentity();
5518
5519 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005520 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005521 if (index >= 0) {
5522 r = (HistoryRecord)mHistory.get(index);
5523 r.thumbnail = thumbnail;
5524 r.description = description;
5525 r.stopped = true;
5526 r.state = ActivityState.STOPPED;
5527 if (!r.finishing) {
5528 if (r.configDestroy) {
5529 destroyActivityLocked(r, true);
5530 resumeTopActivityLocked(null);
5531 }
5532 }
5533 }
5534 }
5535
5536 if (r != null) {
5537 sendPendingThumbnail(r, null, null, null, false);
5538 }
5539
5540 trimApplications();
5541
5542 Binder.restoreCallingIdentity(origId);
5543 }
5544
5545 public final void activityDestroyed(IBinder token) {
5546 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5547 synchronized (this) {
5548 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5549
Dianne Hackborn75b03852009-06-12 15:43:26 -07005550 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005551 if (index >= 0) {
5552 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5553 if (r.state == ActivityState.DESTROYING) {
5554 final long origId = Binder.clearCallingIdentity();
5555 removeActivityFromHistoryLocked(r);
5556 Binder.restoreCallingIdentity(origId);
5557 }
5558 }
5559 }
5560 }
5561
5562 public String getCallingPackage(IBinder token) {
5563 synchronized (this) {
5564 HistoryRecord r = getCallingRecordLocked(token);
5565 return r != null && r.app != null ? r.app.processName : null;
5566 }
5567 }
5568
5569 public ComponentName getCallingActivity(IBinder token) {
5570 synchronized (this) {
5571 HistoryRecord r = getCallingRecordLocked(token);
5572 return r != null ? r.intent.getComponent() : null;
5573 }
5574 }
5575
5576 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005577 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005578 if (index >= 0) {
5579 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5580 if (r != null) {
5581 return r.resultTo;
5582 }
5583 }
5584 return null;
5585 }
5586
5587 public ComponentName getActivityClassForToken(IBinder token) {
5588 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005589 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005590 if (index >= 0) {
5591 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5592 return r.intent.getComponent();
5593 }
5594 return null;
5595 }
5596 }
5597
5598 public String getPackageForToken(IBinder token) {
5599 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005600 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005601 if (index >= 0) {
5602 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5603 return r.packageName;
5604 }
5605 return null;
5606 }
5607 }
5608
5609 public IIntentSender getIntentSender(int type,
5610 String packageName, IBinder token, String resultWho,
5611 int requestCode, Intent intent, String resolvedType, int flags) {
5612 // Refuse possible leaked file descriptors
5613 if (intent != null && intent.hasFileDescriptors() == true) {
5614 throw new IllegalArgumentException("File descriptors passed in Intent");
5615 }
5616
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005617 if (type == INTENT_SENDER_BROADCAST) {
5618 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5619 throw new IllegalArgumentException(
5620 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5621 }
5622 }
5623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005624 synchronized(this) {
5625 int callingUid = Binder.getCallingUid();
5626 try {
5627 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5628 Process.supportsProcesses()) {
5629 int uid = ActivityThread.getPackageManager()
5630 .getPackageUid(packageName);
5631 if (uid != Binder.getCallingUid()) {
5632 String msg = "Permission Denial: getIntentSender() from pid="
5633 + Binder.getCallingPid()
5634 + ", uid=" + Binder.getCallingUid()
5635 + ", (need uid=" + uid + ")"
5636 + " is not allowed to send as package " + packageName;
5637 Log.w(TAG, msg);
5638 throw new SecurityException(msg);
5639 }
5640 }
5641 } catch (RemoteException e) {
5642 throw new SecurityException(e);
5643 }
5644 HistoryRecord activity = null;
5645 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005646 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005647 if (index < 0) {
5648 return null;
5649 }
5650 activity = (HistoryRecord)mHistory.get(index);
5651 if (activity.finishing) {
5652 return null;
5653 }
5654 }
5655
5656 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5657 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5658 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5659 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5660 |PendingIntent.FLAG_UPDATE_CURRENT);
5661
5662 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5663 type, packageName, activity, resultWho,
5664 requestCode, intent, resolvedType, flags);
5665 WeakReference<PendingIntentRecord> ref;
5666 ref = mIntentSenderRecords.get(key);
5667 PendingIntentRecord rec = ref != null ? ref.get() : null;
5668 if (rec != null) {
5669 if (!cancelCurrent) {
5670 if (updateCurrent) {
5671 rec.key.requestIntent.replaceExtras(intent);
5672 }
5673 return rec;
5674 }
5675 rec.canceled = true;
5676 mIntentSenderRecords.remove(key);
5677 }
5678 if (noCreate) {
5679 return rec;
5680 }
5681 rec = new PendingIntentRecord(this, key, callingUid);
5682 mIntentSenderRecords.put(key, rec.ref);
5683 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5684 if (activity.pendingResults == null) {
5685 activity.pendingResults
5686 = new HashSet<WeakReference<PendingIntentRecord>>();
5687 }
5688 activity.pendingResults.add(rec.ref);
5689 }
5690 return rec;
5691 }
5692 }
5693
5694 public void cancelIntentSender(IIntentSender sender) {
5695 if (!(sender instanceof PendingIntentRecord)) {
5696 return;
5697 }
5698 synchronized(this) {
5699 PendingIntentRecord rec = (PendingIntentRecord)sender;
5700 try {
5701 int uid = ActivityThread.getPackageManager()
5702 .getPackageUid(rec.key.packageName);
5703 if (uid != Binder.getCallingUid()) {
5704 String msg = "Permission Denial: cancelIntentSender() from pid="
5705 + Binder.getCallingPid()
5706 + ", uid=" + Binder.getCallingUid()
5707 + " is not allowed to cancel packges "
5708 + rec.key.packageName;
5709 Log.w(TAG, msg);
5710 throw new SecurityException(msg);
5711 }
5712 } catch (RemoteException e) {
5713 throw new SecurityException(e);
5714 }
5715 cancelIntentSenderLocked(rec, true);
5716 }
5717 }
5718
5719 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5720 rec.canceled = true;
5721 mIntentSenderRecords.remove(rec.key);
5722 if (cleanActivity && rec.key.activity != null) {
5723 rec.key.activity.pendingResults.remove(rec.ref);
5724 }
5725 }
5726
5727 public String getPackageForIntentSender(IIntentSender pendingResult) {
5728 if (!(pendingResult instanceof PendingIntentRecord)) {
5729 return null;
5730 }
5731 synchronized(this) {
5732 try {
5733 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5734 return res.key.packageName;
5735 } catch (ClassCastException e) {
5736 }
5737 }
5738 return null;
5739 }
5740
5741 public void setProcessLimit(int max) {
5742 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5743 "setProcessLimit()");
5744 mProcessLimit = max;
5745 }
5746
5747 public int getProcessLimit() {
5748 return mProcessLimit;
5749 }
5750
5751 void foregroundTokenDied(ForegroundToken token) {
5752 synchronized (ActivityManagerService.this) {
5753 synchronized (mPidsSelfLocked) {
5754 ForegroundToken cur
5755 = mForegroundProcesses.get(token.pid);
5756 if (cur != token) {
5757 return;
5758 }
5759 mForegroundProcesses.remove(token.pid);
5760 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5761 if (pr == null) {
5762 return;
5763 }
5764 pr.forcingToForeground = null;
5765 pr.foregroundServices = false;
5766 }
5767 updateOomAdjLocked();
5768 }
5769 }
5770
5771 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5772 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5773 "setProcessForeground()");
5774 synchronized(this) {
5775 boolean changed = false;
5776
5777 synchronized (mPidsSelfLocked) {
5778 ProcessRecord pr = mPidsSelfLocked.get(pid);
5779 if (pr == null) {
5780 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5781 return;
5782 }
5783 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5784 if (oldToken != null) {
5785 oldToken.token.unlinkToDeath(oldToken, 0);
5786 mForegroundProcesses.remove(pid);
5787 pr.forcingToForeground = null;
5788 changed = true;
5789 }
5790 if (isForeground && token != null) {
5791 ForegroundToken newToken = new ForegroundToken() {
5792 public void binderDied() {
5793 foregroundTokenDied(this);
5794 }
5795 };
5796 newToken.pid = pid;
5797 newToken.token = token;
5798 try {
5799 token.linkToDeath(newToken, 0);
5800 mForegroundProcesses.put(pid, newToken);
5801 pr.forcingToForeground = token;
5802 changed = true;
5803 } catch (RemoteException e) {
5804 // If the process died while doing this, we will later
5805 // do the cleanup with the process death link.
5806 }
5807 }
5808 }
5809
5810 if (changed) {
5811 updateOomAdjLocked();
5812 }
5813 }
5814 }
5815
5816 // =========================================================
5817 // PERMISSIONS
5818 // =========================================================
5819
5820 static class PermissionController extends IPermissionController.Stub {
5821 ActivityManagerService mActivityManagerService;
5822 PermissionController(ActivityManagerService activityManagerService) {
5823 mActivityManagerService = activityManagerService;
5824 }
5825
5826 public boolean checkPermission(String permission, int pid, int uid) {
5827 return mActivityManagerService.checkPermission(permission, pid,
5828 uid) == PackageManager.PERMISSION_GRANTED;
5829 }
5830 }
5831
5832 /**
5833 * This can be called with or without the global lock held.
5834 */
5835 int checkComponentPermission(String permission, int pid, int uid,
5836 int reqUid) {
5837 // We might be performing an operation on behalf of an indirect binder
5838 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5839 // client identity accordingly before proceeding.
5840 Identity tlsIdentity = sCallerIdentity.get();
5841 if (tlsIdentity != null) {
5842 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5843 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5844 uid = tlsIdentity.uid;
5845 pid = tlsIdentity.pid;
5846 }
5847
5848 // Root, system server and our own process get to do everything.
5849 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5850 !Process.supportsProcesses()) {
5851 return PackageManager.PERMISSION_GRANTED;
5852 }
5853 // If the target requires a specific UID, always fail for others.
5854 if (reqUid >= 0 && uid != reqUid) {
5855 return PackageManager.PERMISSION_DENIED;
5856 }
5857 if (permission == null) {
5858 return PackageManager.PERMISSION_GRANTED;
5859 }
5860 try {
5861 return ActivityThread.getPackageManager()
5862 .checkUidPermission(permission, uid);
5863 } catch (RemoteException e) {
5864 // Should never happen, but if it does... deny!
5865 Log.e(TAG, "PackageManager is dead?!?", e);
5866 }
5867 return PackageManager.PERMISSION_DENIED;
5868 }
5869
5870 /**
5871 * As the only public entry point for permissions checking, this method
5872 * can enforce the semantic that requesting a check on a null global
5873 * permission is automatically denied. (Internally a null permission
5874 * string is used when calling {@link #checkComponentPermission} in cases
5875 * when only uid-based security is needed.)
5876 *
5877 * This can be called with or without the global lock held.
5878 */
5879 public int checkPermission(String permission, int pid, int uid) {
5880 if (permission == null) {
5881 return PackageManager.PERMISSION_DENIED;
5882 }
5883 return checkComponentPermission(permission, pid, uid, -1);
5884 }
5885
5886 /**
5887 * Binder IPC calls go through the public entry point.
5888 * This can be called with or without the global lock held.
5889 */
5890 int checkCallingPermission(String permission) {
5891 return checkPermission(permission,
5892 Binder.getCallingPid(),
5893 Binder.getCallingUid());
5894 }
5895
5896 /**
5897 * This can be called with or without the global lock held.
5898 */
5899 void enforceCallingPermission(String permission, String func) {
5900 if (checkCallingPermission(permission)
5901 == PackageManager.PERMISSION_GRANTED) {
5902 return;
5903 }
5904
5905 String msg = "Permission Denial: " + func + " from pid="
5906 + Binder.getCallingPid()
5907 + ", uid=" + Binder.getCallingUid()
5908 + " requires " + permission;
5909 Log.w(TAG, msg);
5910 throw new SecurityException(msg);
5911 }
5912
5913 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5914 ProviderInfo pi, int uid, int modeFlags) {
5915 try {
5916 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5917 if ((pi.readPermission != null) &&
5918 (pm.checkUidPermission(pi.readPermission, uid)
5919 != PackageManager.PERMISSION_GRANTED)) {
5920 return false;
5921 }
5922 }
5923 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5924 if ((pi.writePermission != null) &&
5925 (pm.checkUidPermission(pi.writePermission, uid)
5926 != PackageManager.PERMISSION_GRANTED)) {
5927 return false;
5928 }
5929 }
5930 return true;
5931 } catch (RemoteException e) {
5932 return false;
5933 }
5934 }
5935
5936 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5937 int modeFlags) {
5938 // Root gets to do everything.
5939 if (uid == 0 || !Process.supportsProcesses()) {
5940 return true;
5941 }
5942 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5943 if (perms == null) return false;
5944 UriPermission perm = perms.get(uri);
5945 if (perm == null) return false;
5946 return (modeFlags&perm.modeFlags) == modeFlags;
5947 }
5948
5949 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5950 // Another redirected-binder-call permissions check as in
5951 // {@link checkComponentPermission}.
5952 Identity tlsIdentity = sCallerIdentity.get();
5953 if (tlsIdentity != null) {
5954 uid = tlsIdentity.uid;
5955 pid = tlsIdentity.pid;
5956 }
5957
5958 // Our own process gets to do everything.
5959 if (pid == MY_PID) {
5960 return PackageManager.PERMISSION_GRANTED;
5961 }
5962 synchronized(this) {
5963 return checkUriPermissionLocked(uri, uid, modeFlags)
5964 ? PackageManager.PERMISSION_GRANTED
5965 : PackageManager.PERMISSION_DENIED;
5966 }
5967 }
5968
5969 private void grantUriPermissionLocked(int callingUid,
5970 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5971 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5972 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5973 if (modeFlags == 0) {
5974 return;
5975 }
5976
5977 final IPackageManager pm = ActivityThread.getPackageManager();
5978
5979 // If this is not a content: uri, we can't do anything with it.
5980 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5981 return;
5982 }
5983
5984 String name = uri.getAuthority();
5985 ProviderInfo pi = null;
5986 ContentProviderRecord cpr
5987 = (ContentProviderRecord)mProvidersByName.get(name);
5988 if (cpr != null) {
5989 pi = cpr.info;
5990 } else {
5991 try {
5992 pi = pm.resolveContentProvider(name,
5993 PackageManager.GET_URI_PERMISSION_PATTERNS);
5994 } catch (RemoteException ex) {
5995 }
5996 }
5997 if (pi == null) {
5998 Log.w(TAG, "No content provider found for: " + name);
5999 return;
6000 }
6001
6002 int targetUid;
6003 try {
6004 targetUid = pm.getPackageUid(targetPkg);
6005 if (targetUid < 0) {
6006 return;
6007 }
6008 } catch (RemoteException ex) {
6009 return;
6010 }
6011
6012 // First... does the target actually need this permission?
6013 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6014 // No need to grant the target this permission.
6015 return;
6016 }
6017
6018 // Second... maybe someone else has already granted the
6019 // permission?
6020 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6021 // No need to grant the target this permission.
6022 return;
6023 }
6024
6025 // Third... is the provider allowing granting of URI permissions?
6026 if (!pi.grantUriPermissions) {
6027 throw new SecurityException("Provider " + pi.packageName
6028 + "/" + pi.name
6029 + " does not allow granting of Uri permissions (uri "
6030 + uri + ")");
6031 }
6032 if (pi.uriPermissionPatterns != null) {
6033 final int N = pi.uriPermissionPatterns.length;
6034 boolean allowed = false;
6035 for (int i=0; i<N; i++) {
6036 if (pi.uriPermissionPatterns[i] != null
6037 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6038 allowed = true;
6039 break;
6040 }
6041 }
6042 if (!allowed) {
6043 throw new SecurityException("Provider " + pi.packageName
6044 + "/" + pi.name
6045 + " does not allow granting of permission to path of Uri "
6046 + uri);
6047 }
6048 }
6049
6050 // Fourth... does the caller itself have permission to access
6051 // this uri?
6052 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6053 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6054 throw new SecurityException("Uid " + callingUid
6055 + " does not have permission to uri " + uri);
6056 }
6057 }
6058
6059 // Okay! So here we are: the caller has the assumed permission
6060 // to the uri, and the target doesn't. Let's now give this to
6061 // the target.
6062
6063 HashMap<Uri, UriPermission> targetUris
6064 = mGrantedUriPermissions.get(targetUid);
6065 if (targetUris == null) {
6066 targetUris = new HashMap<Uri, UriPermission>();
6067 mGrantedUriPermissions.put(targetUid, targetUris);
6068 }
6069
6070 UriPermission perm = targetUris.get(uri);
6071 if (perm == null) {
6072 perm = new UriPermission(targetUid, uri);
6073 targetUris.put(uri, perm);
6074
6075 }
6076 perm.modeFlags |= modeFlags;
6077 if (activity == null) {
6078 perm.globalModeFlags |= modeFlags;
6079 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6080 perm.readActivities.add(activity);
6081 if (activity.readUriPermissions == null) {
6082 activity.readUriPermissions = new HashSet<UriPermission>();
6083 }
6084 activity.readUriPermissions.add(perm);
6085 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6086 perm.writeActivities.add(activity);
6087 if (activity.writeUriPermissions == null) {
6088 activity.writeUriPermissions = new HashSet<UriPermission>();
6089 }
6090 activity.writeUriPermissions.add(perm);
6091 }
6092 }
6093
6094 private void grantUriPermissionFromIntentLocked(int callingUid,
6095 String targetPkg, Intent intent, HistoryRecord activity) {
6096 if (intent == null) {
6097 return;
6098 }
6099 Uri data = intent.getData();
6100 if (data == null) {
6101 return;
6102 }
6103 grantUriPermissionLocked(callingUid, targetPkg, data,
6104 intent.getFlags(), activity);
6105 }
6106
6107 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6108 Uri uri, int modeFlags) {
6109 synchronized(this) {
6110 final ProcessRecord r = getRecordForAppLocked(caller);
6111 if (r == null) {
6112 throw new SecurityException("Unable to find app for caller "
6113 + caller
6114 + " when granting permission to uri " + uri);
6115 }
6116 if (targetPkg == null) {
6117 Log.w(TAG, "grantUriPermission: null target");
6118 return;
6119 }
6120 if (uri == null) {
6121 Log.w(TAG, "grantUriPermission: null uri");
6122 return;
6123 }
6124
6125 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6126 null);
6127 }
6128 }
6129
6130 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6131 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6132 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6133 HashMap<Uri, UriPermission> perms
6134 = mGrantedUriPermissions.get(perm.uid);
6135 if (perms != null) {
6136 perms.remove(perm.uri);
6137 if (perms.size() == 0) {
6138 mGrantedUriPermissions.remove(perm.uid);
6139 }
6140 }
6141 }
6142 }
6143
6144 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6145 if (activity.readUriPermissions != null) {
6146 for (UriPermission perm : activity.readUriPermissions) {
6147 perm.readActivities.remove(activity);
6148 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6149 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6150 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6151 removeUriPermissionIfNeededLocked(perm);
6152 }
6153 }
6154 }
6155 if (activity.writeUriPermissions != null) {
6156 for (UriPermission perm : activity.writeUriPermissions) {
6157 perm.writeActivities.remove(activity);
6158 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6159 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6160 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6161 removeUriPermissionIfNeededLocked(perm);
6162 }
6163 }
6164 }
6165 }
6166
6167 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6168 int modeFlags) {
6169 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6170 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6171 if (modeFlags == 0) {
6172 return;
6173 }
6174
6175 final IPackageManager pm = ActivityThread.getPackageManager();
6176
6177 final String authority = uri.getAuthority();
6178 ProviderInfo pi = null;
6179 ContentProviderRecord cpr
6180 = (ContentProviderRecord)mProvidersByName.get(authority);
6181 if (cpr != null) {
6182 pi = cpr.info;
6183 } else {
6184 try {
6185 pi = pm.resolveContentProvider(authority,
6186 PackageManager.GET_URI_PERMISSION_PATTERNS);
6187 } catch (RemoteException ex) {
6188 }
6189 }
6190 if (pi == null) {
6191 Log.w(TAG, "No content provider found for: " + authority);
6192 return;
6193 }
6194
6195 // Does the caller have this permission on the URI?
6196 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6197 // Right now, if you are not the original owner of the permission,
6198 // you are not allowed to revoke it.
6199 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6200 throw new SecurityException("Uid " + callingUid
6201 + " does not have permission to uri " + uri);
6202 //}
6203 }
6204
6205 // Go through all of the permissions and remove any that match.
6206 final List<String> SEGMENTS = uri.getPathSegments();
6207 if (SEGMENTS != null) {
6208 final int NS = SEGMENTS.size();
6209 int N = mGrantedUriPermissions.size();
6210 for (int i=0; i<N; i++) {
6211 HashMap<Uri, UriPermission> perms
6212 = mGrantedUriPermissions.valueAt(i);
6213 Iterator<UriPermission> it = perms.values().iterator();
6214 toploop:
6215 while (it.hasNext()) {
6216 UriPermission perm = it.next();
6217 Uri targetUri = perm.uri;
6218 if (!authority.equals(targetUri.getAuthority())) {
6219 continue;
6220 }
6221 List<String> targetSegments = targetUri.getPathSegments();
6222 if (targetSegments == null) {
6223 continue;
6224 }
6225 if (targetSegments.size() < NS) {
6226 continue;
6227 }
6228 for (int j=0; j<NS; j++) {
6229 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6230 continue toploop;
6231 }
6232 }
6233 perm.clearModes(modeFlags);
6234 if (perm.modeFlags == 0) {
6235 it.remove();
6236 }
6237 }
6238 if (perms.size() == 0) {
6239 mGrantedUriPermissions.remove(
6240 mGrantedUriPermissions.keyAt(i));
6241 N--;
6242 i--;
6243 }
6244 }
6245 }
6246 }
6247
6248 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6249 int modeFlags) {
6250 synchronized(this) {
6251 final ProcessRecord r = getRecordForAppLocked(caller);
6252 if (r == null) {
6253 throw new SecurityException("Unable to find app for caller "
6254 + caller
6255 + " when revoking permission to uri " + uri);
6256 }
6257 if (uri == null) {
6258 Log.w(TAG, "revokeUriPermission: null uri");
6259 return;
6260 }
6261
6262 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6263 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6264 if (modeFlags == 0) {
6265 return;
6266 }
6267
6268 final IPackageManager pm = ActivityThread.getPackageManager();
6269
6270 final String authority = uri.getAuthority();
6271 ProviderInfo pi = null;
6272 ContentProviderRecord cpr
6273 = (ContentProviderRecord)mProvidersByName.get(authority);
6274 if (cpr != null) {
6275 pi = cpr.info;
6276 } else {
6277 try {
6278 pi = pm.resolveContentProvider(authority,
6279 PackageManager.GET_URI_PERMISSION_PATTERNS);
6280 } catch (RemoteException ex) {
6281 }
6282 }
6283 if (pi == null) {
6284 Log.w(TAG, "No content provider found for: " + authority);
6285 return;
6286 }
6287
6288 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6289 }
6290 }
6291
6292 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6293 synchronized (this) {
6294 ProcessRecord app =
6295 who != null ? getRecordForAppLocked(who) : null;
6296 if (app == null) return;
6297
6298 Message msg = Message.obtain();
6299 msg.what = WAIT_FOR_DEBUGGER_MSG;
6300 msg.obj = app;
6301 msg.arg1 = waiting ? 1 : 0;
6302 mHandler.sendMessage(msg);
6303 }
6304 }
6305
6306 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6307 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006308 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006309 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006310 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006311 }
6312
6313 // =========================================================
6314 // TASK MANAGEMENT
6315 // =========================================================
6316
6317 public List getTasks(int maxNum, int flags,
6318 IThumbnailReceiver receiver) {
6319 ArrayList list = new ArrayList();
6320
6321 PendingThumbnailsRecord pending = null;
6322 IApplicationThread topThumbnail = null;
6323 HistoryRecord topRecord = null;
6324
6325 synchronized(this) {
6326 if (localLOGV) Log.v(
6327 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6328 + ", receiver=" + receiver);
6329
6330 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6331 != PackageManager.PERMISSION_GRANTED) {
6332 if (receiver != null) {
6333 // If the caller wants to wait for pending thumbnails,
6334 // it ain't gonna get them.
6335 try {
6336 receiver.finished();
6337 } catch (RemoteException ex) {
6338 }
6339 }
6340 String msg = "Permission Denial: getTasks() from pid="
6341 + Binder.getCallingPid()
6342 + ", uid=" + Binder.getCallingUid()
6343 + " requires " + android.Manifest.permission.GET_TASKS;
6344 Log.w(TAG, msg);
6345 throw new SecurityException(msg);
6346 }
6347
6348 int pos = mHistory.size()-1;
6349 HistoryRecord next =
6350 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6351 HistoryRecord top = null;
6352 CharSequence topDescription = null;
6353 TaskRecord curTask = null;
6354 int numActivities = 0;
6355 int numRunning = 0;
6356 while (pos >= 0 && maxNum > 0) {
6357 final HistoryRecord r = next;
6358 pos--;
6359 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6360
6361 // Initialize state for next task if needed.
6362 if (top == null ||
6363 (top.state == ActivityState.INITIALIZING
6364 && top.task == r.task)) {
6365 top = r;
6366 topDescription = r.description;
6367 curTask = r.task;
6368 numActivities = numRunning = 0;
6369 }
6370
6371 // Add 'r' into the current task.
6372 numActivities++;
6373 if (r.app != null && r.app.thread != null) {
6374 numRunning++;
6375 }
6376 if (topDescription == null) {
6377 topDescription = r.description;
6378 }
6379
6380 if (localLOGV) Log.v(
6381 TAG, r.intent.getComponent().flattenToShortString()
6382 + ": task=" + r.task);
6383
6384 // If the next one is a different task, generate a new
6385 // TaskInfo entry for what we have.
6386 if (next == null || next.task != curTask) {
6387 ActivityManager.RunningTaskInfo ci
6388 = new ActivityManager.RunningTaskInfo();
6389 ci.id = curTask.taskId;
6390 ci.baseActivity = r.intent.getComponent();
6391 ci.topActivity = top.intent.getComponent();
6392 ci.thumbnail = top.thumbnail;
6393 ci.description = topDescription;
6394 ci.numActivities = numActivities;
6395 ci.numRunning = numRunning;
6396 //System.out.println(
6397 // "#" + maxNum + ": " + " descr=" + ci.description);
6398 if (ci.thumbnail == null && receiver != null) {
6399 if (localLOGV) Log.v(
6400 TAG, "State=" + top.state + "Idle=" + top.idle
6401 + " app=" + top.app
6402 + " thr=" + (top.app != null ? top.app.thread : null));
6403 if (top.state == ActivityState.RESUMED
6404 || top.state == ActivityState.PAUSING) {
6405 if (top.idle && top.app != null
6406 && top.app.thread != null) {
6407 topRecord = top;
6408 topThumbnail = top.app.thread;
6409 } else {
6410 top.thumbnailNeeded = true;
6411 }
6412 }
6413 if (pending == null) {
6414 pending = new PendingThumbnailsRecord(receiver);
6415 }
6416 pending.pendingRecords.add(top);
6417 }
6418 list.add(ci);
6419 maxNum--;
6420 top = null;
6421 }
6422 }
6423
6424 if (pending != null) {
6425 mPendingThumbnails.add(pending);
6426 }
6427 }
6428
6429 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6430
6431 if (topThumbnail != null) {
6432 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6433 try {
6434 topThumbnail.requestThumbnail(topRecord);
6435 } catch (Exception e) {
6436 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6437 sendPendingThumbnail(null, topRecord, null, null, true);
6438 }
6439 }
6440
6441 if (pending == null && receiver != null) {
6442 // In this case all thumbnails were available and the client
6443 // is being asked to be told when the remaining ones come in...
6444 // which is unusually, since the top-most currently running
6445 // activity should never have a canned thumbnail! Oh well.
6446 try {
6447 receiver.finished();
6448 } catch (RemoteException ex) {
6449 }
6450 }
6451
6452 return list;
6453 }
6454
6455 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6456 int flags) {
6457 synchronized (this) {
6458 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6459 "getRecentTasks()");
6460
6461 final int N = mRecentTasks.size();
6462 ArrayList<ActivityManager.RecentTaskInfo> res
6463 = new ArrayList<ActivityManager.RecentTaskInfo>(
6464 maxNum < N ? maxNum : N);
6465 for (int i=0; i<N && maxNum > 0; i++) {
6466 TaskRecord tr = mRecentTasks.get(i);
6467 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6468 || (tr.intent == null)
6469 || ((tr.intent.getFlags()
6470 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6471 ActivityManager.RecentTaskInfo rti
6472 = new ActivityManager.RecentTaskInfo();
6473 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6474 rti.baseIntent = new Intent(
6475 tr.intent != null ? tr.intent : tr.affinityIntent);
6476 rti.origActivity = tr.origActivity;
6477 res.add(rti);
6478 maxNum--;
6479 }
6480 }
6481 return res;
6482 }
6483 }
6484
6485 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6486 int j;
6487 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6488 TaskRecord jt = startTask;
6489
6490 // First look backwards
6491 for (j=startIndex-1; j>=0; j--) {
6492 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6493 if (r.task != jt) {
6494 jt = r.task;
6495 if (affinity.equals(jt.affinity)) {
6496 return j;
6497 }
6498 }
6499 }
6500
6501 // Now look forwards
6502 final int N = mHistory.size();
6503 jt = startTask;
6504 for (j=startIndex+1; j<N; j++) {
6505 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6506 if (r.task != jt) {
6507 if (affinity.equals(jt.affinity)) {
6508 return j;
6509 }
6510 jt = r.task;
6511 }
6512 }
6513
6514 // Might it be at the top?
6515 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6516 return N-1;
6517 }
6518
6519 return -1;
6520 }
6521
6522 /**
6523 * Perform a reset of the given task, if needed as part of launching it.
6524 * Returns the new HistoryRecord at the top of the task.
6525 */
6526 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6527 HistoryRecord newActivity) {
6528 boolean forceReset = (newActivity.info.flags
6529 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6530 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6531 if ((newActivity.info.flags
6532 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6533 forceReset = true;
6534 }
6535 }
6536
6537 final TaskRecord task = taskTop.task;
6538
6539 // We are going to move through the history list so that we can look
6540 // at each activity 'target' with 'below' either the interesting
6541 // activity immediately below it in the stack or null.
6542 HistoryRecord target = null;
6543 int targetI = 0;
6544 int taskTopI = -1;
6545 int replyChainEnd = -1;
6546 int lastReparentPos = -1;
6547 for (int i=mHistory.size()-1; i>=-1; i--) {
6548 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6549
6550 if (below != null && below.finishing) {
6551 continue;
6552 }
6553 if (target == null) {
6554 target = below;
6555 targetI = i;
6556 // If we were in the middle of a reply chain before this
6557 // task, it doesn't appear like the root of the chain wants
6558 // anything interesting, so drop it.
6559 replyChainEnd = -1;
6560 continue;
6561 }
6562
6563 final int flags = target.info.flags;
6564
6565 final boolean finishOnTaskLaunch =
6566 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6567 final boolean allowTaskReparenting =
6568 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6569
6570 if (target.task == task) {
6571 // We are inside of the task being reset... we'll either
6572 // finish this activity, push it out for another task,
6573 // or leave it as-is. We only do this
6574 // for activities that are not the root of the task (since
6575 // if we finish the root, we may no longer have the task!).
6576 if (taskTopI < 0) {
6577 taskTopI = targetI;
6578 }
6579 if (below != null && below.task == task) {
6580 final boolean clearWhenTaskReset =
6581 (target.intent.getFlags()
6582 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006583 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006584 // If this activity is sending a reply to a previous
6585 // activity, we can't do anything with it now until
6586 // we reach the start of the reply chain.
6587 // XXX note that we are assuming the result is always
6588 // to the previous activity, which is almost always
6589 // the case but we really shouldn't count on.
6590 if (replyChainEnd < 0) {
6591 replyChainEnd = targetI;
6592 }
Ed Heyl73798232009-03-24 21:32:21 -07006593 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006594 && target.taskAffinity != null
6595 && !target.taskAffinity.equals(task.affinity)) {
6596 // If this activity has an affinity for another
6597 // task, then we need to move it out of here. We will
6598 // move it as far out of the way as possible, to the
6599 // bottom of the activity stack. This also keeps it
6600 // correctly ordered with any activities we previously
6601 // moved.
6602 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6603 if (target.taskAffinity != null
6604 && target.taskAffinity.equals(p.task.affinity)) {
6605 // If the activity currently at the bottom has the
6606 // same task affinity as the one we are moving,
6607 // then merge it into the same task.
6608 target.task = p.task;
6609 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6610 + " out to bottom task " + p.task);
6611 } else {
6612 mCurTask++;
6613 if (mCurTask <= 0) {
6614 mCurTask = 1;
6615 }
6616 target.task = new TaskRecord(mCurTask, target.info, null,
6617 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6618 target.task.affinityIntent = target.intent;
6619 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6620 + " out to new task " + target.task);
6621 }
6622 mWindowManager.setAppGroupId(target, task.taskId);
6623 if (replyChainEnd < 0) {
6624 replyChainEnd = targetI;
6625 }
6626 int dstPos = 0;
6627 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6628 p = (HistoryRecord)mHistory.get(srcPos);
6629 if (p.finishing) {
6630 continue;
6631 }
6632 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6633 + " out to target's task " + target.task);
6634 task.numActivities--;
6635 p.task = target.task;
6636 target.task.numActivities++;
6637 mHistory.remove(srcPos);
6638 mHistory.add(dstPos, p);
6639 mWindowManager.moveAppToken(dstPos, p);
6640 mWindowManager.setAppGroupId(p, p.task.taskId);
6641 dstPos++;
6642 if (VALIDATE_TOKENS) {
6643 mWindowManager.validateAppTokens(mHistory);
6644 }
6645 i++;
6646 }
6647 if (taskTop == p) {
6648 taskTop = below;
6649 }
6650 if (taskTopI == replyChainEnd) {
6651 taskTopI = -1;
6652 }
6653 replyChainEnd = -1;
6654 addRecentTask(target.task);
6655 } else if (forceReset || finishOnTaskLaunch
6656 || clearWhenTaskReset) {
6657 // If the activity should just be removed -- either
6658 // because it asks for it, or the task should be
6659 // cleared -- then finish it and anything that is
6660 // part of its reply chain.
6661 if (clearWhenTaskReset) {
6662 // In this case, we want to finish this activity
6663 // and everything above it, so be sneaky and pretend
6664 // like these are all in the reply chain.
6665 replyChainEnd = targetI+1;
6666 while (replyChainEnd < mHistory.size() &&
6667 ((HistoryRecord)mHistory.get(
6668 replyChainEnd)).task == task) {
6669 replyChainEnd++;
6670 }
6671 replyChainEnd--;
6672 } else if (replyChainEnd < 0) {
6673 replyChainEnd = targetI;
6674 }
6675 HistoryRecord p = null;
6676 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6677 p = (HistoryRecord)mHistory.get(srcPos);
6678 if (p.finishing) {
6679 continue;
6680 }
6681 if (finishActivityLocked(p, srcPos,
6682 Activity.RESULT_CANCELED, null, "reset")) {
6683 replyChainEnd--;
6684 srcPos--;
6685 }
6686 }
6687 if (taskTop == p) {
6688 taskTop = below;
6689 }
6690 if (taskTopI == replyChainEnd) {
6691 taskTopI = -1;
6692 }
6693 replyChainEnd = -1;
6694 } else {
6695 // If we were in the middle of a chain, well the
6696 // activity that started it all doesn't want anything
6697 // special, so leave it all as-is.
6698 replyChainEnd = -1;
6699 }
6700 } else {
6701 // Reached the bottom of the task -- any reply chain
6702 // should be left as-is.
6703 replyChainEnd = -1;
6704 }
6705
6706 } else if (target.resultTo != null) {
6707 // If this activity is sending a reply to a previous
6708 // activity, we can't do anything with it now until
6709 // we reach the start of the reply chain.
6710 // XXX note that we are assuming the result is always
6711 // to the previous activity, which is almost always
6712 // the case but we really shouldn't count on.
6713 if (replyChainEnd < 0) {
6714 replyChainEnd = targetI;
6715 }
6716
6717 } else if (taskTopI >= 0 && allowTaskReparenting
6718 && task.affinity != null
6719 && task.affinity.equals(target.taskAffinity)) {
6720 // We are inside of another task... if this activity has
6721 // an affinity for our task, then either remove it if we are
6722 // clearing or move it over to our task. Note that
6723 // we currently punt on the case where we are resetting a
6724 // task that is not at the top but who has activities above
6725 // with an affinity to it... this is really not a normal
6726 // case, and we will need to later pull that task to the front
6727 // and usually at that point we will do the reset and pick
6728 // up those remaining activities. (This only happens if
6729 // someone starts an activity in a new task from an activity
6730 // in a task that is not currently on top.)
6731 if (forceReset || finishOnTaskLaunch) {
6732 if (replyChainEnd < 0) {
6733 replyChainEnd = targetI;
6734 }
6735 HistoryRecord p = null;
6736 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6737 p = (HistoryRecord)mHistory.get(srcPos);
6738 if (p.finishing) {
6739 continue;
6740 }
6741 if (finishActivityLocked(p, srcPos,
6742 Activity.RESULT_CANCELED, null, "reset")) {
6743 taskTopI--;
6744 lastReparentPos--;
6745 replyChainEnd--;
6746 srcPos--;
6747 }
6748 }
6749 replyChainEnd = -1;
6750 } else {
6751 if (replyChainEnd < 0) {
6752 replyChainEnd = targetI;
6753 }
6754 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6755 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6756 if (p.finishing) {
6757 continue;
6758 }
6759 if (lastReparentPos < 0) {
6760 lastReparentPos = taskTopI;
6761 taskTop = p;
6762 } else {
6763 lastReparentPos--;
6764 }
6765 mHistory.remove(srcPos);
6766 p.task.numActivities--;
6767 p.task = task;
6768 mHistory.add(lastReparentPos, p);
6769 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6770 + " in to resetting task " + task);
6771 task.numActivities++;
6772 mWindowManager.moveAppToken(lastReparentPos, p);
6773 mWindowManager.setAppGroupId(p, p.task.taskId);
6774 if (VALIDATE_TOKENS) {
6775 mWindowManager.validateAppTokens(mHistory);
6776 }
6777 }
6778 replyChainEnd = -1;
6779
6780 // Now we've moved it in to place... but what if this is
6781 // a singleTop activity and we have put it on top of another
6782 // instance of the same activity? Then we drop the instance
6783 // below so it remains singleTop.
6784 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6785 for (int j=lastReparentPos-1; j>=0; j--) {
6786 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6787 if (p.finishing) {
6788 continue;
6789 }
6790 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6791 if (finishActivityLocked(p, j,
6792 Activity.RESULT_CANCELED, null, "replace")) {
6793 taskTopI--;
6794 lastReparentPos--;
6795 }
6796 }
6797 }
6798 }
6799 }
6800 }
6801
6802 target = below;
6803 targetI = i;
6804 }
6805
6806 return taskTop;
6807 }
6808
6809 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006810 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006811 */
6812 public void moveTaskToFront(int task) {
6813 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6814 "moveTaskToFront()");
6815
6816 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006817 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6818 Binder.getCallingUid(), "Task to front")) {
6819 return;
6820 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006821 final long origId = Binder.clearCallingIdentity();
6822 try {
6823 int N = mRecentTasks.size();
6824 for (int i=0; i<N; i++) {
6825 TaskRecord tr = mRecentTasks.get(i);
6826 if (tr.taskId == task) {
6827 moveTaskToFrontLocked(tr);
6828 return;
6829 }
6830 }
6831 for (int i=mHistory.size()-1; i>=0; i--) {
6832 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6833 if (hr.task.taskId == task) {
6834 moveTaskToFrontLocked(hr.task);
6835 return;
6836 }
6837 }
6838 } finally {
6839 Binder.restoreCallingIdentity(origId);
6840 }
6841 }
6842 }
6843
6844 private final void moveTaskToFrontLocked(TaskRecord tr) {
6845 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6846
6847 final int task = tr.taskId;
6848 int top = mHistory.size()-1;
6849
6850 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6851 // nothing to do!
6852 return;
6853 }
6854
6855 if (DEBUG_TRANSITION) Log.v(TAG,
6856 "Prepare to front transition: task=" + tr);
6857 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6858
6859 ArrayList moved = new ArrayList();
6860
6861 // Applying the affinities may have removed entries from the history,
6862 // so get the size again.
6863 top = mHistory.size()-1;
6864 int pos = top;
6865
6866 // Shift all activities with this task up to the top
6867 // of the stack, keeping them in the same internal order.
6868 while (pos >= 0) {
6869 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6870 if (localLOGV) Log.v(
6871 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6872 boolean first = true;
6873 if (r.task.taskId == task) {
6874 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6875 mHistory.remove(pos);
6876 mHistory.add(top, r);
6877 moved.add(0, r);
6878 top--;
6879 if (first) {
6880 addRecentTask(r.task);
6881 first = false;
6882 }
6883 }
6884 pos--;
6885 }
6886
6887 mWindowManager.moveAppTokensToTop(moved);
6888 if (VALIDATE_TOKENS) {
6889 mWindowManager.validateAppTokens(mHistory);
6890 }
6891
6892 finishTaskMove(task);
6893 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6894 }
6895
6896 private final void finishTaskMove(int task) {
6897 resumeTopActivityLocked(null);
6898 }
6899
6900 public void moveTaskToBack(int task) {
6901 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6902 "moveTaskToBack()");
6903
6904 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006905 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6906 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6907 Binder.getCallingUid(), "Task to back")) {
6908 return;
6909 }
6910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006911 final long origId = Binder.clearCallingIdentity();
6912 moveTaskToBackLocked(task);
6913 Binder.restoreCallingIdentity(origId);
6914 }
6915 }
6916
6917 /**
6918 * Moves an activity, and all of the other activities within the same task, to the bottom
6919 * of the history stack. The activity's order within the task is unchanged.
6920 *
6921 * @param token A reference to the activity we wish to move
6922 * @param nonRoot If false then this only works if the activity is the root
6923 * of a task; if true it will work for any activity in a task.
6924 * @return Returns true if the move completed, false if not.
6925 */
6926 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6927 synchronized(this) {
6928 final long origId = Binder.clearCallingIdentity();
6929 int taskId = getTaskForActivityLocked(token, !nonRoot);
6930 if (taskId >= 0) {
6931 return moveTaskToBackLocked(taskId);
6932 }
6933 Binder.restoreCallingIdentity(origId);
6934 }
6935 return false;
6936 }
6937
6938 /**
6939 * Worker method for rearranging history stack. Implements the function of moving all
6940 * activities for a specific task (gathering them if disjoint) into a single group at the
6941 * bottom of the stack.
6942 *
6943 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6944 * to premeptively cancel the move.
6945 *
6946 * @param task The taskId to collect and move to the bottom.
6947 * @return Returns true if the move completed, false if not.
6948 */
6949 private final boolean moveTaskToBackLocked(int task) {
6950 Log.i(TAG, "moveTaskToBack: " + task);
6951
6952 // If we have a watcher, preflight the move before committing to it. First check
6953 // for *other* available tasks, but if none are available, then try again allowing the
6954 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006955 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006956 HistoryRecord next = topRunningActivityLocked(null, task);
6957 if (next == null) {
6958 next = topRunningActivityLocked(null, 0);
6959 }
6960 if (next != null) {
6961 // ask watcher if this is allowed
6962 boolean moveOK = true;
6963 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006964 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006965 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006966 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006967 }
6968 if (!moveOK) {
6969 return false;
6970 }
6971 }
6972 }
6973
6974 ArrayList moved = new ArrayList();
6975
6976 if (DEBUG_TRANSITION) Log.v(TAG,
6977 "Prepare to back transition: task=" + task);
6978 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6979
6980 final int N = mHistory.size();
6981 int bottom = 0;
6982 int pos = 0;
6983
6984 // Shift all activities with this task down to the bottom
6985 // of the stack, keeping them in the same internal order.
6986 while (pos < N) {
6987 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6988 if (localLOGV) Log.v(
6989 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6990 if (r.task.taskId == task) {
6991 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6992 mHistory.remove(pos);
6993 mHistory.add(bottom, r);
6994 moved.add(r);
6995 bottom++;
6996 }
6997 pos++;
6998 }
6999
7000 mWindowManager.moveAppTokensToBottom(moved);
7001 if (VALIDATE_TOKENS) {
7002 mWindowManager.validateAppTokens(mHistory);
7003 }
7004
7005 finishTaskMove(task);
7006 return true;
7007 }
7008
7009 public void moveTaskBackwards(int task) {
7010 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7011 "moveTaskBackwards()");
7012
7013 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007014 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7015 Binder.getCallingUid(), "Task backwards")) {
7016 return;
7017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007018 final long origId = Binder.clearCallingIdentity();
7019 moveTaskBackwardsLocked(task);
7020 Binder.restoreCallingIdentity(origId);
7021 }
7022 }
7023
7024 private final void moveTaskBackwardsLocked(int task) {
7025 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7026 }
7027
7028 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7029 synchronized(this) {
7030 return getTaskForActivityLocked(token, onlyRoot);
7031 }
7032 }
7033
7034 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7035 final int N = mHistory.size();
7036 TaskRecord lastTask = null;
7037 for (int i=0; i<N; i++) {
7038 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7039 if (r == token) {
7040 if (!onlyRoot || lastTask != r.task) {
7041 return r.task.taskId;
7042 }
7043 return -1;
7044 }
7045 lastTask = r.task;
7046 }
7047
7048 return -1;
7049 }
7050
7051 /**
7052 * Returns the top activity in any existing task matching the given
7053 * Intent. Returns null if no such task is found.
7054 */
7055 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7056 ComponentName cls = intent.getComponent();
7057 if (info.targetActivity != null) {
7058 cls = new ComponentName(info.packageName, info.targetActivity);
7059 }
7060
7061 TaskRecord cp = null;
7062
7063 final int N = mHistory.size();
7064 for (int i=(N-1); i>=0; i--) {
7065 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7066 if (!r.finishing && r.task != cp
7067 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7068 cp = r.task;
7069 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7070 // + "/aff=" + r.task.affinity + " to new cls="
7071 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7072 if (r.task.affinity != null) {
7073 if (r.task.affinity.equals(info.taskAffinity)) {
7074 //Log.i(TAG, "Found matching affinity!");
7075 return r;
7076 }
7077 } else if (r.task.intent != null
7078 && r.task.intent.getComponent().equals(cls)) {
7079 //Log.i(TAG, "Found matching class!");
7080 //dump();
7081 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7082 return r;
7083 } else if (r.task.affinityIntent != null
7084 && r.task.affinityIntent.getComponent().equals(cls)) {
7085 //Log.i(TAG, "Found matching class!");
7086 //dump();
7087 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7088 return r;
7089 }
7090 }
7091 }
7092
7093 return null;
7094 }
7095
7096 /**
7097 * Returns the first activity (starting from the top of the stack) that
7098 * is the same as the given activity. Returns null if no such activity
7099 * is found.
7100 */
7101 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7102 ComponentName cls = intent.getComponent();
7103 if (info.targetActivity != null) {
7104 cls = new ComponentName(info.packageName, info.targetActivity);
7105 }
7106
7107 final int N = mHistory.size();
7108 for (int i=(N-1); i>=0; i--) {
7109 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7110 if (!r.finishing) {
7111 if (r.intent.getComponent().equals(cls)) {
7112 //Log.i(TAG, "Found matching class!");
7113 //dump();
7114 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7115 return r;
7116 }
7117 }
7118 }
7119
7120 return null;
7121 }
7122
7123 public void finishOtherInstances(IBinder token, ComponentName className) {
7124 synchronized(this) {
7125 final long origId = Binder.clearCallingIdentity();
7126
7127 int N = mHistory.size();
7128 TaskRecord lastTask = null;
7129 for (int i=0; i<N; i++) {
7130 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7131 if (r.realActivity.equals(className)
7132 && r != token && lastTask != r.task) {
7133 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7134 null, "others")) {
7135 i--;
7136 N--;
7137 }
7138 }
7139 lastTask = r.task;
7140 }
7141
7142 Binder.restoreCallingIdentity(origId);
7143 }
7144 }
7145
7146 // =========================================================
7147 // THUMBNAILS
7148 // =========================================================
7149
7150 public void reportThumbnail(IBinder token,
7151 Bitmap thumbnail, CharSequence description) {
7152 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7153 final long origId = Binder.clearCallingIdentity();
7154 sendPendingThumbnail(null, token, thumbnail, description, true);
7155 Binder.restoreCallingIdentity(origId);
7156 }
7157
7158 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7159 Bitmap thumbnail, CharSequence description, boolean always) {
7160 TaskRecord task = null;
7161 ArrayList receivers = null;
7162
7163 //System.out.println("Send pending thumbnail: " + r);
7164
7165 synchronized(this) {
7166 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007167 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007168 if (index < 0) {
7169 return;
7170 }
7171 r = (HistoryRecord)mHistory.get(index);
7172 }
7173 if (thumbnail == null) {
7174 thumbnail = r.thumbnail;
7175 description = r.description;
7176 }
7177 if (thumbnail == null && !always) {
7178 // If there is no thumbnail, and this entry is not actually
7179 // going away, then abort for now and pick up the next
7180 // thumbnail we get.
7181 return;
7182 }
7183 task = r.task;
7184
7185 int N = mPendingThumbnails.size();
7186 int i=0;
7187 while (i<N) {
7188 PendingThumbnailsRecord pr =
7189 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7190 //System.out.println("Looking in " + pr.pendingRecords);
7191 if (pr.pendingRecords.remove(r)) {
7192 if (receivers == null) {
7193 receivers = new ArrayList();
7194 }
7195 receivers.add(pr);
7196 if (pr.pendingRecords.size() == 0) {
7197 pr.finished = true;
7198 mPendingThumbnails.remove(i);
7199 N--;
7200 continue;
7201 }
7202 }
7203 i++;
7204 }
7205 }
7206
7207 if (receivers != null) {
7208 final int N = receivers.size();
7209 for (int i=0; i<N; i++) {
7210 try {
7211 PendingThumbnailsRecord pr =
7212 (PendingThumbnailsRecord)receivers.get(i);
7213 pr.receiver.newThumbnail(
7214 task != null ? task.taskId : -1, thumbnail, description);
7215 if (pr.finished) {
7216 pr.receiver.finished();
7217 }
7218 } catch (Exception e) {
7219 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7220 }
7221 }
7222 }
7223 }
7224
7225 // =========================================================
7226 // CONTENT PROVIDERS
7227 // =========================================================
7228
7229 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7230 List providers = null;
7231 try {
7232 providers = ActivityThread.getPackageManager().
7233 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007234 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007235 } catch (RemoteException ex) {
7236 }
7237 if (providers != null) {
7238 final int N = providers.size();
7239 for (int i=0; i<N; i++) {
7240 ProviderInfo cpi =
7241 (ProviderInfo)providers.get(i);
7242 ContentProviderRecord cpr =
7243 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7244 if (cpr == null) {
7245 cpr = new ContentProviderRecord(cpi, app.info);
7246 mProvidersByClass.put(cpi.name, cpr);
7247 }
7248 app.pubProviders.put(cpi.name, cpr);
7249 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007250 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007251 }
7252 }
7253 return providers;
7254 }
7255
7256 private final String checkContentProviderPermissionLocked(
7257 ProviderInfo cpi, ProcessRecord r, int mode) {
7258 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7259 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7260 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7261 cpi.exported ? -1 : cpi.applicationInfo.uid)
7262 == PackageManager.PERMISSION_GRANTED
7263 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7264 return null;
7265 }
7266 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7267 cpi.exported ? -1 : cpi.applicationInfo.uid)
7268 == PackageManager.PERMISSION_GRANTED) {
7269 return null;
7270 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007271
7272 PathPermission[] pps = cpi.pathPermissions;
7273 if (pps != null) {
7274 int i = pps.length;
7275 while (i > 0) {
7276 i--;
7277 PathPermission pp = pps[i];
7278 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7279 cpi.exported ? -1 : cpi.applicationInfo.uid)
7280 == PackageManager.PERMISSION_GRANTED
7281 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7282 return null;
7283 }
7284 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7285 cpi.exported ? -1 : cpi.applicationInfo.uid)
7286 == PackageManager.PERMISSION_GRANTED) {
7287 return null;
7288 }
7289 }
7290 }
7291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007292 String msg = "Permission Denial: opening provider " + cpi.name
7293 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7294 + ", uid=" + callingUid + ") requires "
7295 + cpi.readPermission + " or " + cpi.writePermission;
7296 Log.w(TAG, msg);
7297 return msg;
7298 }
7299
7300 private final ContentProviderHolder getContentProviderImpl(
7301 IApplicationThread caller, String name) {
7302 ContentProviderRecord cpr;
7303 ProviderInfo cpi = null;
7304
7305 synchronized(this) {
7306 ProcessRecord r = null;
7307 if (caller != null) {
7308 r = getRecordForAppLocked(caller);
7309 if (r == null) {
7310 throw new SecurityException(
7311 "Unable to find app for caller " + caller
7312 + " (pid=" + Binder.getCallingPid()
7313 + ") when getting content provider " + name);
7314 }
7315 }
7316
7317 // First check if this content provider has been published...
7318 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7319 if (cpr != null) {
7320 cpi = cpr.info;
7321 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7322 return new ContentProviderHolder(cpi,
7323 cpi.readPermission != null
7324 ? cpi.readPermission : cpi.writePermission);
7325 }
7326
7327 if (r != null && cpr.canRunHere(r)) {
7328 // This provider has been published or is in the process
7329 // of being published... but it is also allowed to run
7330 // in the caller's process, so don't make a connection
7331 // and just let the caller instantiate its own instance.
7332 if (cpr.provider != null) {
7333 // don't give caller the provider object, it needs
7334 // to make its own.
7335 cpr = new ContentProviderRecord(cpr);
7336 }
7337 return cpr;
7338 }
7339
7340 final long origId = Binder.clearCallingIdentity();
7341
7342 // In this case the provider is a single instance, so we can
7343 // return it right away.
7344 if (r != null) {
7345 r.conProviders.add(cpr);
7346 cpr.clients.add(r);
7347 } else {
7348 cpr.externals++;
7349 }
7350
7351 if (cpr.app != null) {
7352 updateOomAdjLocked(cpr.app);
7353 }
7354
7355 Binder.restoreCallingIdentity(origId);
7356
7357 } else {
7358 try {
7359 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007360 resolveContentProvider(name,
7361 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007362 } catch (RemoteException ex) {
7363 }
7364 if (cpi == null) {
7365 return null;
7366 }
7367
7368 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7369 return new ContentProviderHolder(cpi,
7370 cpi.readPermission != null
7371 ? cpi.readPermission : cpi.writePermission);
7372 }
7373
7374 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7375 final boolean firstClass = cpr == null;
7376 if (firstClass) {
7377 try {
7378 ApplicationInfo ai =
7379 ActivityThread.getPackageManager().
7380 getApplicationInfo(
7381 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007382 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007383 if (ai == null) {
7384 Log.w(TAG, "No package info for content provider "
7385 + cpi.name);
7386 return null;
7387 }
7388 cpr = new ContentProviderRecord(cpi, ai);
7389 } catch (RemoteException ex) {
7390 // pm is in same process, this will never happen.
7391 }
7392 }
7393
7394 if (r != null && cpr.canRunHere(r)) {
7395 // If this is a multiprocess provider, then just return its
7396 // info and allow the caller to instantiate it. Only do
7397 // this if the provider is the same user as the caller's
7398 // process, or can run as root (so can be in any process).
7399 return cpr;
7400 }
7401
7402 if (false) {
7403 RuntimeException e = new RuntimeException("foo");
7404 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7405 // + " pruid " + ai.uid + "): " + cpi.className, e);
7406 }
7407
7408 // This is single process, and our app is now connecting to it.
7409 // See if we are already in the process of launching this
7410 // provider.
7411 final int N = mLaunchingProviders.size();
7412 int i;
7413 for (i=0; i<N; i++) {
7414 if (mLaunchingProviders.get(i) == cpr) {
7415 break;
7416 }
7417 if (false) {
7418 final ContentProviderRecord rec =
7419 (ContentProviderRecord)mLaunchingProviders.get(i);
7420 if (rec.info.name.equals(cpr.info.name)) {
7421 cpr = rec;
7422 break;
7423 }
7424 }
7425 }
7426
7427 // If the provider is not already being launched, then get it
7428 // started.
7429 if (i >= N) {
7430 final long origId = Binder.clearCallingIdentity();
7431 ProcessRecord proc = startProcessLocked(cpi.processName,
7432 cpr.appInfo, false, 0, "content provider",
7433 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007434 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007435 if (proc == null) {
7436 Log.w(TAG, "Unable to launch app "
7437 + cpi.applicationInfo.packageName + "/"
7438 + cpi.applicationInfo.uid + " for provider "
7439 + name + ": process is bad");
7440 return null;
7441 }
7442 cpr.launchingApp = proc;
7443 mLaunchingProviders.add(cpr);
7444 Binder.restoreCallingIdentity(origId);
7445 }
7446
7447 // Make sure the provider is published (the same provider class
7448 // may be published under multiple names).
7449 if (firstClass) {
7450 mProvidersByClass.put(cpi.name, cpr);
7451 }
7452 mProvidersByName.put(name, cpr);
7453
7454 if (r != null) {
7455 r.conProviders.add(cpr);
7456 cpr.clients.add(r);
7457 } else {
7458 cpr.externals++;
7459 }
7460 }
7461 }
7462
7463 // Wait for the provider to be published...
7464 synchronized (cpr) {
7465 while (cpr.provider == null) {
7466 if (cpr.launchingApp == null) {
7467 Log.w(TAG, "Unable to launch app "
7468 + cpi.applicationInfo.packageName + "/"
7469 + cpi.applicationInfo.uid + " for provider "
7470 + name + ": launching app became null");
7471 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7472 cpi.applicationInfo.packageName,
7473 cpi.applicationInfo.uid, name);
7474 return null;
7475 }
7476 try {
7477 cpr.wait();
7478 } catch (InterruptedException ex) {
7479 }
7480 }
7481 }
7482 return cpr;
7483 }
7484
7485 public final ContentProviderHolder getContentProvider(
7486 IApplicationThread caller, String name) {
7487 if (caller == null) {
7488 String msg = "null IApplicationThread when getting content provider "
7489 + name;
7490 Log.w(TAG, msg);
7491 throw new SecurityException(msg);
7492 }
7493
7494 return getContentProviderImpl(caller, name);
7495 }
7496
7497 private ContentProviderHolder getContentProviderExternal(String name) {
7498 return getContentProviderImpl(null, name);
7499 }
7500
7501 /**
7502 * Drop a content provider from a ProcessRecord's bookkeeping
7503 * @param cpr
7504 */
7505 public void removeContentProvider(IApplicationThread caller, String name) {
7506 synchronized (this) {
7507 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7508 if(cpr == null) {
7509 //remove from mProvidersByClass
7510 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7511 return;
7512 }
7513 final ProcessRecord r = getRecordForAppLocked(caller);
7514 if (r == null) {
7515 throw new SecurityException(
7516 "Unable to find app for caller " + caller +
7517 " when removing content provider " + name);
7518 }
7519 //update content provider record entry info
7520 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7521 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7522 r.info.processName+" from process "+localCpr.appInfo.processName);
7523 if(localCpr.appInfo.processName == r.info.processName) {
7524 //should not happen. taken care of as a local provider
7525 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7526 return;
7527 } else {
7528 localCpr.clients.remove(r);
7529 r.conProviders.remove(localCpr);
7530 }
7531 updateOomAdjLocked();
7532 }
7533 }
7534
7535 private void removeContentProviderExternal(String name) {
7536 synchronized (this) {
7537 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7538 if(cpr == null) {
7539 //remove from mProvidersByClass
7540 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7541 return;
7542 }
7543
7544 //update content provider record entry info
7545 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7546 localCpr.externals--;
7547 if (localCpr.externals < 0) {
7548 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7549 }
7550 updateOomAdjLocked();
7551 }
7552 }
7553
7554 public final void publishContentProviders(IApplicationThread caller,
7555 List<ContentProviderHolder> providers) {
7556 if (providers == null) {
7557 return;
7558 }
7559
7560 synchronized(this) {
7561 final ProcessRecord r = getRecordForAppLocked(caller);
7562 if (r == null) {
7563 throw new SecurityException(
7564 "Unable to find app for caller " + caller
7565 + " (pid=" + Binder.getCallingPid()
7566 + ") when publishing content providers");
7567 }
7568
7569 final long origId = Binder.clearCallingIdentity();
7570
7571 final int N = providers.size();
7572 for (int i=0; i<N; i++) {
7573 ContentProviderHolder src = providers.get(i);
7574 if (src == null || src.info == null || src.provider == null) {
7575 continue;
7576 }
7577 ContentProviderRecord dst =
7578 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7579 if (dst != null) {
7580 mProvidersByClass.put(dst.info.name, dst);
7581 String names[] = dst.info.authority.split(";");
7582 for (int j = 0; j < names.length; j++) {
7583 mProvidersByName.put(names[j], dst);
7584 }
7585
7586 int NL = mLaunchingProviders.size();
7587 int j;
7588 for (j=0; j<NL; j++) {
7589 if (mLaunchingProviders.get(j) == dst) {
7590 mLaunchingProviders.remove(j);
7591 j--;
7592 NL--;
7593 }
7594 }
7595 synchronized (dst) {
7596 dst.provider = src.provider;
7597 dst.app = r;
7598 dst.notifyAll();
7599 }
7600 updateOomAdjLocked(r);
7601 }
7602 }
7603
7604 Binder.restoreCallingIdentity(origId);
7605 }
7606 }
7607
7608 public static final void installSystemProviders() {
7609 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7610 List providers = mSelf.generateApplicationProvidersLocked(app);
7611 mSystemThread.installSystemProviders(providers);
7612 }
7613
7614 // =========================================================
7615 // GLOBAL MANAGEMENT
7616 // =========================================================
7617
7618 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7619 ApplicationInfo info, String customProcess) {
7620 String proc = customProcess != null ? customProcess : info.processName;
7621 BatteryStatsImpl.Uid.Proc ps = null;
7622 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7623 synchronized (stats) {
7624 ps = stats.getProcessStatsLocked(info.uid, proc);
7625 }
7626 return new ProcessRecord(ps, thread, info, proc);
7627 }
7628
7629 final ProcessRecord addAppLocked(ApplicationInfo info) {
7630 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7631
7632 if (app == null) {
7633 app = newProcessRecordLocked(null, info, null);
7634 mProcessNames.put(info.processName, info.uid, app);
7635 updateLRUListLocked(app, true);
7636 }
7637
7638 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7639 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7640 app.persistent = true;
7641 app.maxAdj = CORE_SERVER_ADJ;
7642 }
7643 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7644 mPersistentStartingProcesses.add(app);
7645 startProcessLocked(app, "added application", app.processName);
7646 }
7647
7648 return app;
7649 }
7650
7651 public void unhandledBack() {
7652 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7653 "unhandledBack()");
7654
7655 synchronized(this) {
7656 int count = mHistory.size();
7657 if (Config.LOGD) Log.d(
7658 TAG, "Performing unhandledBack(): stack size = " + count);
7659 if (count > 1) {
7660 final long origId = Binder.clearCallingIdentity();
7661 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7662 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7663 Binder.restoreCallingIdentity(origId);
7664 }
7665 }
7666 }
7667
7668 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7669 String name = uri.getAuthority();
7670 ContentProviderHolder cph = getContentProviderExternal(name);
7671 ParcelFileDescriptor pfd = null;
7672 if (cph != null) {
7673 // We record the binder invoker's uid in thread-local storage before
7674 // going to the content provider to open the file. Later, in the code
7675 // that handles all permissions checks, we look for this uid and use
7676 // that rather than the Activity Manager's own uid. The effect is that
7677 // we do the check against the caller's permissions even though it looks
7678 // to the content provider like the Activity Manager itself is making
7679 // the request.
7680 sCallerIdentity.set(new Identity(
7681 Binder.getCallingPid(), Binder.getCallingUid()));
7682 try {
7683 pfd = cph.provider.openFile(uri, "r");
7684 } catch (FileNotFoundException e) {
7685 // do nothing; pfd will be returned null
7686 } finally {
7687 // Ensure that whatever happens, we clean up the identity state
7688 sCallerIdentity.remove();
7689 }
7690
7691 // We've got the fd now, so we're done with the provider.
7692 removeContentProviderExternal(name);
7693 } else {
7694 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7695 }
7696 return pfd;
7697 }
7698
7699 public void goingToSleep() {
7700 synchronized(this) {
7701 mSleeping = true;
7702 mWindowManager.setEventDispatching(false);
7703
7704 if (mResumedActivity != null) {
7705 pauseIfSleepingLocked();
7706 } else {
7707 Log.w(TAG, "goingToSleep with no resumed activity!");
7708 }
7709 }
7710 }
7711
Dianne Hackborn55280a92009-05-07 15:53:46 -07007712 public boolean shutdown(int timeout) {
7713 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7714 != PackageManager.PERMISSION_GRANTED) {
7715 throw new SecurityException("Requires permission "
7716 + android.Manifest.permission.SHUTDOWN);
7717 }
7718
7719 boolean timedout = false;
7720
7721 synchronized(this) {
7722 mShuttingDown = true;
7723 mWindowManager.setEventDispatching(false);
7724
7725 if (mResumedActivity != null) {
7726 pauseIfSleepingLocked();
7727 final long endTime = System.currentTimeMillis() + timeout;
7728 while (mResumedActivity != null || mPausingActivity != null) {
7729 long delay = endTime - System.currentTimeMillis();
7730 if (delay <= 0) {
7731 Log.w(TAG, "Activity manager shutdown timed out");
7732 timedout = true;
7733 break;
7734 }
7735 try {
7736 this.wait();
7737 } catch (InterruptedException e) {
7738 }
7739 }
7740 }
7741 }
7742
7743 mUsageStatsService.shutdown();
7744 mBatteryStatsService.shutdown();
7745
7746 return timedout;
7747 }
7748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007749 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007750 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007751 if (!mGoingToSleep.isHeld()) {
7752 mGoingToSleep.acquire();
7753 if (mLaunchingActivity.isHeld()) {
7754 mLaunchingActivity.release();
7755 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7756 }
7757 }
7758
7759 // If we are not currently pausing an activity, get the current
7760 // one to pause. If we are pausing one, we will just let that stuff
7761 // run and release the wake lock when all done.
7762 if (mPausingActivity == null) {
7763 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7764 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7765 startPausingLocked(false, true);
7766 }
7767 }
7768 }
7769
7770 public void wakingUp() {
7771 synchronized(this) {
7772 if (mGoingToSleep.isHeld()) {
7773 mGoingToSleep.release();
7774 }
7775 mWindowManager.setEventDispatching(true);
7776 mSleeping = false;
7777 resumeTopActivityLocked(null);
7778 }
7779 }
7780
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007781 public void stopAppSwitches() {
7782 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7783 != PackageManager.PERMISSION_GRANTED) {
7784 throw new SecurityException("Requires permission "
7785 + android.Manifest.permission.STOP_APP_SWITCHES);
7786 }
7787
7788 synchronized(this) {
7789 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7790 + APP_SWITCH_DELAY_TIME;
7791 mDidAppSwitch = false;
7792 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7793 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7794 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7795 }
7796 }
7797
7798 public void resumeAppSwitches() {
7799 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7800 != PackageManager.PERMISSION_GRANTED) {
7801 throw new SecurityException("Requires permission "
7802 + android.Manifest.permission.STOP_APP_SWITCHES);
7803 }
7804
7805 synchronized(this) {
7806 // Note that we don't execute any pending app switches... we will
7807 // let those wait until either the timeout, or the next start
7808 // activity request.
7809 mAppSwitchesAllowedTime = 0;
7810 }
7811 }
7812
7813 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7814 String name) {
7815 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7816 return true;
7817 }
7818
7819 final int perm = checkComponentPermission(
7820 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7821 callingUid, -1);
7822 if (perm == PackageManager.PERMISSION_GRANTED) {
7823 return true;
7824 }
7825
7826 Log.w(TAG, name + " request from " + callingUid + " stopped");
7827 return false;
7828 }
7829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007830 public void setDebugApp(String packageName, boolean waitForDebugger,
7831 boolean persistent) {
7832 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7833 "setDebugApp()");
7834
7835 // Note that this is not really thread safe if there are multiple
7836 // callers into it at the same time, but that's not a situation we
7837 // care about.
7838 if (persistent) {
7839 final ContentResolver resolver = mContext.getContentResolver();
7840 Settings.System.putString(
7841 resolver, Settings.System.DEBUG_APP,
7842 packageName);
7843 Settings.System.putInt(
7844 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7845 waitForDebugger ? 1 : 0);
7846 }
7847
7848 synchronized (this) {
7849 if (!persistent) {
7850 mOrigDebugApp = mDebugApp;
7851 mOrigWaitForDebugger = mWaitForDebugger;
7852 }
7853 mDebugApp = packageName;
7854 mWaitForDebugger = waitForDebugger;
7855 mDebugTransient = !persistent;
7856 if (packageName != null) {
7857 final long origId = Binder.clearCallingIdentity();
7858 uninstallPackageLocked(packageName, -1, false);
7859 Binder.restoreCallingIdentity(origId);
7860 }
7861 }
7862 }
7863
7864 public void setAlwaysFinish(boolean enabled) {
7865 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7866 "setAlwaysFinish()");
7867
7868 Settings.System.putInt(
7869 mContext.getContentResolver(),
7870 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7871
7872 synchronized (this) {
7873 mAlwaysFinishActivities = enabled;
7874 }
7875 }
7876
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007877 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007878 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007879 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007880 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007881 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007882 }
7883 }
7884
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007885 public void registerActivityWatcher(IActivityWatcher watcher) {
7886 mWatchers.register(watcher);
7887 }
7888
7889 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7890 mWatchers.unregister(watcher);
7891 }
7892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007893 public final void enterSafeMode() {
7894 synchronized(this) {
7895 // It only makes sense to do this before the system is ready
7896 // and started launching other packages.
7897 if (!mSystemReady) {
7898 try {
7899 ActivityThread.getPackageManager().enterSafeMode();
7900 } catch (RemoteException e) {
7901 }
7902
7903 View v = LayoutInflater.from(mContext).inflate(
7904 com.android.internal.R.layout.safe_mode, null);
7905 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7906 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7907 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7908 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7909 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7910 lp.format = v.getBackground().getOpacity();
7911 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7912 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7913 ((WindowManager)mContext.getSystemService(
7914 Context.WINDOW_SERVICE)).addView(v, lp);
7915 }
7916 }
7917 }
7918
7919 public void noteWakeupAlarm(IIntentSender sender) {
7920 if (!(sender instanceof PendingIntentRecord)) {
7921 return;
7922 }
7923 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7924 synchronized (stats) {
7925 if (mBatteryStatsService.isOnBattery()) {
7926 mBatteryStatsService.enforceCallingPermission();
7927 PendingIntentRecord rec = (PendingIntentRecord)sender;
7928 int MY_UID = Binder.getCallingUid();
7929 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7930 BatteryStatsImpl.Uid.Pkg pkg =
7931 stats.getPackageStatsLocked(uid, rec.key.packageName);
7932 pkg.incWakeupsLocked();
7933 }
7934 }
7935 }
7936
7937 public boolean killPidsForMemory(int[] pids) {
7938 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7939 throw new SecurityException("killPidsForMemory only available to the system");
7940 }
7941
7942 // XXX Note: don't acquire main activity lock here, because the window
7943 // manager calls in with its locks held.
7944
7945 boolean killed = false;
7946 synchronized (mPidsSelfLocked) {
7947 int[] types = new int[pids.length];
7948 int worstType = 0;
7949 for (int i=0; i<pids.length; i++) {
7950 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7951 if (proc != null) {
7952 int type = proc.setAdj;
7953 types[i] = type;
7954 if (type > worstType) {
7955 worstType = type;
7956 }
7957 }
7958 }
7959
7960 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7961 // then constrain it so we will kill all hidden procs.
7962 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7963 worstType = HIDDEN_APP_MIN_ADJ;
7964 }
7965 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7966 for (int i=0; i<pids.length; i++) {
7967 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7968 if (proc == null) {
7969 continue;
7970 }
7971 int adj = proc.setAdj;
7972 if (adj >= worstType) {
7973 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7974 + adj + ")");
7975 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7976 proc.processName, adj);
7977 killed = true;
7978 Process.killProcess(pids[i]);
7979 }
7980 }
7981 }
7982 return killed;
7983 }
7984
7985 public void reportPss(IApplicationThread caller, int pss) {
7986 Watchdog.PssRequestor req;
7987 String name;
7988 ProcessRecord callerApp;
7989 synchronized (this) {
7990 if (caller == null) {
7991 return;
7992 }
7993 callerApp = getRecordForAppLocked(caller);
7994 if (callerApp == null) {
7995 return;
7996 }
7997 callerApp.lastPss = pss;
7998 req = callerApp;
7999 name = callerApp.processName;
8000 }
8001 Watchdog.getInstance().reportPss(req, name, pss);
8002 if (!callerApp.persistent) {
8003 removeRequestedPss(callerApp);
8004 }
8005 }
8006
8007 public void requestPss(Runnable completeCallback) {
8008 ArrayList<ProcessRecord> procs;
8009 synchronized (this) {
8010 mRequestPssCallback = completeCallback;
8011 mRequestPssList.clear();
8012 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8013 ProcessRecord proc = mLRUProcesses.get(i);
8014 if (!proc.persistent) {
8015 mRequestPssList.add(proc);
8016 }
8017 }
8018 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8019 }
8020
8021 int oldPri = Process.getThreadPriority(Process.myTid());
8022 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8023 for (int i=procs.size()-1; i>=0; i--) {
8024 ProcessRecord proc = procs.get(i);
8025 proc.lastPss = 0;
8026 proc.requestPss();
8027 }
8028 Process.setThreadPriority(oldPri);
8029 }
8030
8031 void removeRequestedPss(ProcessRecord proc) {
8032 Runnable callback = null;
8033 synchronized (this) {
8034 if (mRequestPssList.remove(proc)) {
8035 if (mRequestPssList.size() == 0) {
8036 callback = mRequestPssCallback;
8037 mRequestPssCallback = null;
8038 }
8039 }
8040 }
8041
8042 if (callback != null) {
8043 callback.run();
8044 }
8045 }
8046
8047 public void collectPss(Watchdog.PssStats stats) {
8048 stats.mEmptyPss = 0;
8049 stats.mEmptyCount = 0;
8050 stats.mBackgroundPss = 0;
8051 stats.mBackgroundCount = 0;
8052 stats.mServicePss = 0;
8053 stats.mServiceCount = 0;
8054 stats.mVisiblePss = 0;
8055 stats.mVisibleCount = 0;
8056 stats.mForegroundPss = 0;
8057 stats.mForegroundCount = 0;
8058 stats.mNoPssCount = 0;
8059 synchronized (this) {
8060 int i;
8061 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8062 ? mProcDeaths.length : stats.mProcDeaths.length;
8063 int aggr = 0;
8064 for (i=0; i<NPD; i++) {
8065 aggr += mProcDeaths[i];
8066 stats.mProcDeaths[i] = aggr;
8067 }
8068 while (i<stats.mProcDeaths.length) {
8069 stats.mProcDeaths[i] = 0;
8070 i++;
8071 }
8072
8073 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8074 ProcessRecord proc = mLRUProcesses.get(i);
8075 if (proc.persistent) {
8076 continue;
8077 }
8078 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8079 if (proc.lastPss == 0) {
8080 stats.mNoPssCount++;
8081 continue;
8082 }
8083 if (proc.setAdj == EMPTY_APP_ADJ) {
8084 stats.mEmptyPss += proc.lastPss;
8085 stats.mEmptyCount++;
8086 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8087 stats.mEmptyPss += proc.lastPss;
8088 stats.mEmptyCount++;
8089 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8090 stats.mBackgroundPss += proc.lastPss;
8091 stats.mBackgroundCount++;
8092 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8093 stats.mVisiblePss += proc.lastPss;
8094 stats.mVisibleCount++;
8095 } else {
8096 stats.mForegroundPss += proc.lastPss;
8097 stats.mForegroundCount++;
8098 }
8099 }
8100 }
8101 }
8102
8103 public final void startRunning(String pkg, String cls, String action,
8104 String data) {
8105 synchronized(this) {
8106 if (mStartRunning) {
8107 return;
8108 }
8109 mStartRunning = true;
8110 mTopComponent = pkg != null && cls != null
8111 ? new ComponentName(pkg, cls) : null;
8112 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8113 mTopData = data;
8114 if (!mSystemReady) {
8115 return;
8116 }
8117 }
8118
8119 systemReady();
8120 }
8121
8122 private void retrieveSettings() {
8123 final ContentResolver resolver = mContext.getContentResolver();
8124 String debugApp = Settings.System.getString(
8125 resolver, Settings.System.DEBUG_APP);
8126 boolean waitForDebugger = Settings.System.getInt(
8127 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8128 boolean alwaysFinishActivities = Settings.System.getInt(
8129 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8130
8131 Configuration configuration = new Configuration();
8132 Settings.System.getConfiguration(resolver, configuration);
8133
8134 synchronized (this) {
8135 mDebugApp = mOrigDebugApp = debugApp;
8136 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8137 mAlwaysFinishActivities = alwaysFinishActivities;
8138 // This happens before any activities are started, so we can
8139 // change mConfiguration in-place.
8140 mConfiguration.updateFrom(configuration);
8141 }
8142 }
8143
8144 public boolean testIsSystemReady() {
8145 // no need to synchronize(this) just to read & return the value
8146 return mSystemReady;
8147 }
8148
8149 public void systemReady() {
8150 // In the simulator, startRunning will never have been called, which
8151 // normally sets a few crucial variables. Do it here instead.
8152 if (!Process.supportsProcesses()) {
8153 mStartRunning = true;
8154 mTopAction = Intent.ACTION_MAIN;
8155 }
8156
8157 synchronized(this) {
8158 if (mSystemReady) {
8159 return;
8160 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008161
8162 // Check to see if there are any update receivers to run.
8163 if (!mDidUpdate) {
8164 if (mWaitingUpdate) {
8165 return;
8166 }
8167 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8168 List<ResolveInfo> ris = null;
8169 try {
8170 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8171 intent, null, 0);
8172 } catch (RemoteException e) {
8173 }
8174 if (ris != null) {
8175 for (int i=ris.size()-1; i>=0; i--) {
8176 if ((ris.get(i).activityInfo.applicationInfo.flags
8177 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8178 ris.remove(i);
8179 }
8180 }
8181 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8182 for (int i=0; i<ris.size(); i++) {
8183 ActivityInfo ai = ris.get(i).activityInfo;
8184 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8185 IIntentReceiver finisher = null;
8186 if (i == 0) {
8187 finisher = new IIntentReceiver.Stub() {
8188 public void performReceive(Intent intent, int resultCode,
8189 String data, Bundle extras, boolean ordered)
8190 throws RemoteException {
8191 synchronized (ActivityManagerService.this) {
8192 mDidUpdate = true;
8193 }
8194 systemReady();
8195 }
8196 };
8197 }
8198 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8199 broadcastIntentLocked(null, null, intent, null, finisher,
8200 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8201 if (i == 0) {
8202 mWaitingUpdate = true;
8203 }
8204 }
8205 }
8206 if (mWaitingUpdate) {
8207 return;
8208 }
8209 mDidUpdate = true;
8210 }
8211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008212 mSystemReady = true;
8213 if (!mStartRunning) {
8214 return;
8215 }
8216 }
8217
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008218 ArrayList<ProcessRecord> procsToKill = null;
8219 synchronized(mPidsSelfLocked) {
8220 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8221 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8222 if (!isAllowedWhileBooting(proc.info)){
8223 if (procsToKill == null) {
8224 procsToKill = new ArrayList<ProcessRecord>();
8225 }
8226 procsToKill.add(proc);
8227 }
8228 }
8229 }
8230
8231 if (procsToKill != null) {
8232 synchronized(this) {
8233 for (int i=procsToKill.size()-1; i>=0; i--) {
8234 ProcessRecord proc = procsToKill.get(i);
8235 Log.i(TAG, "Removing system update proc: " + proc);
8236 removeProcessLocked(proc, true);
8237 }
8238 }
8239 }
8240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008241 if (Config.LOGD) Log.d(TAG, "Start running!");
8242 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8243 SystemClock.uptimeMillis());
8244
8245 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008246 // Make sure we have no pre-ready processes sitting around.
8247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008248 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8249 ResolveInfo ri = mContext.getPackageManager()
8250 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008251 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008252 CharSequence errorMsg = null;
8253 if (ri != null) {
8254 ActivityInfo ai = ri.activityInfo;
8255 ApplicationInfo app = ai.applicationInfo;
8256 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8257 mTopAction = Intent.ACTION_FACTORY_TEST;
8258 mTopData = null;
8259 mTopComponent = new ComponentName(app.packageName,
8260 ai.name);
8261 } else {
8262 errorMsg = mContext.getResources().getText(
8263 com.android.internal.R.string.factorytest_not_system);
8264 }
8265 } else {
8266 errorMsg = mContext.getResources().getText(
8267 com.android.internal.R.string.factorytest_no_action);
8268 }
8269 if (errorMsg != null) {
8270 mTopAction = null;
8271 mTopData = null;
8272 mTopComponent = null;
8273 Message msg = Message.obtain();
8274 msg.what = SHOW_FACTORY_ERROR_MSG;
8275 msg.getData().putCharSequence("msg", errorMsg);
8276 mHandler.sendMessage(msg);
8277 }
8278 }
8279 }
8280
8281 retrieveSettings();
8282
8283 synchronized (this) {
8284 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8285 try {
8286 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008287 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008288 if (apps != null) {
8289 int N = apps.size();
8290 int i;
8291 for (i=0; i<N; i++) {
8292 ApplicationInfo info
8293 = (ApplicationInfo)apps.get(i);
8294 if (info != null &&
8295 !info.packageName.equals("android")) {
8296 addAppLocked(info);
8297 }
8298 }
8299 }
8300 } catch (RemoteException ex) {
8301 // pm is in same process, this will never happen.
8302 }
8303 }
8304
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008305 // Start up initial activity.
8306 mBooting = true;
8307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008308 try {
8309 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8310 Message msg = Message.obtain();
8311 msg.what = SHOW_UID_ERROR_MSG;
8312 mHandler.sendMessage(msg);
8313 }
8314 } catch (RemoteException e) {
8315 }
8316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008317 resumeTopActivityLocked(null);
8318 }
8319 }
8320
8321 boolean makeAppCrashingLocked(ProcessRecord app,
8322 String tag, String shortMsg, String longMsg, byte[] crashData) {
8323 app.crashing = true;
8324 app.crashingReport = generateProcessError(app,
8325 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8326 startAppProblemLocked(app);
8327 app.stopFreezingAllLocked();
8328 return handleAppCrashLocked(app);
8329 }
8330
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008331 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8332 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008333
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008334 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008335 // look for receiver in the installer package
8336 String candidate = pm.getInstallerPackageName(app.info.packageName);
8337 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8338 if (result != null) {
8339 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008340 }
8341
Jacek Surazski82a73df2009-06-17 14:33:18 +02008342 // if the error app is on the system image, look for system apps
8343 // error receiver
8344 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8345 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8346 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8347 if (result != null) {
8348 return result;
8349 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008350 }
8351
Jacek Surazski82a73df2009-06-17 14:33:18 +02008352 // if there is a default receiver, try that
8353 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8354 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008355 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008356 // should not happen
8357 Log.e(TAG, "error talking to PackageManager", e);
8358 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008359 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008360 }
8361
8362 /**
8363 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8364 *
8365 * @param pm PackageManager isntance
8366 * @param errorPackage package which caused the error
8367 * @param receiverPackage candidate package to receive the error
8368 * @return activity component within receiverPackage which handles
8369 * ACTION_APP_ERROR, or null if not found
8370 */
8371 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8372 String receiverPackage) throws RemoteException {
8373 if (receiverPackage == null || receiverPackage.length() == 0) {
8374 return null;
8375 }
8376
8377 // break the loop if it's the error report receiver package that crashed
8378 if (receiverPackage.equals(errorPackage)) {
8379 return null;
8380 }
8381
8382 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8383 intent.setPackage(receiverPackage);
8384 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8385 if (info == null || info.activityInfo == null) {
8386 return null;
8387 }
8388 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008389 }
8390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008391 void makeAppNotRespondingLocked(ProcessRecord app,
8392 String tag, String shortMsg, String longMsg, byte[] crashData) {
8393 app.notResponding = true;
8394 app.notRespondingReport = generateProcessError(app,
8395 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8396 crashData);
8397 startAppProblemLocked(app);
8398 app.stopFreezingAllLocked();
8399 }
8400
8401 /**
8402 * Generate a process error record, suitable for attachment to a ProcessRecord.
8403 *
8404 * @param app The ProcessRecord in which the error occurred.
8405 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8406 * ActivityManager.AppErrorStateInfo
8407 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8408 * @param shortMsg Short message describing the crash.
8409 * @param longMsg Long message describing the crash.
8410 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8411 *
8412 * @return Returns a fully-formed AppErrorStateInfo record.
8413 */
8414 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8415 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8416 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8417
8418 report.condition = condition;
8419 report.processName = app.processName;
8420 report.pid = app.pid;
8421 report.uid = app.info.uid;
8422 report.tag = tag;
8423 report.shortMsg = shortMsg;
8424 report.longMsg = longMsg;
8425 report.crashData = crashData;
8426
8427 return report;
8428 }
8429
8430 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8431 boolean crashed) {
8432 synchronized (this) {
8433 app.crashing = false;
8434 app.crashingReport = null;
8435 app.notResponding = false;
8436 app.notRespondingReport = null;
8437 if (app.anrDialog == fromDialog) {
8438 app.anrDialog = null;
8439 }
8440 if (app.waitDialog == fromDialog) {
8441 app.waitDialog = null;
8442 }
8443 if (app.pid > 0 && app.pid != MY_PID) {
8444 if (crashed) {
8445 handleAppCrashLocked(app);
8446 }
8447 Log.i(ActivityManagerService.TAG, "Killing process "
8448 + app.processName
8449 + " (pid=" + app.pid + ") at user's request");
8450 Process.killProcess(app.pid);
8451 }
8452
8453 }
8454 }
8455
8456 boolean handleAppCrashLocked(ProcessRecord app) {
8457 long now = SystemClock.uptimeMillis();
8458
8459 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8460 app.info.uid);
8461 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8462 // This process loses!
8463 Log.w(TAG, "Process " + app.info.processName
8464 + " has crashed too many times: killing!");
8465 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8466 app.info.processName, app.info.uid);
8467 killServicesLocked(app, false);
8468 for (int i=mHistory.size()-1; i>=0; i--) {
8469 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8470 if (r.app == app) {
8471 if (Config.LOGD) Log.d(
8472 TAG, " Force finishing activity "
8473 + r.intent.getComponent().flattenToShortString());
8474 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8475 }
8476 }
8477 if (!app.persistent) {
8478 // We don't want to start this process again until the user
8479 // explicitly does so... but for persistent process, we really
8480 // need to keep it running. If a persistent process is actually
8481 // repeatedly crashing, then badness for everyone.
8482 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8483 app.info.processName);
8484 mBadProcesses.put(app.info.processName, app.info.uid, now);
8485 app.bad = true;
8486 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8487 app.removed = true;
8488 removeProcessLocked(app, false);
8489 return false;
8490 }
8491 }
8492
8493 // Bump up the crash count of any services currently running in the proc.
8494 if (app.services.size() != 0) {
8495 // Any services running in the application need to be placed
8496 // back in the pending list.
8497 Iterator it = app.services.iterator();
8498 while (it.hasNext()) {
8499 ServiceRecord sr = (ServiceRecord)it.next();
8500 sr.crashCount++;
8501 }
8502 }
8503
8504 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8505 return true;
8506 }
8507
8508 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008509 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008510 skipCurrentReceiverLocked(app);
8511 }
8512
8513 void skipCurrentReceiverLocked(ProcessRecord app) {
8514 boolean reschedule = false;
8515 BroadcastRecord r = app.curReceiver;
8516 if (r != null) {
8517 // The current broadcast is waiting for this app's receiver
8518 // to be finished. Looks like that's not going to happen, so
8519 // let the broadcast continue.
8520 logBroadcastReceiverDiscard(r);
8521 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8522 r.resultExtras, r.resultAbort, true);
8523 reschedule = true;
8524 }
8525 r = mPendingBroadcast;
8526 if (r != null && r.curApp == app) {
8527 if (DEBUG_BROADCAST) Log.v(TAG,
8528 "skip & discard pending app " + r);
8529 logBroadcastReceiverDiscard(r);
8530 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8531 r.resultExtras, r.resultAbort, true);
8532 reschedule = true;
8533 }
8534 if (reschedule) {
8535 scheduleBroadcastsLocked();
8536 }
8537 }
8538
8539 public int handleApplicationError(IBinder app, int flags,
8540 String tag, String shortMsg, String longMsg, byte[] crashData) {
8541 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008542 ProcessRecord r = null;
8543 synchronized (this) {
8544 if (app != null) {
8545 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8546 final int NA = apps.size();
8547 for (int ia=0; ia<NA; ia++) {
8548 ProcessRecord p = apps.valueAt(ia);
8549 if (p.thread != null && p.thread.asBinder() == app) {
8550 r = p;
8551 break;
8552 }
8553 }
8554 }
8555 }
8556
8557 if (r != null) {
8558 // The application has crashed. Send the SIGQUIT to the process so
8559 // that it can dump its state.
8560 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8561 //Log.i(TAG, "Current system threads:");
8562 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8563 }
8564
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008565 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566 try {
8567 String name = r != null ? r.processName : null;
8568 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008569 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008570 shortMsg, longMsg, crashData)) {
8571 Log.w(TAG, "Force-killing crashed app " + name
8572 + " at watcher's request");
8573 Process.killProcess(pid);
8574 return 0;
8575 }
8576 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008577 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008578 }
8579 }
8580
8581 final long origId = Binder.clearCallingIdentity();
8582
8583 // If this process is running instrumentation, finish it.
8584 if (r != null && r.instrumentationClass != null) {
8585 Log.w(TAG, "Error in app " + r.processName
8586 + " running instrumentation " + r.instrumentationClass + ":");
8587 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8588 if (longMsg != null) Log.w(TAG, " " + longMsg);
8589 Bundle info = new Bundle();
8590 info.putString("shortMsg", shortMsg);
8591 info.putString("longMsg", longMsg);
8592 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8593 Binder.restoreCallingIdentity(origId);
8594 return 0;
8595 }
8596
8597 if (r != null) {
8598 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8599 return 0;
8600 }
8601 } else {
8602 Log.w(TAG, "Some application object " + app + " tag " + tag
8603 + " has crashed, but I don't know who it is.");
8604 Log.w(TAG, "ShortMsg:" + shortMsg);
8605 Log.w(TAG, "LongMsg:" + longMsg);
8606 Binder.restoreCallingIdentity(origId);
8607 return 0;
8608 }
8609
8610 Message msg = Message.obtain();
8611 msg.what = SHOW_ERROR_MSG;
8612 HashMap data = new HashMap();
8613 data.put("result", result);
8614 data.put("app", r);
8615 data.put("flags", flags);
8616 data.put("shortMsg", shortMsg);
8617 data.put("longMsg", longMsg);
8618 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8619 // For system processes, submit crash data to the server.
8620 data.put("crashData", crashData);
8621 }
8622 msg.obj = data;
8623 mHandler.sendMessage(msg);
8624
8625 Binder.restoreCallingIdentity(origId);
8626 }
8627
8628 int res = result.get();
8629
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008630 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008631 synchronized (this) {
8632 if (r != null) {
8633 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8634 SystemClock.uptimeMillis());
8635 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008636 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8637 appErrorIntent = createAppErrorIntentLocked(r);
8638 res = AppErrorDialog.FORCE_QUIT;
8639 }
8640 }
8641
8642 if (appErrorIntent != null) {
8643 try {
8644 mContext.startActivity(appErrorIntent);
8645 } catch (ActivityNotFoundException e) {
8646 Log.w(TAG, "bug report receiver dissappeared", e);
8647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008648 }
8649
8650 return res;
8651 }
8652
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008653 Intent createAppErrorIntentLocked(ProcessRecord r) {
8654 ApplicationErrorReport report = createAppErrorReportLocked(r);
8655 if (report == null) {
8656 return null;
8657 }
8658 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8659 result.setComponent(r.errorReportReceiver);
8660 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8661 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8662 return result;
8663 }
8664
8665 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8666 if (r.errorReportReceiver == null) {
8667 return null;
8668 }
8669
8670 if (!r.crashing && !r.notResponding) {
8671 return null;
8672 }
8673
8674 try {
8675 ApplicationErrorReport report = new ApplicationErrorReport();
8676 report.packageName = r.info.packageName;
8677 report.installerPackageName = r.errorReportReceiver.getPackageName();
8678 report.processName = r.processName;
8679
8680 if (r.crashing) {
8681 report.type = ApplicationErrorReport.TYPE_CRASH;
8682 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8683
8684 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8685 r.crashingReport.crashData);
8686 DataInputStream dataStream = new DataInputStream(byteStream);
8687 CrashData crashData = new CrashData(dataStream);
8688 ThrowableData throwData = crashData.getThrowableData();
8689
8690 report.time = crashData.getTime();
8691 report.crashInfo.stackTrace = throwData.toString();
8692
Jacek Surazskif829a782009-06-11 22:47:02 +02008693 // Extract the source of the exception, useful for report
8694 // clustering. Also extract the "deepest" non-null exception
8695 // message.
8696 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008697 while (throwData.getCause() != null) {
8698 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008699 String msg = throwData.getMessage();
8700 if (msg != null && msg.length() > 0) {
8701 exceptionMessage = msg;
8702 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008703 }
8704 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008705 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008706 report.crashInfo.exceptionClassName = throwData.getType();
8707 report.crashInfo.throwFileName = trace.getFileName();
8708 report.crashInfo.throwClassName = trace.getClassName();
8709 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008710 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008711 } else if (r.notResponding) {
8712 report.type = ApplicationErrorReport.TYPE_ANR;
8713 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8714
8715 report.anrInfo.activity = r.notRespondingReport.tag;
8716 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8717 report.anrInfo.info = r.notRespondingReport.longMsg;
8718 }
8719
8720 return report;
8721 } catch (IOException e) {
8722 // we don't send it
8723 }
8724
8725 return null;
8726 }
8727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008728 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8729 // assume our apps are happy - lazy create the list
8730 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8731
8732 synchronized (this) {
8733
8734 // iterate across all processes
8735 final int N = mLRUProcesses.size();
8736 for (int i = 0; i < N; i++) {
8737 ProcessRecord app = mLRUProcesses.get(i);
8738 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8739 // This one's in trouble, so we'll generate a report for it
8740 // crashes are higher priority (in case there's a crash *and* an anr)
8741 ActivityManager.ProcessErrorStateInfo report = null;
8742 if (app.crashing) {
8743 report = app.crashingReport;
8744 } else if (app.notResponding) {
8745 report = app.notRespondingReport;
8746 }
8747
8748 if (report != null) {
8749 if (errList == null) {
8750 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8751 }
8752 errList.add(report);
8753 } else {
8754 Log.w(TAG, "Missing app error report, app = " + app.processName +
8755 " crashing = " + app.crashing +
8756 " notResponding = " + app.notResponding);
8757 }
8758 }
8759 }
8760 }
8761
8762 return errList;
8763 }
8764
8765 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8766 // Lazy instantiation of list
8767 List<ActivityManager.RunningAppProcessInfo> runList = null;
8768 synchronized (this) {
8769 // Iterate across all processes
8770 final int N = mLRUProcesses.size();
8771 for (int i = 0; i < N; i++) {
8772 ProcessRecord app = mLRUProcesses.get(i);
8773 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8774 // Generate process state info for running application
8775 ActivityManager.RunningAppProcessInfo currApp =
8776 new ActivityManager.RunningAppProcessInfo(app.processName,
8777 app.pid, app.getPackageList());
8778 int adj = app.curAdj;
8779 if (adj >= CONTENT_PROVIDER_ADJ) {
8780 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8781 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8782 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008783 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8784 } else if (adj >= HOME_APP_ADJ) {
8785 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8786 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008787 } else if (adj >= SECONDARY_SERVER_ADJ) {
8788 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8789 } else if (adj >= VISIBLE_APP_ADJ) {
8790 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8791 } else {
8792 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8793 }
8794 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8795 // + " lru=" + currApp.lru);
8796 if (runList == null) {
8797 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8798 }
8799 runList.add(currApp);
8800 }
8801 }
8802 }
8803 return runList;
8804 }
8805
8806 @Override
8807 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8808 synchronized (this) {
8809 if (checkCallingPermission(android.Manifest.permission.DUMP)
8810 != PackageManager.PERMISSION_GRANTED) {
8811 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8812 + Binder.getCallingPid()
8813 + ", uid=" + Binder.getCallingUid()
8814 + " without permission "
8815 + android.Manifest.permission.DUMP);
8816 return;
8817 }
8818 if (args.length != 0 && "service".equals(args[0])) {
8819 dumpService(fd, pw, args);
8820 return;
8821 }
8822 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008823 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008824 pw.println(" ");
8825 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008826 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008827 if (mWaitingVisibleActivities.size() > 0) {
8828 pw.println(" ");
8829 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008830 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008831 }
8832 if (mStoppingActivities.size() > 0) {
8833 pw.println(" ");
8834 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008835 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008836 }
8837 if (mFinishingActivities.size() > 0) {
8838 pw.println(" ");
8839 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008840 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008841 }
8842
8843 pw.println(" ");
8844 pw.println(" mPausingActivity: " + mPausingActivity);
8845 pw.println(" mResumedActivity: " + mResumedActivity);
8846 pw.println(" mFocusedActivity: " + mFocusedActivity);
8847 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8848
8849 if (mRecentTasks.size() > 0) {
8850 pw.println(" ");
8851 pw.println("Recent tasks in Current Activity Manager State:");
8852
8853 final int N = mRecentTasks.size();
8854 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008855 TaskRecord tr = mRecentTasks.get(i);
8856 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8857 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008858 mRecentTasks.get(i).dump(pw, " ");
8859 }
8860 }
8861
8862 pw.println(" ");
8863 pw.println(" mCurTask: " + mCurTask);
8864
8865 pw.println(" ");
8866 pw.println("Processes in Current Activity Manager State:");
8867
8868 boolean needSep = false;
8869 int numPers = 0;
8870
8871 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8872 final int NA = procs.size();
8873 for (int ia=0; ia<NA; ia++) {
8874 if (!needSep) {
8875 pw.println(" All known processes:");
8876 needSep = true;
8877 }
8878 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008879 pw.print(r.persistent ? " *PERS*" : " *APP*");
8880 pw.print(" UID "); pw.print(procs.keyAt(ia));
8881 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008882 r.dump(pw, " ");
8883 if (r.persistent) {
8884 numPers++;
8885 }
8886 }
8887 }
8888
8889 if (mLRUProcesses.size() > 0) {
8890 if (needSep) pw.println(" ");
8891 needSep = true;
8892 pw.println(" Running processes (most recent first):");
8893 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008894 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008895 needSep = true;
8896 }
8897
8898 synchronized (mPidsSelfLocked) {
8899 if (mPidsSelfLocked.size() > 0) {
8900 if (needSep) pw.println(" ");
8901 needSep = true;
8902 pw.println(" PID mappings:");
8903 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008904 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8905 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008906 }
8907 }
8908 }
8909
8910 if (mForegroundProcesses.size() > 0) {
8911 if (needSep) pw.println(" ");
8912 needSep = true;
8913 pw.println(" Foreground Processes:");
8914 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008915 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8916 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008917 }
8918 }
8919
8920 if (mPersistentStartingProcesses.size() > 0) {
8921 if (needSep) pw.println(" ");
8922 needSep = true;
8923 pw.println(" Persisent processes that are starting:");
8924 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008925 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008926 }
8927
8928 if (mStartingProcesses.size() > 0) {
8929 if (needSep) pw.println(" ");
8930 needSep = true;
8931 pw.println(" Processes that are starting:");
8932 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008933 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 }
8935
8936 if (mRemovedProcesses.size() > 0) {
8937 if (needSep) pw.println(" ");
8938 needSep = true;
8939 pw.println(" Processes that are being removed:");
8940 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008941 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008942 }
8943
8944 if (mProcessesOnHold.size() > 0) {
8945 if (needSep) pw.println(" ");
8946 needSep = true;
8947 pw.println(" Processes that are on old until the system is ready:");
8948 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008949 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008950 }
8951
8952 if (mProcessCrashTimes.getMap().size() > 0) {
8953 if (needSep) pw.println(" ");
8954 needSep = true;
8955 pw.println(" Time since processes crashed:");
8956 long now = SystemClock.uptimeMillis();
8957 for (Map.Entry<String, SparseArray<Long>> procs
8958 : mProcessCrashTimes.getMap().entrySet()) {
8959 SparseArray<Long> uids = procs.getValue();
8960 final int N = uids.size();
8961 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008962 pw.print(" Process "); pw.print(procs.getKey());
8963 pw.print(" uid "); pw.print(uids.keyAt(i));
8964 pw.print(": last crashed ");
8965 pw.print((now-uids.valueAt(i)));
8966 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008967 }
8968 }
8969 }
8970
8971 if (mBadProcesses.getMap().size() > 0) {
8972 if (needSep) pw.println(" ");
8973 needSep = true;
8974 pw.println(" Bad processes:");
8975 for (Map.Entry<String, SparseArray<Long>> procs
8976 : mBadProcesses.getMap().entrySet()) {
8977 SparseArray<Long> uids = procs.getValue();
8978 final int N = uids.size();
8979 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008980 pw.print(" Bad process "); pw.print(procs.getKey());
8981 pw.print(" uid "); pw.print(uids.keyAt(i));
8982 pw.print(": crashed at time ");
8983 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008984 }
8985 }
8986 }
8987
8988 pw.println(" ");
8989 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008990 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008991 pw.println(" mConfiguration: " + mConfiguration);
8992 pw.println(" mStartRunning=" + mStartRunning
8993 + " mSystemReady=" + mSystemReady
8994 + " mBooting=" + mBooting
8995 + " mBooted=" + mBooted
8996 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008997 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008998 pw.println(" mGoingToSleep=" + mGoingToSleep);
8999 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9000 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9001 + " mDebugTransient=" + mDebugTransient
9002 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9003 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009004 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009005 }
9006 }
9007
9008 /**
9009 * There are three ways to call this:
9010 * - no service specified: dump all the services
9011 * - a flattened component name that matched an existing service was specified as the
9012 * first arg: dump that one service
9013 * - the first arg isn't the flattened component name of an existing service:
9014 * dump all services whose component contains the first arg as a substring
9015 */
9016 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9017 String[] newArgs;
9018 String componentNameString;
9019 ServiceRecord r;
9020 if (args.length == 1) {
9021 componentNameString = null;
9022 newArgs = EMPTY_STRING_ARRAY;
9023 r = null;
9024 } else {
9025 componentNameString = args[1];
9026 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9027 r = componentName != null ? mServices.get(componentName) : null;
9028 newArgs = new String[args.length - 2];
9029 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9030 }
9031
9032 if (r != null) {
9033 dumpService(fd, pw, r, newArgs);
9034 } else {
9035 for (ServiceRecord r1 : mServices.values()) {
9036 if (componentNameString == null
9037 || r1.name.flattenToString().contains(componentNameString)) {
9038 dumpService(fd, pw, r1, newArgs);
9039 }
9040 }
9041 }
9042 }
9043
9044 /**
9045 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9046 * there is a thread associated with the service.
9047 */
9048 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9049 pw.println(" Service " + r.name.flattenToString());
9050 if (r.app != null && r.app.thread != null) {
9051 try {
9052 // flush anything that is already in the PrintWriter since the thread is going
9053 // to write to the file descriptor directly
9054 pw.flush();
9055 r.app.thread.dumpService(fd, r, args);
9056 pw.print("\n");
9057 } catch (RemoteException e) {
9058 pw.println("got a RemoteException while dumping the service");
9059 }
9060 }
9061 }
9062
9063 void dumpBroadcasts(PrintWriter pw) {
9064 synchronized (this) {
9065 if (checkCallingPermission(android.Manifest.permission.DUMP)
9066 != PackageManager.PERMISSION_GRANTED) {
9067 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9068 + Binder.getCallingPid()
9069 + ", uid=" + Binder.getCallingUid()
9070 + " without permission "
9071 + android.Manifest.permission.DUMP);
9072 return;
9073 }
9074 pw.println("Broadcasts in Current Activity Manager State:");
9075
9076 if (mRegisteredReceivers.size() > 0) {
9077 pw.println(" ");
9078 pw.println(" Registered Receivers:");
9079 Iterator it = mRegisteredReceivers.values().iterator();
9080 while (it.hasNext()) {
9081 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009082 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009083 r.dump(pw, " ");
9084 }
9085 }
9086
9087 pw.println(" ");
9088 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009089 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009090
9091 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9092 || mPendingBroadcast != null) {
9093 if (mParallelBroadcasts.size() > 0) {
9094 pw.println(" ");
9095 pw.println(" Active broadcasts:");
9096 }
9097 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9098 pw.println(" Broadcast #" + i + ":");
9099 mParallelBroadcasts.get(i).dump(pw, " ");
9100 }
9101 if (mOrderedBroadcasts.size() > 0) {
9102 pw.println(" ");
9103 pw.println(" Active serialized broadcasts:");
9104 }
9105 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9106 pw.println(" Serialized Broadcast #" + i + ":");
9107 mOrderedBroadcasts.get(i).dump(pw, " ");
9108 }
9109 pw.println(" ");
9110 pw.println(" Pending broadcast:");
9111 if (mPendingBroadcast != null) {
9112 mPendingBroadcast.dump(pw, " ");
9113 } else {
9114 pw.println(" (null)");
9115 }
9116 }
9117
9118 pw.println(" ");
9119 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9120 if (mStickyBroadcasts != null) {
9121 pw.println(" ");
9122 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009123 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009124 for (Map.Entry<String, ArrayList<Intent>> ent
9125 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009126 pw.print(" * Sticky action "); pw.print(ent.getKey());
9127 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009128 ArrayList<Intent> intents = ent.getValue();
9129 final int N = intents.size();
9130 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009131 sb.setLength(0);
9132 sb.append(" Intent: ");
9133 intents.get(i).toShortString(sb, true, false);
9134 pw.println(sb.toString());
9135 Bundle bundle = intents.get(i).getExtras();
9136 if (bundle != null) {
9137 pw.print(" ");
9138 pw.println(bundle.toString());
9139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009140 }
9141 }
9142 }
9143
9144 pw.println(" ");
9145 pw.println(" mHandler:");
9146 mHandler.dump(new PrintWriterPrinter(pw), " ");
9147 }
9148 }
9149
9150 void dumpServices(PrintWriter pw) {
9151 synchronized (this) {
9152 if (checkCallingPermission(android.Manifest.permission.DUMP)
9153 != PackageManager.PERMISSION_GRANTED) {
9154 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9155 + Binder.getCallingPid()
9156 + ", uid=" + Binder.getCallingUid()
9157 + " without permission "
9158 + android.Manifest.permission.DUMP);
9159 return;
9160 }
9161 pw.println("Services in Current Activity Manager State:");
9162
9163 boolean needSep = false;
9164
9165 if (mServices.size() > 0) {
9166 pw.println(" Active services:");
9167 Iterator<ServiceRecord> it = mServices.values().iterator();
9168 while (it.hasNext()) {
9169 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009170 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009171 r.dump(pw, " ");
9172 }
9173 needSep = true;
9174 }
9175
9176 if (mPendingServices.size() > 0) {
9177 if (needSep) pw.println(" ");
9178 pw.println(" Pending services:");
9179 for (int i=0; i<mPendingServices.size(); i++) {
9180 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009181 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009182 r.dump(pw, " ");
9183 }
9184 needSep = true;
9185 }
9186
9187 if (mRestartingServices.size() > 0) {
9188 if (needSep) pw.println(" ");
9189 pw.println(" Restarting services:");
9190 for (int i=0; i<mRestartingServices.size(); i++) {
9191 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009192 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009193 r.dump(pw, " ");
9194 }
9195 needSep = true;
9196 }
9197
9198 if (mStoppingServices.size() > 0) {
9199 if (needSep) pw.println(" ");
9200 pw.println(" Stopping services:");
9201 for (int i=0; i<mStoppingServices.size(); i++) {
9202 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009203 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009204 r.dump(pw, " ");
9205 }
9206 needSep = true;
9207 }
9208
9209 if (mServiceConnections.size() > 0) {
9210 if (needSep) pw.println(" ");
9211 pw.println(" Connection bindings to services:");
9212 Iterator<ConnectionRecord> it
9213 = mServiceConnections.values().iterator();
9214 while (it.hasNext()) {
9215 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009216 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009217 r.dump(pw, " ");
9218 }
9219 }
9220 }
9221 }
9222
9223 void dumpProviders(PrintWriter pw) {
9224 synchronized (this) {
9225 if (checkCallingPermission(android.Manifest.permission.DUMP)
9226 != PackageManager.PERMISSION_GRANTED) {
9227 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9228 + Binder.getCallingPid()
9229 + ", uid=" + Binder.getCallingUid()
9230 + " without permission "
9231 + android.Manifest.permission.DUMP);
9232 return;
9233 }
9234
9235 pw.println("Content Providers in Current Activity Manager State:");
9236
9237 boolean needSep = false;
9238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009239 if (mProvidersByClass.size() > 0) {
9240 if (needSep) pw.println(" ");
9241 pw.println(" Published content providers (by class):");
9242 Iterator it = mProvidersByClass.entrySet().iterator();
9243 while (it.hasNext()) {
9244 Map.Entry e = (Map.Entry)it.next();
9245 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009246 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009247 r.dump(pw, " ");
9248 }
9249 needSep = true;
9250 }
9251
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009252 if (mProvidersByName.size() > 0) {
9253 pw.println(" ");
9254 pw.println(" Authority to provider mappings:");
9255 Iterator it = mProvidersByName.entrySet().iterator();
9256 while (it.hasNext()) {
9257 Map.Entry e = (Map.Entry)it.next();
9258 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9259 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9260 pw.println(r);
9261 }
9262 needSep = true;
9263 }
9264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009265 if (mLaunchingProviders.size() > 0) {
9266 if (needSep) pw.println(" ");
9267 pw.println(" Launching content providers:");
9268 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009269 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9270 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009271 }
9272 needSep = true;
9273 }
9274
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009275 if (mGrantedUriPermissions.size() > 0) {
9276 pw.println();
9277 pw.println("Granted Uri Permissions:");
9278 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9279 int uid = mGrantedUriPermissions.keyAt(i);
9280 HashMap<Uri, UriPermission> perms
9281 = mGrantedUriPermissions.valueAt(i);
9282 pw.print(" * UID "); pw.print(uid);
9283 pw.println(" holds:");
9284 for (UriPermission perm : perms.values()) {
9285 pw.print(" "); pw.println(perm);
9286 perm.dump(pw, " ");
9287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009288 }
9289 }
9290 }
9291 }
9292
9293 void dumpSenders(PrintWriter pw) {
9294 synchronized (this) {
9295 if (checkCallingPermission(android.Manifest.permission.DUMP)
9296 != PackageManager.PERMISSION_GRANTED) {
9297 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9298 + Binder.getCallingPid()
9299 + ", uid=" + Binder.getCallingUid()
9300 + " without permission "
9301 + android.Manifest.permission.DUMP);
9302 return;
9303 }
9304
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009305 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009306
9307 if (this.mIntentSenderRecords.size() > 0) {
9308 Iterator<WeakReference<PendingIntentRecord>> it
9309 = mIntentSenderRecords.values().iterator();
9310 while (it.hasNext()) {
9311 WeakReference<PendingIntentRecord> ref = it.next();
9312 PendingIntentRecord rec = ref != null ? ref.get(): null;
9313 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009314 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009315 rec.dump(pw, " ");
9316 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009317 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009318 }
9319 }
9320 }
9321 }
9322 }
9323
9324 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009325 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009326 TaskRecord lastTask = null;
9327 for (int i=list.size()-1; i>=0; i--) {
9328 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009329 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009330 if (lastTask != r.task) {
9331 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009332 pw.print(prefix);
9333 pw.print(full ? "* " : " ");
9334 pw.println(lastTask);
9335 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009336 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009337 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009338 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009339 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9340 pw.print(" #"); pw.print(i); pw.print(": ");
9341 pw.println(r);
9342 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009343 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009345 }
9346 }
9347
9348 private static final int dumpProcessList(PrintWriter pw, List list,
9349 String prefix, String normalLabel, String persistentLabel,
9350 boolean inclOomAdj) {
9351 int numPers = 0;
9352 for (int i=list.size()-1; i>=0; i--) {
9353 ProcessRecord r = (ProcessRecord)list.get(i);
9354 if (false) {
9355 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9356 + " #" + i + ":");
9357 r.dump(pw, prefix + " ");
9358 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009359 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009360 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009361 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9362 if (r.adjSource != null || r.adjTarget != null) {
9363 pw.println(prefix + " " + r.adjTarget
9364 + " used by " + r.adjSource);
9365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009366 } else {
9367 pw.println(String.format("%s%s #%2d: %s",
9368 prefix, (r.persistent ? persistentLabel : normalLabel),
9369 i, r.toString()));
9370 }
9371 if (r.persistent) {
9372 numPers++;
9373 }
9374 }
9375 return numPers;
9376 }
9377
9378 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9379 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009380 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009381 long uptime = SystemClock.uptimeMillis();
9382 long realtime = SystemClock.elapsedRealtime();
9383
9384 if (isCheckinRequest) {
9385 // short checkin version
9386 pw.println(uptime + "," + realtime);
9387 pw.flush();
9388 } else {
9389 pw.println("Applications Memory Usage (kB):");
9390 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9391 }
9392 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9393 ProcessRecord r = (ProcessRecord)list.get(i);
9394 if (r.thread != null) {
9395 if (!isCheckinRequest) {
9396 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9397 pw.flush();
9398 }
9399 try {
9400 r.thread.asBinder().dump(fd, args);
9401 } catch (RemoteException e) {
9402 if (!isCheckinRequest) {
9403 pw.println("Got RemoteException!");
9404 pw.flush();
9405 }
9406 }
9407 }
9408 }
9409 }
9410
9411 /**
9412 * Searches array of arguments for the specified string
9413 * @param args array of argument strings
9414 * @param value value to search for
9415 * @return true if the value is contained in the array
9416 */
9417 private static boolean scanArgs(String[] args, String value) {
9418 if (args != null) {
9419 for (String arg : args) {
9420 if (value.equals(arg)) {
9421 return true;
9422 }
9423 }
9424 }
9425 return false;
9426 }
9427
Dianne Hackborn75b03852009-06-12 15:43:26 -07009428 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009429 int count = mHistory.size();
9430
9431 // convert the token to an entry in the history.
9432 HistoryRecord r = null;
9433 int index = -1;
9434 for (int i=count-1; i>=0; i--) {
9435 Object o = mHistory.get(i);
9436 if (o == token) {
9437 r = (HistoryRecord)o;
9438 index = i;
9439 break;
9440 }
9441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009442
9443 return index;
9444 }
9445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446 private final void killServicesLocked(ProcessRecord app,
9447 boolean allowRestart) {
9448 // Report disconnected services.
9449 if (false) {
9450 // XXX we are letting the client link to the service for
9451 // death notifications.
9452 if (app.services.size() > 0) {
9453 Iterator it = app.services.iterator();
9454 while (it.hasNext()) {
9455 ServiceRecord r = (ServiceRecord)it.next();
9456 if (r.connections.size() > 0) {
9457 Iterator<ConnectionRecord> jt
9458 = r.connections.values().iterator();
9459 while (jt.hasNext()) {
9460 ConnectionRecord c = jt.next();
9461 if (c.binding.client != app) {
9462 try {
9463 //c.conn.connected(r.className, null);
9464 } catch (Exception e) {
9465 // todo: this should be asynchronous!
9466 Log.w(TAG, "Exception thrown disconnected servce "
9467 + r.shortName
9468 + " from app " + app.processName, e);
9469 }
9470 }
9471 }
9472 }
9473 }
9474 }
9475 }
9476
9477 // Clean up any connections this application has to other services.
9478 if (app.connections.size() > 0) {
9479 Iterator<ConnectionRecord> it = app.connections.iterator();
9480 while (it.hasNext()) {
9481 ConnectionRecord r = it.next();
9482 removeConnectionLocked(r, app, null);
9483 }
9484 }
9485 app.connections.clear();
9486
9487 if (app.services.size() != 0) {
9488 // Any services running in the application need to be placed
9489 // back in the pending list.
9490 Iterator it = app.services.iterator();
9491 while (it.hasNext()) {
9492 ServiceRecord sr = (ServiceRecord)it.next();
9493 synchronized (sr.stats.getBatteryStats()) {
9494 sr.stats.stopLaunchedLocked();
9495 }
9496 sr.app = null;
9497 sr.executeNesting = 0;
9498 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009499
9500 boolean hasClients = sr.bindings.size() > 0;
9501 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009502 Iterator<IntentBindRecord> bindings
9503 = sr.bindings.values().iterator();
9504 while (bindings.hasNext()) {
9505 IntentBindRecord b = bindings.next();
9506 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9507 + ": shouldUnbind=" + b.hasBound);
9508 b.binder = null;
9509 b.requested = b.received = b.hasBound = false;
9510 }
9511 }
9512
9513 if (sr.crashCount >= 2) {
9514 Log.w(TAG, "Service crashed " + sr.crashCount
9515 + " times, stopping: " + sr);
9516 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9517 sr.crashCount, sr.shortName, app.pid);
9518 bringDownServiceLocked(sr, true);
9519 } else if (!allowRestart) {
9520 bringDownServiceLocked(sr, true);
9521 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009522 boolean canceled = scheduleServiceRestartLocked(sr, true);
9523
9524 // Should the service remain running? Note that in the
9525 // extreme case of so many attempts to deliver a command
9526 // that it failed, that we also will stop it here.
9527 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9528 if (sr.pendingStarts.size() == 0) {
9529 sr.startRequested = false;
9530 if (!hasClients) {
9531 // Whoops, no reason to restart!
9532 bringDownServiceLocked(sr, true);
9533 }
9534 }
9535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009536 }
9537 }
9538
9539 if (!allowRestart) {
9540 app.services.clear();
9541 }
9542 }
9543
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009544 // Make sure we have no more records on the stopping list.
9545 int i = mStoppingServices.size();
9546 while (i > 0) {
9547 i--;
9548 ServiceRecord sr = mStoppingServices.get(i);
9549 if (sr.app == app) {
9550 mStoppingServices.remove(i);
9551 }
9552 }
9553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009554 app.executingServices.clear();
9555 }
9556
9557 private final void removeDyingProviderLocked(ProcessRecord proc,
9558 ContentProviderRecord cpr) {
9559 synchronized (cpr) {
9560 cpr.launchingApp = null;
9561 cpr.notifyAll();
9562 }
9563
9564 mProvidersByClass.remove(cpr.info.name);
9565 String names[] = cpr.info.authority.split(";");
9566 for (int j = 0; j < names.length; j++) {
9567 mProvidersByName.remove(names[j]);
9568 }
9569
9570 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9571 while (cit.hasNext()) {
9572 ProcessRecord capp = cit.next();
9573 if (!capp.persistent && capp.thread != null
9574 && capp.pid != 0
9575 && capp.pid != MY_PID) {
9576 Log.i(TAG, "Killing app " + capp.processName
9577 + " (pid " + capp.pid
9578 + ") because provider " + cpr.info.name
9579 + " is in dying process " + proc.processName);
9580 Process.killProcess(capp.pid);
9581 }
9582 }
9583
9584 mLaunchingProviders.remove(cpr);
9585 }
9586
9587 /**
9588 * Main code for cleaning up a process when it has gone away. This is
9589 * called both as a result of the process dying, or directly when stopping
9590 * a process when running in single process mode.
9591 */
9592 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9593 boolean restarting, int index) {
9594 if (index >= 0) {
9595 mLRUProcesses.remove(index);
9596 }
9597
9598 // Dismiss any open dialogs.
9599 if (app.crashDialog != null) {
9600 app.crashDialog.dismiss();
9601 app.crashDialog = null;
9602 }
9603 if (app.anrDialog != null) {
9604 app.anrDialog.dismiss();
9605 app.anrDialog = null;
9606 }
9607 if (app.waitDialog != null) {
9608 app.waitDialog.dismiss();
9609 app.waitDialog = null;
9610 }
9611
9612 app.crashing = false;
9613 app.notResponding = false;
9614
9615 app.resetPackageList();
9616 app.thread = null;
9617 app.forcingToForeground = null;
9618 app.foregroundServices = false;
9619
9620 killServicesLocked(app, true);
9621
9622 boolean restart = false;
9623
9624 int NL = mLaunchingProviders.size();
9625
9626 // Remove published content providers.
9627 if (!app.pubProviders.isEmpty()) {
9628 Iterator it = app.pubProviders.values().iterator();
9629 while (it.hasNext()) {
9630 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9631 cpr.provider = null;
9632 cpr.app = null;
9633
9634 // See if someone is waiting for this provider... in which
9635 // case we don't remove it, but just let it restart.
9636 int i = 0;
9637 if (!app.bad) {
9638 for (; i<NL; i++) {
9639 if (mLaunchingProviders.get(i) == cpr) {
9640 restart = true;
9641 break;
9642 }
9643 }
9644 } else {
9645 i = NL;
9646 }
9647
9648 if (i >= NL) {
9649 removeDyingProviderLocked(app, cpr);
9650 NL = mLaunchingProviders.size();
9651 }
9652 }
9653 app.pubProviders.clear();
9654 }
9655
9656 // Look through the content providers we are waiting to have launched,
9657 // and if any run in this process then either schedule a restart of
9658 // the process or kill the client waiting for it if this process has
9659 // gone bad.
9660 for (int i=0; i<NL; i++) {
9661 ContentProviderRecord cpr = (ContentProviderRecord)
9662 mLaunchingProviders.get(i);
9663 if (cpr.launchingApp == app) {
9664 if (!app.bad) {
9665 restart = true;
9666 } else {
9667 removeDyingProviderLocked(app, cpr);
9668 NL = mLaunchingProviders.size();
9669 }
9670 }
9671 }
9672
9673 // Unregister from connected content providers.
9674 if (!app.conProviders.isEmpty()) {
9675 Iterator it = app.conProviders.iterator();
9676 while (it.hasNext()) {
9677 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9678 cpr.clients.remove(app);
9679 }
9680 app.conProviders.clear();
9681 }
9682
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009683 // At this point there may be remaining entries in mLaunchingProviders
9684 // where we were the only one waiting, so they are no longer of use.
9685 // Look for these and clean up if found.
9686 // XXX Commented out for now. Trying to figure out a way to reproduce
9687 // the actual situation to identify what is actually going on.
9688 if (false) {
9689 for (int i=0; i<NL; i++) {
9690 ContentProviderRecord cpr = (ContentProviderRecord)
9691 mLaunchingProviders.get(i);
9692 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9693 synchronized (cpr) {
9694 cpr.launchingApp = null;
9695 cpr.notifyAll();
9696 }
9697 }
9698 }
9699 }
9700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009701 skipCurrentReceiverLocked(app);
9702
9703 // Unregister any receivers.
9704 if (app.receivers.size() > 0) {
9705 Iterator<ReceiverList> it = app.receivers.iterator();
9706 while (it.hasNext()) {
9707 removeReceiverLocked(it.next());
9708 }
9709 app.receivers.clear();
9710 }
9711
Christopher Tate181fafa2009-05-14 11:12:14 -07009712 // If the app is undergoing backup, tell the backup manager about it
9713 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9714 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9715 try {
9716 IBackupManager bm = IBackupManager.Stub.asInterface(
9717 ServiceManager.getService(Context.BACKUP_SERVICE));
9718 bm.agentDisconnected(app.info.packageName);
9719 } catch (RemoteException e) {
9720 // can't happen; backup manager is local
9721 }
9722 }
9723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009724 // If the caller is restarting this app, then leave it in its
9725 // current lists and let the caller take care of it.
9726 if (restarting) {
9727 return;
9728 }
9729
9730 if (!app.persistent) {
9731 if (DEBUG_PROCESSES) Log.v(TAG,
9732 "Removing non-persistent process during cleanup: " + app);
9733 mProcessNames.remove(app.processName, app.info.uid);
9734 } else if (!app.removed) {
9735 // This app is persistent, so we need to keep its record around.
9736 // If it is not already on the pending app list, add it there
9737 // and start a new process for it.
9738 app.thread = null;
9739 app.forcingToForeground = null;
9740 app.foregroundServices = false;
9741 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9742 mPersistentStartingProcesses.add(app);
9743 restart = true;
9744 }
9745 }
9746 mProcessesOnHold.remove(app);
9747
The Android Open Source Project4df24232009-03-05 14:34:35 -08009748 if (app == mHomeProcess) {
9749 mHomeProcess = null;
9750 }
9751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009752 if (restart) {
9753 // We have components that still need to be running in the
9754 // process, so re-launch it.
9755 mProcessNames.put(app.processName, app.info.uid, app);
9756 startProcessLocked(app, "restart", app.processName);
9757 } else if (app.pid > 0 && app.pid != MY_PID) {
9758 // Goodbye!
9759 synchronized (mPidsSelfLocked) {
9760 mPidsSelfLocked.remove(app.pid);
9761 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9762 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009763 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009764 }
9765 }
9766
9767 // =========================================================
9768 // SERVICES
9769 // =========================================================
9770
9771 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9772 ActivityManager.RunningServiceInfo info =
9773 new ActivityManager.RunningServiceInfo();
9774 info.service = r.name;
9775 if (r.app != null) {
9776 info.pid = r.app.pid;
9777 }
9778 info.process = r.processName;
9779 info.foreground = r.isForeground;
9780 info.activeSince = r.createTime;
9781 info.started = r.startRequested;
9782 info.clientCount = r.connections.size();
9783 info.crashCount = r.crashCount;
9784 info.lastActivityTime = r.lastActivity;
9785 return info;
9786 }
9787
9788 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9789 int flags) {
9790 synchronized (this) {
9791 ArrayList<ActivityManager.RunningServiceInfo> res
9792 = new ArrayList<ActivityManager.RunningServiceInfo>();
9793
9794 if (mServices.size() > 0) {
9795 Iterator<ServiceRecord> it = mServices.values().iterator();
9796 while (it.hasNext() && res.size() < maxNum) {
9797 res.add(makeRunningServiceInfoLocked(it.next()));
9798 }
9799 }
9800
9801 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9802 ServiceRecord r = mRestartingServices.get(i);
9803 ActivityManager.RunningServiceInfo info =
9804 makeRunningServiceInfoLocked(r);
9805 info.restarting = r.nextRestartTime;
9806 res.add(info);
9807 }
9808
9809 return res;
9810 }
9811 }
9812
9813 private final ServiceRecord findServiceLocked(ComponentName name,
9814 IBinder token) {
9815 ServiceRecord r = mServices.get(name);
9816 return r == token ? r : null;
9817 }
9818
9819 private final class ServiceLookupResult {
9820 final ServiceRecord record;
9821 final String permission;
9822
9823 ServiceLookupResult(ServiceRecord _record, String _permission) {
9824 record = _record;
9825 permission = _permission;
9826 }
9827 };
9828
9829 private ServiceLookupResult findServiceLocked(Intent service,
9830 String resolvedType) {
9831 ServiceRecord r = null;
9832 if (service.getComponent() != null) {
9833 r = mServices.get(service.getComponent());
9834 }
9835 if (r == null) {
9836 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9837 r = mServicesByIntent.get(filter);
9838 }
9839
9840 if (r == null) {
9841 try {
9842 ResolveInfo rInfo =
9843 ActivityThread.getPackageManager().resolveService(
9844 service, resolvedType, 0);
9845 ServiceInfo sInfo =
9846 rInfo != null ? rInfo.serviceInfo : null;
9847 if (sInfo == null) {
9848 return null;
9849 }
9850
9851 ComponentName name = new ComponentName(
9852 sInfo.applicationInfo.packageName, sInfo.name);
9853 r = mServices.get(name);
9854 } catch (RemoteException ex) {
9855 // pm is in same process, this will never happen.
9856 }
9857 }
9858 if (r != null) {
9859 int callingPid = Binder.getCallingPid();
9860 int callingUid = Binder.getCallingUid();
9861 if (checkComponentPermission(r.permission,
9862 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9863 != PackageManager.PERMISSION_GRANTED) {
9864 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9865 + " from pid=" + callingPid
9866 + ", uid=" + callingUid
9867 + " requires " + r.permission);
9868 return new ServiceLookupResult(null, r.permission);
9869 }
9870 return new ServiceLookupResult(r, null);
9871 }
9872 return null;
9873 }
9874
9875 private class ServiceRestarter implements Runnable {
9876 private ServiceRecord mService;
9877
9878 void setService(ServiceRecord service) {
9879 mService = service;
9880 }
9881
9882 public void run() {
9883 synchronized(ActivityManagerService.this) {
9884 performServiceRestartLocked(mService);
9885 }
9886 }
9887 }
9888
9889 private ServiceLookupResult retrieveServiceLocked(Intent service,
9890 String resolvedType, int callingPid, int callingUid) {
9891 ServiceRecord r = null;
9892 if (service.getComponent() != null) {
9893 r = mServices.get(service.getComponent());
9894 }
9895 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9896 r = mServicesByIntent.get(filter);
9897 if (r == null) {
9898 try {
9899 ResolveInfo rInfo =
9900 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009901 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009902 ServiceInfo sInfo =
9903 rInfo != null ? rInfo.serviceInfo : null;
9904 if (sInfo == null) {
9905 Log.w(TAG, "Unable to start service " + service +
9906 ": not found");
9907 return null;
9908 }
9909
9910 ComponentName name = new ComponentName(
9911 sInfo.applicationInfo.packageName, sInfo.name);
9912 r = mServices.get(name);
9913 if (r == null) {
9914 filter = new Intent.FilterComparison(service.cloneFilter());
9915 ServiceRestarter res = new ServiceRestarter();
9916 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9917 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9918 synchronized (stats) {
9919 ss = stats.getServiceStatsLocked(
9920 sInfo.applicationInfo.uid, sInfo.packageName,
9921 sInfo.name);
9922 }
9923 r = new ServiceRecord(ss, name, filter, sInfo, res);
9924 res.setService(r);
9925 mServices.put(name, r);
9926 mServicesByIntent.put(filter, r);
9927
9928 // Make sure this component isn't in the pending list.
9929 int N = mPendingServices.size();
9930 for (int i=0; i<N; i++) {
9931 ServiceRecord pr = mPendingServices.get(i);
9932 if (pr.name.equals(name)) {
9933 mPendingServices.remove(i);
9934 i--;
9935 N--;
9936 }
9937 }
9938 }
9939 } catch (RemoteException ex) {
9940 // pm is in same process, this will never happen.
9941 }
9942 }
9943 if (r != null) {
9944 if (checkComponentPermission(r.permission,
9945 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9946 != PackageManager.PERMISSION_GRANTED) {
9947 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9948 + " from pid=" + Binder.getCallingPid()
9949 + ", uid=" + Binder.getCallingUid()
9950 + " requires " + r.permission);
9951 return new ServiceLookupResult(null, r.permission);
9952 }
9953 return new ServiceLookupResult(r, null);
9954 }
9955 return null;
9956 }
9957
9958 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9959 long now = SystemClock.uptimeMillis();
9960 if (r.executeNesting == 0 && r.app != null) {
9961 if (r.app.executingServices.size() == 0) {
9962 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9963 msg.obj = r.app;
9964 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9965 }
9966 r.app.executingServices.add(r);
9967 }
9968 r.executeNesting++;
9969 r.executingStart = now;
9970 }
9971
9972 private final void sendServiceArgsLocked(ServiceRecord r,
9973 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009974 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009975 if (N == 0) {
9976 return;
9977 }
9978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009979 int i = 0;
9980 while (i < N) {
9981 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009982 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009983 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009984 + r.name + " " + r.intent + " args=" + si.intent);
9985 if (si.intent == null && N > 0) {
9986 // If somehow we got a dummy start at the front, then
9987 // just drop it here.
9988 i++;
9989 continue;
9990 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009991 bumpServiceExecutingLocked(r);
9992 if (!oomAdjusted) {
9993 oomAdjusted = true;
9994 updateOomAdjLocked(r.app);
9995 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009996 int flags = 0;
9997 if (si.deliveryCount > 0) {
9998 flags |= Service.START_FLAG_RETRY;
9999 }
10000 if (si.doneExecutingCount > 0) {
10001 flags |= Service.START_FLAG_REDELIVERY;
10002 }
10003 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10004 si.deliveredTime = SystemClock.uptimeMillis();
10005 r.deliveredStarts.add(si);
10006 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010007 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010008 } catch (RemoteException e) {
10009 // Remote process gone... we'll let the normal cleanup take
10010 // care of this.
10011 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010012 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010013 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010014 break;
10015 }
10016 }
10017 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010018 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010019 } else {
10020 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010021 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010022 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010023 }
10024 }
10025 }
10026
10027 private final boolean requestServiceBindingLocked(ServiceRecord r,
10028 IntentBindRecord i, boolean rebind) {
10029 if (r.app == null || r.app.thread == null) {
10030 // If service is not currently running, can't yet bind.
10031 return false;
10032 }
10033 if ((!i.requested || rebind) && i.apps.size() > 0) {
10034 try {
10035 bumpServiceExecutingLocked(r);
10036 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10037 + ": shouldUnbind=" + i.hasBound);
10038 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10039 if (!rebind) {
10040 i.requested = true;
10041 }
10042 i.hasBound = true;
10043 i.doRebind = false;
10044 } catch (RemoteException e) {
10045 return false;
10046 }
10047 }
10048 return true;
10049 }
10050
10051 private final void requestServiceBindingsLocked(ServiceRecord r) {
10052 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10053 while (bindings.hasNext()) {
10054 IntentBindRecord i = bindings.next();
10055 if (!requestServiceBindingLocked(r, i, false)) {
10056 break;
10057 }
10058 }
10059 }
10060
10061 private final void realStartServiceLocked(ServiceRecord r,
10062 ProcessRecord app) throws RemoteException {
10063 if (app.thread == null) {
10064 throw new RemoteException();
10065 }
10066
10067 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010068 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010069
10070 app.services.add(r);
10071 bumpServiceExecutingLocked(r);
10072 updateLRUListLocked(app, true);
10073
10074 boolean created = false;
10075 try {
10076 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10077 + r.name + " " + r.intent);
10078 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10079 System.identityHashCode(r), r.shortName,
10080 r.intent.getIntent().toString(), r.app.pid);
10081 synchronized (r.stats.getBatteryStats()) {
10082 r.stats.startLaunchedLocked();
10083 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010084 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010085 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010086 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010087 created = true;
10088 } finally {
10089 if (!created) {
10090 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010091 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010092 }
10093 }
10094
10095 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010096
10097 // If the service is in the started state, and there are no
10098 // pending arguments, then fake up one so its onStartCommand() will
10099 // be called.
10100 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10101 r.lastStartId++;
10102 if (r.lastStartId < 1) {
10103 r.lastStartId = 1;
10104 }
10105 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10106 }
10107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010108 sendServiceArgsLocked(r, true);
10109 }
10110
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010111 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10112 boolean allowCancel) {
10113 boolean canceled = false;
10114
10115 long minDuration = SERVICE_RESTART_DURATION;
10116 long resetTime = minDuration*2*2*2;
10117
10118 // Any delivered but not yet finished starts should be put back
10119 // on the pending list.
10120 final int N = r.deliveredStarts.size();
10121 if (N > 0) {
10122 for (int i=N-1; i>=0; i--) {
10123 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10124 if (si.intent == null) {
10125 // We'll generate this again if needed.
10126 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10127 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10128 r.pendingStarts.add(0, si);
10129 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10130 dur *= 2;
10131 if (minDuration < dur) minDuration = dur;
10132 if (resetTime < dur) resetTime = dur;
10133 } else {
10134 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10135 + r.name);
10136 canceled = true;
10137 }
10138 }
10139 r.deliveredStarts.clear();
10140 }
10141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010142 r.totalRestartCount++;
10143 if (r.restartDelay == 0) {
10144 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010145 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010146 } else {
10147 // If it has been a "reasonably long time" since the service
10148 // was started, then reset our restart duration back to
10149 // the beginning, so we don't infinitely increase the duration
10150 // on a service that just occasionally gets killed (which is
10151 // a normal case, due to process being killed to reclaim memory).
10152 long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010153 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010154 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010155 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010156 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010157 r.restartDelay *= 4;
10158 if (r.restartDelay < minDuration) {
10159 r.restartDelay = minDuration;
10160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010161 }
10162 }
10163 if (!mRestartingServices.contains(r)) {
10164 mRestartingServices.add(r);
10165 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010166 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010168 mHandler.removeCallbacks(r.restarter);
10169 mHandler.postDelayed(r.restarter, r.restartDelay);
10170 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10171 Log.w(TAG, "Scheduling restart of crashed service "
10172 + r.shortName + " in " + r.restartDelay + "ms");
10173 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10174 r.shortName, r.restartDelay);
10175
10176 Message msg = Message.obtain();
10177 msg.what = SERVICE_ERROR_MSG;
10178 msg.obj = r;
10179 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010180
10181 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010182 }
10183
10184 final void performServiceRestartLocked(ServiceRecord r) {
10185 if (!mRestartingServices.contains(r)) {
10186 return;
10187 }
10188 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10189 }
10190
10191 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10192 if (r.restartDelay == 0) {
10193 return false;
10194 }
10195 r.resetRestartCounter();
10196 mRestartingServices.remove(r);
10197 mHandler.removeCallbacks(r.restarter);
10198 return true;
10199 }
10200
10201 private final boolean bringUpServiceLocked(ServiceRecord r,
10202 int intentFlags, boolean whileRestarting) {
10203 //Log.i(TAG, "Bring up service:");
10204 //r.dump(" ");
10205
10206 if (r.app != null) {
10207 sendServiceArgsLocked(r, false);
10208 return true;
10209 }
10210
10211 if (!whileRestarting && r.restartDelay > 0) {
10212 // If waiting for a restart, then do nothing.
10213 return true;
10214 }
10215
10216 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10217 + " " + r.intent);
10218
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010219 // We are now bringing the service up, so no longer in the
10220 // restarting state.
10221 mRestartingServices.remove(r);
10222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010223 final String appName = r.processName;
10224 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10225 if (app != null && app.thread != null) {
10226 try {
10227 realStartServiceLocked(r, app);
10228 return true;
10229 } catch (RemoteException e) {
10230 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10231 }
10232
10233 // If a dead object exception was thrown -- fall through to
10234 // restart the application.
10235 }
10236
10237 if (!mPendingServices.contains(r)) {
10238 // Not running -- get it started, and enqueue this service record
10239 // to be executed when the app comes up.
10240 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010241 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010242 Log.w(TAG, "Unable to launch app "
10243 + r.appInfo.packageName + "/"
10244 + r.appInfo.uid + " for service "
10245 + r.intent.getIntent() + ": process is bad");
10246 bringDownServiceLocked(r, true);
10247 return false;
10248 }
10249 mPendingServices.add(r);
10250 }
10251 return true;
10252 }
10253
10254 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10255 //Log.i(TAG, "Bring down service:");
10256 //r.dump(" ");
10257
10258 // Does it still need to run?
10259 if (!force && r.startRequested) {
10260 return;
10261 }
10262 if (r.connections.size() > 0) {
10263 if (!force) {
10264 // XXX should probably keep a count of the number of auto-create
10265 // connections directly in the service.
10266 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10267 while (it.hasNext()) {
10268 ConnectionRecord cr = it.next();
10269 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10270 return;
10271 }
10272 }
10273 }
10274
10275 // Report to all of the connections that the service is no longer
10276 // available.
10277 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10278 while (it.hasNext()) {
10279 ConnectionRecord c = it.next();
10280 try {
10281 // todo: shouldn't be a synchronous call!
10282 c.conn.connected(r.name, null);
10283 } catch (Exception e) {
10284 Log.w(TAG, "Failure disconnecting service " + r.name +
10285 " to connection " + c.conn.asBinder() +
10286 " (in " + c.binding.client.processName + ")", e);
10287 }
10288 }
10289 }
10290
10291 // Tell the service that it has been unbound.
10292 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10293 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10294 while (it.hasNext()) {
10295 IntentBindRecord ibr = it.next();
10296 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10297 + ": hasBound=" + ibr.hasBound);
10298 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10299 try {
10300 bumpServiceExecutingLocked(r);
10301 updateOomAdjLocked(r.app);
10302 ibr.hasBound = false;
10303 r.app.thread.scheduleUnbindService(r,
10304 ibr.intent.getIntent());
10305 } catch (Exception e) {
10306 Log.w(TAG, "Exception when unbinding service "
10307 + r.shortName, e);
10308 serviceDoneExecutingLocked(r, true);
10309 }
10310 }
10311 }
10312 }
10313
10314 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10315 + " " + r.intent);
10316 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10317 System.identityHashCode(r), r.shortName,
10318 (r.app != null) ? r.app.pid : -1);
10319
10320 mServices.remove(r.name);
10321 mServicesByIntent.remove(r.intent);
10322 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10323 r.totalRestartCount = 0;
10324 unscheduleServiceRestartLocked(r);
10325
10326 // Also make sure it is not on the pending list.
10327 int N = mPendingServices.size();
10328 for (int i=0; i<N; i++) {
10329 if (mPendingServices.get(i) == r) {
10330 mPendingServices.remove(i);
10331 if (DEBUG_SERVICE) Log.v(
10332 TAG, "Removed pending service: " + r.shortName);
10333 i--;
10334 N--;
10335 }
10336 }
10337
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010338 r.cancelNotification();
10339 r.isForeground = false;
10340 r.foregroundId = 0;
10341 r.foregroundNoti = null;
10342
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010343 // Clear start entries.
10344 r.deliveredStarts.clear();
10345 r.pendingStarts.clear();
10346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010347 if (r.app != null) {
10348 synchronized (r.stats.getBatteryStats()) {
10349 r.stats.stopLaunchedLocked();
10350 }
10351 r.app.services.remove(r);
10352 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010353 try {
10354 Log.i(TAG, "Stopping service: " + r.shortName);
10355 bumpServiceExecutingLocked(r);
10356 mStoppingServices.add(r);
10357 updateOomAdjLocked(r.app);
10358 r.app.thread.scheduleStopService(r);
10359 } catch (Exception e) {
10360 Log.w(TAG, "Exception when stopping service "
10361 + r.shortName, e);
10362 serviceDoneExecutingLocked(r, true);
10363 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010364 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010365 } else {
10366 if (DEBUG_SERVICE) Log.v(
10367 TAG, "Removed service that has no process: " + r.shortName);
10368 }
10369 } else {
10370 if (DEBUG_SERVICE) Log.v(
10371 TAG, "Removed service that is not running: " + r.shortName);
10372 }
10373 }
10374
10375 ComponentName startServiceLocked(IApplicationThread caller,
10376 Intent service, String resolvedType,
10377 int callingPid, int callingUid) {
10378 synchronized(this) {
10379 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10380 + " type=" + resolvedType + " args=" + service.getExtras());
10381
10382 if (caller != null) {
10383 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10384 if (callerApp == null) {
10385 throw new SecurityException(
10386 "Unable to find app for caller " + caller
10387 + " (pid=" + Binder.getCallingPid()
10388 + ") when starting service " + service);
10389 }
10390 }
10391
10392 ServiceLookupResult res =
10393 retrieveServiceLocked(service, resolvedType,
10394 callingPid, callingUid);
10395 if (res == null) {
10396 return null;
10397 }
10398 if (res.record == null) {
10399 return new ComponentName("!", res.permission != null
10400 ? res.permission : "private to package");
10401 }
10402 ServiceRecord r = res.record;
10403 if (unscheduleServiceRestartLocked(r)) {
10404 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10405 + r.shortName);
10406 }
10407 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010408 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010409 r.lastStartId++;
10410 if (r.lastStartId < 1) {
10411 r.lastStartId = 1;
10412 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010413 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010414 r.lastActivity = SystemClock.uptimeMillis();
10415 synchronized (r.stats.getBatteryStats()) {
10416 r.stats.startRunningLocked();
10417 }
10418 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10419 return new ComponentName("!", "Service process is bad");
10420 }
10421 return r.name;
10422 }
10423 }
10424
10425 public ComponentName startService(IApplicationThread caller, Intent service,
10426 String resolvedType) {
10427 // Refuse possible leaked file descriptors
10428 if (service != null && service.hasFileDescriptors() == true) {
10429 throw new IllegalArgumentException("File descriptors passed in Intent");
10430 }
10431
10432 synchronized(this) {
10433 final int callingPid = Binder.getCallingPid();
10434 final int callingUid = Binder.getCallingUid();
10435 final long origId = Binder.clearCallingIdentity();
10436 ComponentName res = startServiceLocked(caller, service,
10437 resolvedType, callingPid, callingUid);
10438 Binder.restoreCallingIdentity(origId);
10439 return res;
10440 }
10441 }
10442
10443 ComponentName startServiceInPackage(int uid,
10444 Intent service, String resolvedType) {
10445 synchronized(this) {
10446 final long origId = Binder.clearCallingIdentity();
10447 ComponentName res = startServiceLocked(null, service,
10448 resolvedType, -1, uid);
10449 Binder.restoreCallingIdentity(origId);
10450 return res;
10451 }
10452 }
10453
10454 public int stopService(IApplicationThread caller, Intent service,
10455 String resolvedType) {
10456 // Refuse possible leaked file descriptors
10457 if (service != null && service.hasFileDescriptors() == true) {
10458 throw new IllegalArgumentException("File descriptors passed in Intent");
10459 }
10460
10461 synchronized(this) {
10462 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10463 + " type=" + resolvedType);
10464
10465 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10466 if (caller != null && callerApp == null) {
10467 throw new SecurityException(
10468 "Unable to find app for caller " + caller
10469 + " (pid=" + Binder.getCallingPid()
10470 + ") when stopping service " + service);
10471 }
10472
10473 // If this service is active, make sure it is stopped.
10474 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10475 if (r != null) {
10476 if (r.record != null) {
10477 synchronized (r.record.stats.getBatteryStats()) {
10478 r.record.stats.stopRunningLocked();
10479 }
10480 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010481 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010482 final long origId = Binder.clearCallingIdentity();
10483 bringDownServiceLocked(r.record, false);
10484 Binder.restoreCallingIdentity(origId);
10485 return 1;
10486 }
10487 return -1;
10488 }
10489 }
10490
10491 return 0;
10492 }
10493
10494 public IBinder peekService(Intent service, String resolvedType) {
10495 // Refuse possible leaked file descriptors
10496 if (service != null && service.hasFileDescriptors() == true) {
10497 throw new IllegalArgumentException("File descriptors passed in Intent");
10498 }
10499
10500 IBinder ret = null;
10501
10502 synchronized(this) {
10503 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10504
10505 if (r != null) {
10506 // r.record is null if findServiceLocked() failed the caller permission check
10507 if (r.record == null) {
10508 throw new SecurityException(
10509 "Permission Denial: Accessing service " + r.record.name
10510 + " from pid=" + Binder.getCallingPid()
10511 + ", uid=" + Binder.getCallingUid()
10512 + " requires " + r.permission);
10513 }
10514 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10515 if (ib != null) {
10516 ret = ib.binder;
10517 }
10518 }
10519 }
10520
10521 return ret;
10522 }
10523
10524 public boolean stopServiceToken(ComponentName className, IBinder token,
10525 int startId) {
10526 synchronized(this) {
10527 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10528 + " " + token + " startId=" + startId);
10529 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010530 if (r != null) {
10531 if (startId >= 0) {
10532 // Asked to only stop if done with all work. Note that
10533 // to avoid leaks, we will take this as dropping all
10534 // start items up to and including this one.
10535 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10536 if (si != null) {
10537 while (r.deliveredStarts.size() > 0) {
10538 if (r.deliveredStarts.remove(0) == si) {
10539 break;
10540 }
10541 }
10542 }
10543
10544 if (r.lastStartId != startId) {
10545 return false;
10546 }
10547
10548 if (r.deliveredStarts.size() > 0) {
10549 Log.w(TAG, "stopServiceToken startId " + startId
10550 + " is last, but have " + r.deliveredStarts.size()
10551 + " remaining args");
10552 }
10553 }
10554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010555 synchronized (r.stats.getBatteryStats()) {
10556 r.stats.stopRunningLocked();
10557 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010558 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010559 }
10560 final long origId = Binder.clearCallingIdentity();
10561 bringDownServiceLocked(r, false);
10562 Binder.restoreCallingIdentity(origId);
10563 return true;
10564 }
10565 }
10566 return false;
10567 }
10568
10569 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010570 int id, Notification notification, boolean removeNotification) {
10571 final long origId = Binder.clearCallingIdentity();
10572 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010573 synchronized(this) {
10574 ServiceRecord r = findServiceLocked(className, token);
10575 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010576 if (id != 0) {
10577 if (notification == null) {
10578 throw new IllegalArgumentException("null notification");
10579 }
10580 if (r.foregroundId != id) {
10581 r.cancelNotification();
10582 r.foregroundId = id;
10583 }
10584 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10585 r.foregroundNoti = notification;
10586 r.isForeground = true;
10587 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010588 if (r.app != null) {
10589 updateServiceForegroundLocked(r.app, true);
10590 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010591 } else {
10592 if (r.isForeground) {
10593 r.isForeground = false;
10594 if (r.app != null) {
10595 updateServiceForegroundLocked(r.app, true);
10596 }
10597 }
10598 if (removeNotification) {
10599 r.cancelNotification();
10600 r.foregroundId = 0;
10601 r.foregroundNoti = null;
10602 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010603 }
10604 }
10605 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010606 } finally {
10607 Binder.restoreCallingIdentity(origId);
10608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010609 }
10610
10611 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10612 boolean anyForeground = false;
10613 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10614 if (sr.isForeground) {
10615 anyForeground = true;
10616 break;
10617 }
10618 }
10619 if (anyForeground != proc.foregroundServices) {
10620 proc.foregroundServices = anyForeground;
10621 if (oomAdj) {
10622 updateOomAdjLocked();
10623 }
10624 }
10625 }
10626
10627 public int bindService(IApplicationThread caller, IBinder token,
10628 Intent service, String resolvedType,
10629 IServiceConnection connection, int flags) {
10630 // Refuse possible leaked file descriptors
10631 if (service != null && service.hasFileDescriptors() == true) {
10632 throw new IllegalArgumentException("File descriptors passed in Intent");
10633 }
10634
10635 synchronized(this) {
10636 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10637 + " type=" + resolvedType + " conn=" + connection.asBinder()
10638 + " flags=0x" + Integer.toHexString(flags));
10639 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10640 if (callerApp == null) {
10641 throw new SecurityException(
10642 "Unable to find app for caller " + caller
10643 + " (pid=" + Binder.getCallingPid()
10644 + ") when binding service " + service);
10645 }
10646
10647 HistoryRecord activity = null;
10648 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010649 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010650 if (aindex < 0) {
10651 Log.w(TAG, "Binding with unknown activity: " + token);
10652 return 0;
10653 }
10654 activity = (HistoryRecord)mHistory.get(aindex);
10655 }
10656
10657 ServiceLookupResult res =
10658 retrieveServiceLocked(service, resolvedType,
10659 Binder.getCallingPid(), Binder.getCallingUid());
10660 if (res == null) {
10661 return 0;
10662 }
10663 if (res.record == null) {
10664 return -1;
10665 }
10666 ServiceRecord s = res.record;
10667
10668 final long origId = Binder.clearCallingIdentity();
10669
10670 if (unscheduleServiceRestartLocked(s)) {
10671 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10672 + s.shortName);
10673 }
10674
10675 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10676 ConnectionRecord c = new ConnectionRecord(b, activity,
10677 connection, flags);
10678
10679 IBinder binder = connection.asBinder();
10680 s.connections.put(binder, c);
10681 b.connections.add(c);
10682 if (activity != null) {
10683 if (activity.connections == null) {
10684 activity.connections = new HashSet<ConnectionRecord>();
10685 }
10686 activity.connections.add(c);
10687 }
10688 b.client.connections.add(c);
10689 mServiceConnections.put(binder, c);
10690
10691 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10692 s.lastActivity = SystemClock.uptimeMillis();
10693 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10694 return 0;
10695 }
10696 }
10697
10698 if (s.app != null) {
10699 // This could have made the service more important.
10700 updateOomAdjLocked(s.app);
10701 }
10702
10703 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10704 + ": received=" + b.intent.received
10705 + " apps=" + b.intent.apps.size()
10706 + " doRebind=" + b.intent.doRebind);
10707
10708 if (s.app != null && b.intent.received) {
10709 // Service is already running, so we can immediately
10710 // publish the connection.
10711 try {
10712 c.conn.connected(s.name, b.intent.binder);
10713 } catch (Exception e) {
10714 Log.w(TAG, "Failure sending service " + s.shortName
10715 + " to connection " + c.conn.asBinder()
10716 + " (in " + c.binding.client.processName + ")", e);
10717 }
10718
10719 // If this is the first app connected back to this binding,
10720 // and the service had previously asked to be told when
10721 // rebound, then do so.
10722 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10723 requestServiceBindingLocked(s, b.intent, true);
10724 }
10725 } else if (!b.intent.requested) {
10726 requestServiceBindingLocked(s, b.intent, false);
10727 }
10728
10729 Binder.restoreCallingIdentity(origId);
10730 }
10731
10732 return 1;
10733 }
10734
10735 private void removeConnectionLocked(
10736 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10737 IBinder binder = c.conn.asBinder();
10738 AppBindRecord b = c.binding;
10739 ServiceRecord s = b.service;
10740 s.connections.remove(binder);
10741 b.connections.remove(c);
10742 if (c.activity != null && c.activity != skipAct) {
10743 if (c.activity.connections != null) {
10744 c.activity.connections.remove(c);
10745 }
10746 }
10747 if (b.client != skipApp) {
10748 b.client.connections.remove(c);
10749 }
10750 mServiceConnections.remove(binder);
10751
10752 if (b.connections.size() == 0) {
10753 b.intent.apps.remove(b.client);
10754 }
10755
10756 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10757 + ": shouldUnbind=" + b.intent.hasBound);
10758 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10759 && b.intent.hasBound) {
10760 try {
10761 bumpServiceExecutingLocked(s);
10762 updateOomAdjLocked(s.app);
10763 b.intent.hasBound = false;
10764 // Assume the client doesn't want to know about a rebind;
10765 // we will deal with that later if it asks for one.
10766 b.intent.doRebind = false;
10767 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10768 } catch (Exception e) {
10769 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10770 serviceDoneExecutingLocked(s, true);
10771 }
10772 }
10773
10774 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10775 bringDownServiceLocked(s, false);
10776 }
10777 }
10778
10779 public boolean unbindService(IServiceConnection connection) {
10780 synchronized (this) {
10781 IBinder binder = connection.asBinder();
10782 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10783 ConnectionRecord r = mServiceConnections.get(binder);
10784 if (r == null) {
10785 Log.w(TAG, "Unbind failed: could not find connection for "
10786 + connection.asBinder());
10787 return false;
10788 }
10789
10790 final long origId = Binder.clearCallingIdentity();
10791
10792 removeConnectionLocked(r, null, null);
10793
10794 if (r.binding.service.app != null) {
10795 // This could have made the service less important.
10796 updateOomAdjLocked(r.binding.service.app);
10797 }
10798
10799 Binder.restoreCallingIdentity(origId);
10800 }
10801
10802 return true;
10803 }
10804
10805 public void publishService(IBinder token, Intent intent, IBinder service) {
10806 // Refuse possible leaked file descriptors
10807 if (intent != null && intent.hasFileDescriptors() == true) {
10808 throw new IllegalArgumentException("File descriptors passed in Intent");
10809 }
10810
10811 synchronized(this) {
10812 if (!(token instanceof ServiceRecord)) {
10813 throw new IllegalArgumentException("Invalid service token");
10814 }
10815 ServiceRecord r = (ServiceRecord)token;
10816
10817 final long origId = Binder.clearCallingIdentity();
10818
10819 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10820 + " " + intent + ": " + service);
10821 if (r != null) {
10822 Intent.FilterComparison filter
10823 = new Intent.FilterComparison(intent);
10824 IntentBindRecord b = r.bindings.get(filter);
10825 if (b != null && !b.received) {
10826 b.binder = service;
10827 b.requested = true;
10828 b.received = true;
10829 if (r.connections.size() > 0) {
10830 Iterator<ConnectionRecord> it
10831 = r.connections.values().iterator();
10832 while (it.hasNext()) {
10833 ConnectionRecord c = it.next();
10834 if (!filter.equals(c.binding.intent.intent)) {
10835 if (DEBUG_SERVICE) Log.v(
10836 TAG, "Not publishing to: " + c);
10837 if (DEBUG_SERVICE) Log.v(
10838 TAG, "Bound intent: " + c.binding.intent.intent);
10839 if (DEBUG_SERVICE) Log.v(
10840 TAG, "Published intent: " + intent);
10841 continue;
10842 }
10843 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10844 try {
10845 c.conn.connected(r.name, service);
10846 } catch (Exception e) {
10847 Log.w(TAG, "Failure sending service " + r.name +
10848 " to connection " + c.conn.asBinder() +
10849 " (in " + c.binding.client.processName + ")", e);
10850 }
10851 }
10852 }
10853 }
10854
10855 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10856
10857 Binder.restoreCallingIdentity(origId);
10858 }
10859 }
10860 }
10861
10862 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10863 // Refuse possible leaked file descriptors
10864 if (intent != null && intent.hasFileDescriptors() == true) {
10865 throw new IllegalArgumentException("File descriptors passed in Intent");
10866 }
10867
10868 synchronized(this) {
10869 if (!(token instanceof ServiceRecord)) {
10870 throw new IllegalArgumentException("Invalid service token");
10871 }
10872 ServiceRecord r = (ServiceRecord)token;
10873
10874 final long origId = Binder.clearCallingIdentity();
10875
10876 if (r != null) {
10877 Intent.FilterComparison filter
10878 = new Intent.FilterComparison(intent);
10879 IntentBindRecord b = r.bindings.get(filter);
10880 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10881 + " at " + b + ": apps="
10882 + (b != null ? b.apps.size() : 0));
10883 if (b != null) {
10884 if (b.apps.size() > 0) {
10885 // Applications have already bound since the last
10886 // unbind, so just rebind right here.
10887 requestServiceBindingLocked(r, b, true);
10888 } else {
10889 // Note to tell the service the next time there is
10890 // a new client.
10891 b.doRebind = true;
10892 }
10893 }
10894
10895 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10896
10897 Binder.restoreCallingIdentity(origId);
10898 }
10899 }
10900 }
10901
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010902 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010903 synchronized(this) {
10904 if (!(token instanceof ServiceRecord)) {
10905 throw new IllegalArgumentException("Invalid service token");
10906 }
10907 ServiceRecord r = (ServiceRecord)token;
10908 boolean inStopping = mStoppingServices.contains(token);
10909 if (r != null) {
10910 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10911 + ": nesting=" + r.executeNesting
10912 + ", inStopping=" + inStopping);
10913 if (r != token) {
10914 Log.w(TAG, "Done executing service " + r.name
10915 + " with incorrect token: given " + token
10916 + ", expected " + r);
10917 return;
10918 }
10919
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010920 if (type == 1) {
10921 // This is a call from a service start... take care of
10922 // book-keeping.
10923 r.callStart = true;
10924 switch (res) {
10925 case Service.START_STICKY_COMPATIBILITY:
10926 case Service.START_STICKY: {
10927 // We are done with the associated start arguments.
10928 r.findDeliveredStart(startId, true);
10929 // Don't stop if killed.
10930 r.stopIfKilled = false;
10931 break;
10932 }
10933 case Service.START_NOT_STICKY: {
10934 // We are done with the associated start arguments.
10935 r.findDeliveredStart(startId, true);
10936 if (r.lastStartId == startId) {
10937 // There is no more work, and this service
10938 // doesn't want to hang around if killed.
10939 r.stopIfKilled = true;
10940 }
10941 break;
10942 }
10943 case Service.START_REDELIVER_INTENT: {
10944 // We'll keep this item until they explicitly
10945 // call stop for it, but keep track of the fact
10946 // that it was delivered.
10947 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10948 if (si != null) {
10949 si.deliveryCount = 0;
10950 si.doneExecutingCount++;
10951 // Don't stop if killed.
10952 r.stopIfKilled = true;
10953 }
10954 break;
10955 }
10956 default:
10957 throw new IllegalArgumentException(
10958 "Unknown service start result: " + res);
10959 }
10960 if (res == Service.START_STICKY_COMPATIBILITY) {
10961 r.callStart = false;
10962 }
10963 }
10964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010965 final long origId = Binder.clearCallingIdentity();
10966 serviceDoneExecutingLocked(r, inStopping);
10967 Binder.restoreCallingIdentity(origId);
10968 } else {
10969 Log.w(TAG, "Done executing unknown service " + r.name
10970 + " with token " + token);
10971 }
10972 }
10973 }
10974
10975 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10976 r.executeNesting--;
10977 if (r.executeNesting <= 0 && r.app != null) {
10978 r.app.executingServices.remove(r);
10979 if (r.app.executingServices.size() == 0) {
10980 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10981 }
10982 if (inStopping) {
10983 mStoppingServices.remove(r);
10984 }
10985 updateOomAdjLocked(r.app);
10986 }
10987 }
10988
10989 void serviceTimeout(ProcessRecord proc) {
10990 synchronized(this) {
10991 if (proc.executingServices.size() == 0 || proc.thread == null) {
10992 return;
10993 }
10994 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10995 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10996 ServiceRecord timeout = null;
10997 long nextTime = 0;
10998 while (it.hasNext()) {
10999 ServiceRecord sr = it.next();
11000 if (sr.executingStart < maxTime) {
11001 timeout = sr;
11002 break;
11003 }
11004 if (sr.executingStart > nextTime) {
11005 nextTime = sr.executingStart;
11006 }
11007 }
11008 if (timeout != null && mLRUProcesses.contains(proc)) {
11009 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011010 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011011 + timeout.name);
11012 } else {
11013 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11014 msg.obj = proc;
11015 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11016 }
11017 }
11018 }
11019
11020 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011021 // BACKUP AND RESTORE
11022 // =========================================================
11023
11024 // Cause the target app to be launched if necessary and its backup agent
11025 // instantiated. The backup agent will invoke backupAgentCreated() on the
11026 // activity manager to announce its creation.
11027 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11028 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11029 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11030
11031 synchronized(this) {
11032 // !!! TODO: currently no check here that we're already bound
11033 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11034 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11035 synchronized (stats) {
11036 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11037 }
11038
11039 BackupRecord r = new BackupRecord(ss, app, backupMode);
11040 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11041 // startProcessLocked() returns existing proc's record if it's already running
11042 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011043 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011044 if (proc == null) {
11045 Log.e(TAG, "Unable to start backup agent process " + r);
11046 return false;
11047 }
11048
11049 r.app = proc;
11050 mBackupTarget = r;
11051 mBackupAppName = app.packageName;
11052
Christopher Tate6fa95972009-06-05 18:43:55 -070011053 // Try not to kill the process during backup
11054 updateOomAdjLocked(proc);
11055
Christopher Tate181fafa2009-05-14 11:12:14 -070011056 // If the process is already attached, schedule the creation of the backup agent now.
11057 // If it is not yet live, this will be done when it attaches to the framework.
11058 if (proc.thread != null) {
11059 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11060 try {
11061 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11062 } catch (RemoteException e) {
11063 // !!! TODO: notify the backup manager that we crashed, or rely on
11064 // death notices, or...?
11065 }
11066 } else {
11067 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11068 }
11069 // Invariants: at this point, the target app process exists and the application
11070 // is either already running or in the process of coming up. mBackupTarget and
11071 // mBackupAppName describe the app, so that when it binds back to the AM we
11072 // know that it's scheduled for a backup-agent operation.
11073 }
11074
11075 return true;
11076 }
11077
11078 // A backup agent has just come up
11079 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11080 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11081 + " = " + agent);
11082
11083 synchronized(this) {
11084 if (!agentPackageName.equals(mBackupAppName)) {
11085 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11086 return;
11087 }
11088
Christopher Tate043dadc2009-06-02 16:11:00 -070011089 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011090 try {
11091 IBackupManager bm = IBackupManager.Stub.asInterface(
11092 ServiceManager.getService(Context.BACKUP_SERVICE));
11093 bm.agentConnected(agentPackageName, agent);
11094 } catch (RemoteException e) {
11095 // can't happen; the backup manager service is local
11096 } catch (Exception e) {
11097 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11098 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011099 } finally {
11100 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011101 }
11102 }
11103 }
11104
11105 // done with this agent
11106 public void unbindBackupAgent(ApplicationInfo appInfo) {
11107 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011108 if (appInfo == null) {
11109 Log.w(TAG, "unbind backup agent for null app");
11110 return;
11111 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011112
11113 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011114 if (mBackupAppName == null) {
11115 Log.w(TAG, "Unbinding backup agent with no active backup");
11116 return;
11117 }
11118
Christopher Tate181fafa2009-05-14 11:12:14 -070011119 if (!mBackupAppName.equals(appInfo.packageName)) {
11120 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11121 return;
11122 }
11123
Christopher Tate6fa95972009-06-05 18:43:55 -070011124 ProcessRecord proc = mBackupTarget.app;
11125 mBackupTarget = null;
11126 mBackupAppName = null;
11127
11128 // Not backing this app up any more; reset its OOM adjustment
11129 updateOomAdjLocked(proc);
11130
Christopher Tatec7b31e32009-06-10 15:49:30 -070011131 // If the app crashed during backup, 'thread' will be null here
11132 if (proc.thread != null) {
11133 try {
11134 proc.thread.scheduleDestroyBackupAgent(appInfo);
11135 } catch (Exception e) {
11136 Log.e(TAG, "Exception when unbinding backup agent:");
11137 e.printStackTrace();
11138 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011139 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011140 }
11141 }
11142 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011143 // BROADCASTS
11144 // =========================================================
11145
11146 private final List getStickies(String action, IntentFilter filter,
11147 List cur) {
11148 final ContentResolver resolver = mContext.getContentResolver();
11149 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11150 if (list == null) {
11151 return cur;
11152 }
11153 int N = list.size();
11154 for (int i=0; i<N; i++) {
11155 Intent intent = list.get(i);
11156 if (filter.match(resolver, intent, true, TAG) >= 0) {
11157 if (cur == null) {
11158 cur = new ArrayList<Intent>();
11159 }
11160 cur.add(intent);
11161 }
11162 }
11163 return cur;
11164 }
11165
11166 private final void scheduleBroadcastsLocked() {
11167 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11168 + mBroadcastsScheduled);
11169
11170 if (mBroadcastsScheduled) {
11171 return;
11172 }
11173 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11174 mBroadcastsScheduled = true;
11175 }
11176
11177 public Intent registerReceiver(IApplicationThread caller,
11178 IIntentReceiver receiver, IntentFilter filter, String permission) {
11179 synchronized(this) {
11180 ProcessRecord callerApp = null;
11181 if (caller != null) {
11182 callerApp = getRecordForAppLocked(caller);
11183 if (callerApp == null) {
11184 throw new SecurityException(
11185 "Unable to find app for caller " + caller
11186 + " (pid=" + Binder.getCallingPid()
11187 + ") when registering receiver " + receiver);
11188 }
11189 }
11190
11191 List allSticky = null;
11192
11193 // Look for any matching sticky broadcasts...
11194 Iterator actions = filter.actionsIterator();
11195 if (actions != null) {
11196 while (actions.hasNext()) {
11197 String action = (String)actions.next();
11198 allSticky = getStickies(action, filter, allSticky);
11199 }
11200 } else {
11201 allSticky = getStickies(null, filter, allSticky);
11202 }
11203
11204 // The first sticky in the list is returned directly back to
11205 // the client.
11206 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11207
11208 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11209 + ": " + sticky);
11210
11211 if (receiver == null) {
11212 return sticky;
11213 }
11214
11215 ReceiverList rl
11216 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11217 if (rl == null) {
11218 rl = new ReceiverList(this, callerApp,
11219 Binder.getCallingPid(),
11220 Binder.getCallingUid(), receiver);
11221 if (rl.app != null) {
11222 rl.app.receivers.add(rl);
11223 } else {
11224 try {
11225 receiver.asBinder().linkToDeath(rl, 0);
11226 } catch (RemoteException e) {
11227 return sticky;
11228 }
11229 rl.linkedToDeath = true;
11230 }
11231 mRegisteredReceivers.put(receiver.asBinder(), rl);
11232 }
11233 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11234 rl.add(bf);
11235 if (!bf.debugCheck()) {
11236 Log.w(TAG, "==> For Dynamic broadast");
11237 }
11238 mReceiverResolver.addFilter(bf);
11239
11240 // Enqueue broadcasts for all existing stickies that match
11241 // this filter.
11242 if (allSticky != null) {
11243 ArrayList receivers = new ArrayList();
11244 receivers.add(bf);
11245
11246 int N = allSticky.size();
11247 for (int i=0; i<N; i++) {
11248 Intent intent = (Intent)allSticky.get(i);
11249 BroadcastRecord r = new BroadcastRecord(intent, null,
11250 null, -1, -1, null, receivers, null, 0, null, null,
11251 false);
11252 if (mParallelBroadcasts.size() == 0) {
11253 scheduleBroadcastsLocked();
11254 }
11255 mParallelBroadcasts.add(r);
11256 }
11257 }
11258
11259 return sticky;
11260 }
11261 }
11262
11263 public void unregisterReceiver(IIntentReceiver receiver) {
11264 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11265
11266 boolean doNext = false;
11267
11268 synchronized(this) {
11269 ReceiverList rl
11270 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11271 if (rl != null) {
11272 if (rl.curBroadcast != null) {
11273 BroadcastRecord r = rl.curBroadcast;
11274 doNext = finishReceiverLocked(
11275 receiver.asBinder(), r.resultCode, r.resultData,
11276 r.resultExtras, r.resultAbort, true);
11277 }
11278
11279 if (rl.app != null) {
11280 rl.app.receivers.remove(rl);
11281 }
11282 removeReceiverLocked(rl);
11283 if (rl.linkedToDeath) {
11284 rl.linkedToDeath = false;
11285 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11286 }
11287 }
11288 }
11289
11290 if (!doNext) {
11291 return;
11292 }
11293
11294 final long origId = Binder.clearCallingIdentity();
11295 processNextBroadcast(false);
11296 trimApplications();
11297 Binder.restoreCallingIdentity(origId);
11298 }
11299
11300 void removeReceiverLocked(ReceiverList rl) {
11301 mRegisteredReceivers.remove(rl.receiver.asBinder());
11302 int N = rl.size();
11303 for (int i=0; i<N; i++) {
11304 mReceiverResolver.removeFilter(rl.get(i));
11305 }
11306 }
11307
11308 private final int broadcastIntentLocked(ProcessRecord callerApp,
11309 String callerPackage, Intent intent, String resolvedType,
11310 IIntentReceiver resultTo, int resultCode, String resultData,
11311 Bundle map, String requiredPermission,
11312 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11313 intent = new Intent(intent);
11314
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011315 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011316 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11317 + " ordered=" + ordered);
11318 if ((resultTo != null) && !ordered) {
11319 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11320 }
11321
11322 // Handle special intents: if this broadcast is from the package
11323 // manager about a package being removed, we need to remove all of
11324 // its activities from the history stack.
11325 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11326 intent.getAction());
11327 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11328 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11329 || uidRemoved) {
11330 if (checkComponentPermission(
11331 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11332 callingPid, callingUid, -1)
11333 == PackageManager.PERMISSION_GRANTED) {
11334 if (uidRemoved) {
11335 final Bundle intentExtras = intent.getExtras();
11336 final int uid = intentExtras != null
11337 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11338 if (uid >= 0) {
11339 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11340 synchronized (bs) {
11341 bs.removeUidStatsLocked(uid);
11342 }
11343 }
11344 } else {
11345 Uri data = intent.getData();
11346 String ssp;
11347 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11348 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11349 uninstallPackageLocked(ssp,
11350 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011351 AttributeCache ac = AttributeCache.instance();
11352 if (ac != null) {
11353 ac.removePackage(ssp);
11354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011355 }
11356 }
11357 }
11358 } else {
11359 String msg = "Permission Denial: " + intent.getAction()
11360 + " broadcast from " + callerPackage + " (pid=" + callingPid
11361 + ", uid=" + callingUid + ")"
11362 + " requires "
11363 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11364 Log.w(TAG, msg);
11365 throw new SecurityException(msg);
11366 }
11367 }
11368
11369 /*
11370 * If this is the time zone changed action, queue up a message that will reset the timezone
11371 * of all currently running processes. This message will get queued up before the broadcast
11372 * happens.
11373 */
11374 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11375 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11376 }
11377
Dianne Hackborn854060af2009-07-09 18:14:31 -070011378 /*
11379 * Prevent non-system code (defined here to be non-persistent
11380 * processes) from sending protected broadcasts.
11381 */
11382 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11383 || callingUid == Process.SHELL_UID || callingUid == 0) {
11384 // Always okay.
11385 } else if (callerApp == null || !callerApp.persistent) {
11386 try {
11387 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11388 intent.getAction())) {
11389 String msg = "Permission Denial: not allowed to send broadcast "
11390 + intent.getAction() + " from pid="
11391 + callingPid + ", uid=" + callingUid;
11392 Log.w(TAG, msg);
11393 throw new SecurityException(msg);
11394 }
11395 } catch (RemoteException e) {
11396 Log.w(TAG, "Remote exception", e);
11397 return BROADCAST_SUCCESS;
11398 }
11399 }
11400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011401 // Add to the sticky list if requested.
11402 if (sticky) {
11403 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11404 callingPid, callingUid)
11405 != PackageManager.PERMISSION_GRANTED) {
11406 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11407 + callingPid + ", uid=" + callingUid
11408 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11409 Log.w(TAG, msg);
11410 throw new SecurityException(msg);
11411 }
11412 if (requiredPermission != null) {
11413 Log.w(TAG, "Can't broadcast sticky intent " + intent
11414 + " and enforce permission " + requiredPermission);
11415 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11416 }
11417 if (intent.getComponent() != null) {
11418 throw new SecurityException(
11419 "Sticky broadcasts can't target a specific component");
11420 }
11421 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11422 if (list == null) {
11423 list = new ArrayList<Intent>();
11424 mStickyBroadcasts.put(intent.getAction(), list);
11425 }
11426 int N = list.size();
11427 int i;
11428 for (i=0; i<N; i++) {
11429 if (intent.filterEquals(list.get(i))) {
11430 // This sticky already exists, replace it.
11431 list.set(i, new Intent(intent));
11432 break;
11433 }
11434 }
11435 if (i >= N) {
11436 list.add(new Intent(intent));
11437 }
11438 }
11439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011440 // Figure out who all will receive this broadcast.
11441 List receivers = null;
11442 List<BroadcastFilter> registeredReceivers = null;
11443 try {
11444 if (intent.getComponent() != null) {
11445 // Broadcast is going to one specific receiver class...
11446 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011447 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011448 if (ai != null) {
11449 receivers = new ArrayList();
11450 ResolveInfo ri = new ResolveInfo();
11451 ri.activityInfo = ai;
11452 receivers.add(ri);
11453 }
11454 } else {
11455 // Need to resolve the intent to interested receivers...
11456 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11457 == 0) {
11458 receivers =
11459 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011460 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011461 }
Mihai Preda074edef2009-05-18 17:13:31 +020011462 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011463 }
11464 } catch (RemoteException ex) {
11465 // pm is in same process, this will never happen.
11466 }
11467
11468 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11469 if (!ordered && NR > 0) {
11470 // If we are not serializing this broadcast, then send the
11471 // registered receivers separately so they don't wait for the
11472 // components to be launched.
11473 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11474 callerPackage, callingPid, callingUid, requiredPermission,
11475 registeredReceivers, resultTo, resultCode, resultData, map,
11476 ordered);
11477 if (DEBUG_BROADCAST) Log.v(
11478 TAG, "Enqueueing parallel broadcast " + r
11479 + ": prev had " + mParallelBroadcasts.size());
11480 mParallelBroadcasts.add(r);
11481 scheduleBroadcastsLocked();
11482 registeredReceivers = null;
11483 NR = 0;
11484 }
11485
11486 // Merge into one list.
11487 int ir = 0;
11488 if (receivers != null) {
11489 // A special case for PACKAGE_ADDED: do not allow the package
11490 // being added to see this broadcast. This prevents them from
11491 // using this as a back door to get run as soon as they are
11492 // installed. Maybe in the future we want to have a special install
11493 // broadcast or such for apps, but we'd like to deliberately make
11494 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011495 boolean skip = false;
11496 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011497 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011498 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11499 skip = true;
11500 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11501 skip = true;
11502 }
11503 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011504 ? intent.getData().getSchemeSpecificPart()
11505 : null;
11506 if (skipPackage != null && receivers != null) {
11507 int NT = receivers.size();
11508 for (int it=0; it<NT; it++) {
11509 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11510 if (curt.activityInfo.packageName.equals(skipPackage)) {
11511 receivers.remove(it);
11512 it--;
11513 NT--;
11514 }
11515 }
11516 }
11517
11518 int NT = receivers != null ? receivers.size() : 0;
11519 int it = 0;
11520 ResolveInfo curt = null;
11521 BroadcastFilter curr = null;
11522 while (it < NT && ir < NR) {
11523 if (curt == null) {
11524 curt = (ResolveInfo)receivers.get(it);
11525 }
11526 if (curr == null) {
11527 curr = registeredReceivers.get(ir);
11528 }
11529 if (curr.getPriority() >= curt.priority) {
11530 // Insert this broadcast record into the final list.
11531 receivers.add(it, curr);
11532 ir++;
11533 curr = null;
11534 it++;
11535 NT++;
11536 } else {
11537 // Skip to the next ResolveInfo in the final list.
11538 it++;
11539 curt = null;
11540 }
11541 }
11542 }
11543 while (ir < NR) {
11544 if (receivers == null) {
11545 receivers = new ArrayList();
11546 }
11547 receivers.add(registeredReceivers.get(ir));
11548 ir++;
11549 }
11550
11551 if ((receivers != null && receivers.size() > 0)
11552 || resultTo != null) {
11553 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11554 callerPackage, callingPid, callingUid, requiredPermission,
11555 receivers, resultTo, resultCode, resultData, map, ordered);
11556 if (DEBUG_BROADCAST) Log.v(
11557 TAG, "Enqueueing ordered broadcast " + r
11558 + ": prev had " + mOrderedBroadcasts.size());
11559 if (DEBUG_BROADCAST) {
11560 int seq = r.intent.getIntExtra("seq", -1);
11561 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11562 }
11563 mOrderedBroadcasts.add(r);
11564 scheduleBroadcastsLocked();
11565 }
11566
11567 return BROADCAST_SUCCESS;
11568 }
11569
11570 public final int broadcastIntent(IApplicationThread caller,
11571 Intent intent, String resolvedType, IIntentReceiver resultTo,
11572 int resultCode, String resultData, Bundle map,
11573 String requiredPermission, boolean serialized, boolean sticky) {
11574 // Refuse possible leaked file descriptors
11575 if (intent != null && intent.hasFileDescriptors() == true) {
11576 throw new IllegalArgumentException("File descriptors passed in Intent");
11577 }
11578
11579 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011580 int flags = intent.getFlags();
11581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011582 if (!mSystemReady) {
11583 // if the caller really truly claims to know what they're doing, go
11584 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011585 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11586 intent = new Intent(intent);
11587 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11588 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11589 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11590 + " before boot completion");
11591 throw new IllegalStateException("Cannot broadcast before boot completed");
11592 }
11593 }
11594
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011595 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11596 throw new IllegalArgumentException(
11597 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11598 }
11599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011600 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11601 final int callingPid = Binder.getCallingPid();
11602 final int callingUid = Binder.getCallingUid();
11603 final long origId = Binder.clearCallingIdentity();
11604 int res = broadcastIntentLocked(callerApp,
11605 callerApp != null ? callerApp.info.packageName : null,
11606 intent, resolvedType, resultTo,
11607 resultCode, resultData, map, requiredPermission, serialized,
11608 sticky, callingPid, callingUid);
11609 Binder.restoreCallingIdentity(origId);
11610 return res;
11611 }
11612 }
11613
11614 int broadcastIntentInPackage(String packageName, int uid,
11615 Intent intent, String resolvedType, IIntentReceiver resultTo,
11616 int resultCode, String resultData, Bundle map,
11617 String requiredPermission, boolean serialized, boolean sticky) {
11618 synchronized(this) {
11619 final long origId = Binder.clearCallingIdentity();
11620 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11621 resultTo, resultCode, resultData, map, requiredPermission,
11622 serialized, sticky, -1, uid);
11623 Binder.restoreCallingIdentity(origId);
11624 return res;
11625 }
11626 }
11627
11628 public final void unbroadcastIntent(IApplicationThread caller,
11629 Intent intent) {
11630 // Refuse possible leaked file descriptors
11631 if (intent != null && intent.hasFileDescriptors() == true) {
11632 throw new IllegalArgumentException("File descriptors passed in Intent");
11633 }
11634
11635 synchronized(this) {
11636 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11637 != PackageManager.PERMISSION_GRANTED) {
11638 String msg = "Permission Denial: unbroadcastIntent() from pid="
11639 + Binder.getCallingPid()
11640 + ", uid=" + Binder.getCallingUid()
11641 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11642 Log.w(TAG, msg);
11643 throw new SecurityException(msg);
11644 }
11645 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11646 if (list != null) {
11647 int N = list.size();
11648 int i;
11649 for (i=0; i<N; i++) {
11650 if (intent.filterEquals(list.get(i))) {
11651 list.remove(i);
11652 break;
11653 }
11654 }
11655 }
11656 }
11657 }
11658
11659 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11660 String resultData, Bundle resultExtras, boolean resultAbort,
11661 boolean explicit) {
11662 if (mOrderedBroadcasts.size() == 0) {
11663 if (explicit) {
11664 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11665 }
11666 return false;
11667 }
11668 BroadcastRecord r = mOrderedBroadcasts.get(0);
11669 if (r.receiver == null) {
11670 if (explicit) {
11671 Log.w(TAG, "finishReceiver called but none active");
11672 }
11673 return false;
11674 }
11675 if (r.receiver != receiver) {
11676 Log.w(TAG, "finishReceiver called but active receiver is different");
11677 return false;
11678 }
11679 int state = r.state;
11680 r.state = r.IDLE;
11681 if (state == r.IDLE) {
11682 if (explicit) {
11683 Log.w(TAG, "finishReceiver called but state is IDLE");
11684 }
11685 }
11686 r.receiver = null;
11687 r.intent.setComponent(null);
11688 if (r.curApp != null) {
11689 r.curApp.curReceiver = null;
11690 }
11691 if (r.curFilter != null) {
11692 r.curFilter.receiverList.curBroadcast = null;
11693 }
11694 r.curFilter = null;
11695 r.curApp = null;
11696 r.curComponent = null;
11697 r.curReceiver = null;
11698 mPendingBroadcast = null;
11699
11700 r.resultCode = resultCode;
11701 r.resultData = resultData;
11702 r.resultExtras = resultExtras;
11703 r.resultAbort = resultAbort;
11704
11705 // We will process the next receiver right now if this is finishing
11706 // an app receiver (which is always asynchronous) or after we have
11707 // come back from calling a receiver.
11708 return state == BroadcastRecord.APP_RECEIVE
11709 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11710 }
11711
11712 public void finishReceiver(IBinder who, int resultCode, String resultData,
11713 Bundle resultExtras, boolean resultAbort) {
11714 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11715
11716 // Refuse possible leaked file descriptors
11717 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11718 throw new IllegalArgumentException("File descriptors passed in Bundle");
11719 }
11720
11721 boolean doNext;
11722
11723 final long origId = Binder.clearCallingIdentity();
11724
11725 synchronized(this) {
11726 doNext = finishReceiverLocked(
11727 who, resultCode, resultData, resultExtras, resultAbort, true);
11728 }
11729
11730 if (doNext) {
11731 processNextBroadcast(false);
11732 }
11733 trimApplications();
11734
11735 Binder.restoreCallingIdentity(origId);
11736 }
11737
11738 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11739 if (r.nextReceiver > 0) {
11740 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11741 if (curReceiver instanceof BroadcastFilter) {
11742 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11743 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11744 System.identityHashCode(r),
11745 r.intent.getAction(),
11746 r.nextReceiver - 1,
11747 System.identityHashCode(bf));
11748 } else {
11749 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11750 System.identityHashCode(r),
11751 r.intent.getAction(),
11752 r.nextReceiver - 1,
11753 ((ResolveInfo)curReceiver).toString());
11754 }
11755 } else {
11756 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11757 + r);
11758 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11759 System.identityHashCode(r),
11760 r.intent.getAction(),
11761 r.nextReceiver,
11762 "NONE");
11763 }
11764 }
11765
11766 private final void broadcastTimeout() {
11767 synchronized (this) {
11768 if (mOrderedBroadcasts.size() == 0) {
11769 return;
11770 }
11771 long now = SystemClock.uptimeMillis();
11772 BroadcastRecord r = mOrderedBroadcasts.get(0);
11773 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11774 if (DEBUG_BROADCAST) Log.v(TAG,
11775 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11776 + (r.startTime + BROADCAST_TIMEOUT));
11777 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11778 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11779 return;
11780 }
11781
11782 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11783 r.startTime = now;
11784 r.anrCount++;
11785
11786 // Current receiver has passed its expiration date.
11787 if (r.nextReceiver <= 0) {
11788 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11789 return;
11790 }
11791
11792 ProcessRecord app = null;
11793
11794 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11795 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11796 logBroadcastReceiverDiscard(r);
11797 if (curReceiver instanceof BroadcastFilter) {
11798 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11799 if (bf.receiverList.pid != 0
11800 && bf.receiverList.pid != MY_PID) {
11801 synchronized (this.mPidsSelfLocked) {
11802 app = this.mPidsSelfLocked.get(
11803 bf.receiverList.pid);
11804 }
11805 }
11806 } else {
11807 app = r.curApp;
11808 }
11809
11810 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011811 appNotRespondingLocked(app, null, null,
11812 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011813 }
11814
11815 if (mPendingBroadcast == r) {
11816 mPendingBroadcast = null;
11817 }
11818
11819 // Move on to the next receiver.
11820 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11821 r.resultExtras, r.resultAbort, true);
11822 scheduleBroadcastsLocked();
11823 }
11824 }
11825
11826 private final void processCurBroadcastLocked(BroadcastRecord r,
11827 ProcessRecord app) throws RemoteException {
11828 if (app.thread == null) {
11829 throw new RemoteException();
11830 }
11831 r.receiver = app.thread.asBinder();
11832 r.curApp = app;
11833 app.curReceiver = r;
11834 updateLRUListLocked(app, true);
11835
11836 // Tell the application to launch this receiver.
11837 r.intent.setComponent(r.curComponent);
11838
11839 boolean started = false;
11840 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011841 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011842 "Delivering to component " + r.curComponent
11843 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011844 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011845 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11846 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11847 started = true;
11848 } finally {
11849 if (!started) {
11850 r.receiver = null;
11851 r.curApp = null;
11852 app.curReceiver = null;
11853 }
11854 }
11855
11856 }
11857
11858 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11859 Intent intent, int resultCode, String data,
11860 Bundle extras, boolean ordered) throws RemoteException {
11861 if (app != null && app.thread != null) {
11862 // If we have an app thread, do the call through that so it is
11863 // correctly ordered with other one-way calls.
11864 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11865 data, extras, ordered);
11866 } else {
11867 receiver.performReceive(intent, resultCode, data, extras, ordered);
11868 }
11869 }
11870
11871 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11872 BroadcastFilter filter, boolean ordered) {
11873 boolean skip = false;
11874 if (filter.requiredPermission != null) {
11875 int perm = checkComponentPermission(filter.requiredPermission,
11876 r.callingPid, r.callingUid, -1);
11877 if (perm != PackageManager.PERMISSION_GRANTED) {
11878 Log.w(TAG, "Permission Denial: broadcasting "
11879 + r.intent.toString()
11880 + " from " + r.callerPackage + " (pid="
11881 + r.callingPid + ", uid=" + r.callingUid + ")"
11882 + " requires " + filter.requiredPermission
11883 + " due to registered receiver " + filter);
11884 skip = true;
11885 }
11886 }
11887 if (r.requiredPermission != null) {
11888 int perm = checkComponentPermission(r.requiredPermission,
11889 filter.receiverList.pid, filter.receiverList.uid, -1);
11890 if (perm != PackageManager.PERMISSION_GRANTED) {
11891 Log.w(TAG, "Permission Denial: receiving "
11892 + r.intent.toString()
11893 + " to " + filter.receiverList.app
11894 + " (pid=" + filter.receiverList.pid
11895 + ", uid=" + filter.receiverList.uid + ")"
11896 + " requires " + r.requiredPermission
11897 + " due to sender " + r.callerPackage
11898 + " (uid " + r.callingUid + ")");
11899 skip = true;
11900 }
11901 }
11902
11903 if (!skip) {
11904 // If this is not being sent as an ordered broadcast, then we
11905 // don't want to touch the fields that keep track of the current
11906 // state of ordered broadcasts.
11907 if (ordered) {
11908 r.receiver = filter.receiverList.receiver.asBinder();
11909 r.curFilter = filter;
11910 filter.receiverList.curBroadcast = r;
11911 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011912 if (filter.receiverList.app != null) {
11913 // Bump hosting application to no longer be in background
11914 // scheduling class. Note that we can't do that if there
11915 // isn't an app... but we can only be in that case for
11916 // things that directly call the IActivityManager API, which
11917 // are already core system stuff so don't matter for this.
11918 r.curApp = filter.receiverList.app;
11919 filter.receiverList.app.curReceiver = r;
11920 updateOomAdjLocked();
11921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011922 }
11923 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011924 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011925 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011926 Log.i(TAG, "Delivering to " + filter.receiverList.app
11927 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011928 }
11929 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11930 new Intent(r.intent), r.resultCode,
11931 r.resultData, r.resultExtras, r.ordered);
11932 if (ordered) {
11933 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11934 }
11935 } catch (RemoteException e) {
11936 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11937 if (ordered) {
11938 r.receiver = null;
11939 r.curFilter = null;
11940 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011941 if (filter.receiverList.app != null) {
11942 filter.receiverList.app.curReceiver = null;
11943 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011944 }
11945 }
11946 }
11947 }
11948
11949 private final void processNextBroadcast(boolean fromMsg) {
11950 synchronized(this) {
11951 BroadcastRecord r;
11952
11953 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11954 + mParallelBroadcasts.size() + " broadcasts, "
11955 + mOrderedBroadcasts.size() + " serialized broadcasts");
11956
11957 updateCpuStats();
11958
11959 if (fromMsg) {
11960 mBroadcastsScheduled = false;
11961 }
11962
11963 // First, deliver any non-serialized broadcasts right away.
11964 while (mParallelBroadcasts.size() > 0) {
11965 r = mParallelBroadcasts.remove(0);
11966 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011967 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11968 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011969 for (int i=0; i<N; i++) {
11970 Object target = r.receivers.get(i);
11971 if (DEBUG_BROADCAST) Log.v(TAG,
11972 "Delivering non-serialized to registered "
11973 + target + ": " + r);
11974 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11975 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011976 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11977 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011978 }
11979
11980 // Now take care of the next serialized one...
11981
11982 // If we are waiting for a process to come up to handle the next
11983 // broadcast, then do nothing at this point. Just in case, we
11984 // check that the process we're waiting for still exists.
11985 if (mPendingBroadcast != null) {
11986 Log.i(TAG, "processNextBroadcast: waiting for "
11987 + mPendingBroadcast.curApp);
11988
11989 boolean isDead;
11990 synchronized (mPidsSelfLocked) {
11991 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11992 }
11993 if (!isDead) {
11994 // It's still alive, so keep waiting
11995 return;
11996 } else {
11997 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11998 + " died before responding to broadcast");
11999 mPendingBroadcast = null;
12000 }
12001 }
12002
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012003 boolean looped = false;
12004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012005 do {
12006 if (mOrderedBroadcasts.size() == 0) {
12007 // No more broadcasts pending, so all done!
12008 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012009 if (looped) {
12010 // If we had finished the last ordered broadcast, then
12011 // make sure all processes have correct oom and sched
12012 // adjustments.
12013 updateOomAdjLocked();
12014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012015 return;
12016 }
12017 r = mOrderedBroadcasts.get(0);
12018 boolean forceReceive = false;
12019
12020 // Ensure that even if something goes awry with the timeout
12021 // detection, we catch "hung" broadcasts here, discard them,
12022 // and continue to make progress.
12023 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12024 long now = SystemClock.uptimeMillis();
12025 if (r.dispatchTime > 0) {
12026 if ((numReceivers > 0) &&
12027 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12028 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12029 + " now=" + now
12030 + " dispatchTime=" + r.dispatchTime
12031 + " startTime=" + r.startTime
12032 + " intent=" + r.intent
12033 + " numReceivers=" + numReceivers
12034 + " nextReceiver=" + r.nextReceiver
12035 + " state=" + r.state);
12036 broadcastTimeout(); // forcibly finish this broadcast
12037 forceReceive = true;
12038 r.state = BroadcastRecord.IDLE;
12039 }
12040 }
12041
12042 if (r.state != BroadcastRecord.IDLE) {
12043 if (DEBUG_BROADCAST) Log.d(TAG,
12044 "processNextBroadcast() called when not idle (state="
12045 + r.state + ")");
12046 return;
12047 }
12048
12049 if (r.receivers == null || r.nextReceiver >= numReceivers
12050 || r.resultAbort || forceReceive) {
12051 // No more receivers for this broadcast! Send the final
12052 // result if requested...
12053 if (r.resultTo != null) {
12054 try {
12055 if (DEBUG_BROADCAST) {
12056 int seq = r.intent.getIntExtra("seq", -1);
12057 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12058 + " seq=" + seq + " app=" + r.callerApp);
12059 }
12060 performReceive(r.callerApp, r.resultTo,
12061 new Intent(r.intent), r.resultCode,
12062 r.resultData, r.resultExtras, false);
12063 } catch (RemoteException e) {
12064 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12065 }
12066 }
12067
12068 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12069 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12070
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012071 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12072 + r);
12073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012074 // ... and on to the next...
12075 mOrderedBroadcasts.remove(0);
12076 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012077 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012078 continue;
12079 }
12080 } while (r == null);
12081
12082 // Get the next receiver...
12083 int recIdx = r.nextReceiver++;
12084
12085 // Keep track of when this receiver started, and make sure there
12086 // is a timeout message pending to kill it if need be.
12087 r.startTime = SystemClock.uptimeMillis();
12088 if (recIdx == 0) {
12089 r.dispatchTime = r.startTime;
12090
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012091 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12092 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012093 if (DEBUG_BROADCAST) Log.v(TAG,
12094 "Submitting BROADCAST_TIMEOUT_MSG for "
12095 + (r.startTime + BROADCAST_TIMEOUT));
12096 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12097 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12098 }
12099
12100 Object nextReceiver = r.receivers.get(recIdx);
12101 if (nextReceiver instanceof BroadcastFilter) {
12102 // Simple case: this is a registered receiver who gets
12103 // a direct call.
12104 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12105 if (DEBUG_BROADCAST) Log.v(TAG,
12106 "Delivering serialized to registered "
12107 + filter + ": " + r);
12108 deliverToRegisteredReceiver(r, filter, r.ordered);
12109 if (r.receiver == null || !r.ordered) {
12110 // The receiver has already finished, so schedule to
12111 // process the next one.
12112 r.state = BroadcastRecord.IDLE;
12113 scheduleBroadcastsLocked();
12114 }
12115 return;
12116 }
12117
12118 // Hard case: need to instantiate the receiver, possibly
12119 // starting its application process to host it.
12120
12121 ResolveInfo info =
12122 (ResolveInfo)nextReceiver;
12123
12124 boolean skip = false;
12125 int perm = checkComponentPermission(info.activityInfo.permission,
12126 r.callingPid, r.callingUid,
12127 info.activityInfo.exported
12128 ? -1 : info.activityInfo.applicationInfo.uid);
12129 if (perm != PackageManager.PERMISSION_GRANTED) {
12130 Log.w(TAG, "Permission Denial: broadcasting "
12131 + r.intent.toString()
12132 + " from " + r.callerPackage + " (pid=" + r.callingPid
12133 + ", uid=" + r.callingUid + ")"
12134 + " requires " + info.activityInfo.permission
12135 + " due to receiver " + info.activityInfo.packageName
12136 + "/" + info.activityInfo.name);
12137 skip = true;
12138 }
12139 if (r.callingUid != Process.SYSTEM_UID &&
12140 r.requiredPermission != null) {
12141 try {
12142 perm = ActivityThread.getPackageManager().
12143 checkPermission(r.requiredPermission,
12144 info.activityInfo.applicationInfo.packageName);
12145 } catch (RemoteException e) {
12146 perm = PackageManager.PERMISSION_DENIED;
12147 }
12148 if (perm != PackageManager.PERMISSION_GRANTED) {
12149 Log.w(TAG, "Permission Denial: receiving "
12150 + r.intent + " to "
12151 + info.activityInfo.applicationInfo.packageName
12152 + " requires " + r.requiredPermission
12153 + " due to sender " + r.callerPackage
12154 + " (uid " + r.callingUid + ")");
12155 skip = true;
12156 }
12157 }
12158 if (r.curApp != null && r.curApp.crashing) {
12159 // If the target process is crashing, just skip it.
12160 skip = true;
12161 }
12162
12163 if (skip) {
12164 r.receiver = null;
12165 r.curFilter = null;
12166 r.state = BroadcastRecord.IDLE;
12167 scheduleBroadcastsLocked();
12168 return;
12169 }
12170
12171 r.state = BroadcastRecord.APP_RECEIVE;
12172 String targetProcess = info.activityInfo.processName;
12173 r.curComponent = new ComponentName(
12174 info.activityInfo.applicationInfo.packageName,
12175 info.activityInfo.name);
12176 r.curReceiver = info.activityInfo;
12177
12178 // Is this receiver's application already running?
12179 ProcessRecord app = getProcessRecordLocked(targetProcess,
12180 info.activityInfo.applicationInfo.uid);
12181 if (app != null && app.thread != null) {
12182 try {
12183 processCurBroadcastLocked(r, app);
12184 return;
12185 } catch (RemoteException e) {
12186 Log.w(TAG, "Exception when sending broadcast to "
12187 + r.curComponent, e);
12188 }
12189
12190 // If a dead object exception was thrown -- fall through to
12191 // restart the application.
12192 }
12193
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012194 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012195 if ((r.curApp=startProcessLocked(targetProcess,
12196 info.activityInfo.applicationInfo, true,
12197 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012198 "broadcast", r.curComponent,
12199 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12200 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012201 // Ah, this recipient is unavailable. Finish it if necessary,
12202 // and mark the broadcast record as ready for the next.
12203 Log.w(TAG, "Unable to launch app "
12204 + info.activityInfo.applicationInfo.packageName + "/"
12205 + info.activityInfo.applicationInfo.uid + " for broadcast "
12206 + r.intent + ": process is bad");
12207 logBroadcastReceiverDiscard(r);
12208 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12209 r.resultExtras, r.resultAbort, true);
12210 scheduleBroadcastsLocked();
12211 r.state = BroadcastRecord.IDLE;
12212 return;
12213 }
12214
12215 mPendingBroadcast = r;
12216 }
12217 }
12218
12219 // =========================================================
12220 // INSTRUMENTATION
12221 // =========================================================
12222
12223 public boolean startInstrumentation(ComponentName className,
12224 String profileFile, int flags, Bundle arguments,
12225 IInstrumentationWatcher watcher) {
12226 // Refuse possible leaked file descriptors
12227 if (arguments != null && arguments.hasFileDescriptors()) {
12228 throw new IllegalArgumentException("File descriptors passed in Bundle");
12229 }
12230
12231 synchronized(this) {
12232 InstrumentationInfo ii = null;
12233 ApplicationInfo ai = null;
12234 try {
12235 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012236 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012237 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012238 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012239 } catch (PackageManager.NameNotFoundException e) {
12240 }
12241 if (ii == null) {
12242 reportStartInstrumentationFailure(watcher, className,
12243 "Unable to find instrumentation info for: " + className);
12244 return false;
12245 }
12246 if (ai == null) {
12247 reportStartInstrumentationFailure(watcher, className,
12248 "Unable to find instrumentation target package: " + ii.targetPackage);
12249 return false;
12250 }
12251
12252 int match = mContext.getPackageManager().checkSignatures(
12253 ii.targetPackage, ii.packageName);
12254 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12255 String msg = "Permission Denial: starting instrumentation "
12256 + className + " from pid="
12257 + Binder.getCallingPid()
12258 + ", uid=" + Binder.getCallingPid()
12259 + " not allowed because package " + ii.packageName
12260 + " does not have a signature matching the target "
12261 + ii.targetPackage;
12262 reportStartInstrumentationFailure(watcher, className, msg);
12263 throw new SecurityException(msg);
12264 }
12265
12266 final long origId = Binder.clearCallingIdentity();
12267 uninstallPackageLocked(ii.targetPackage, -1, true);
12268 ProcessRecord app = addAppLocked(ai);
12269 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012270 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012271 app.instrumentationProfileFile = profileFile;
12272 app.instrumentationArguments = arguments;
12273 app.instrumentationWatcher = watcher;
12274 app.instrumentationResultClass = className;
12275 Binder.restoreCallingIdentity(origId);
12276 }
12277
12278 return true;
12279 }
12280
12281 /**
12282 * Report errors that occur while attempting to start Instrumentation. Always writes the
12283 * error to the logs, but if somebody is watching, send the report there too. This enables
12284 * the "am" command to report errors with more information.
12285 *
12286 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12287 * @param cn The component name of the instrumentation.
12288 * @param report The error report.
12289 */
12290 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12291 ComponentName cn, String report) {
12292 Log.w(TAG, report);
12293 try {
12294 if (watcher != null) {
12295 Bundle results = new Bundle();
12296 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12297 results.putString("Error", report);
12298 watcher.instrumentationStatus(cn, -1, results);
12299 }
12300 } catch (RemoteException e) {
12301 Log.w(TAG, e);
12302 }
12303 }
12304
12305 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12306 if (app.instrumentationWatcher != null) {
12307 try {
12308 // NOTE: IInstrumentationWatcher *must* be oneway here
12309 app.instrumentationWatcher.instrumentationFinished(
12310 app.instrumentationClass,
12311 resultCode,
12312 results);
12313 } catch (RemoteException e) {
12314 }
12315 }
12316 app.instrumentationWatcher = null;
12317 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012318 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012319 app.instrumentationProfileFile = null;
12320 app.instrumentationArguments = null;
12321
12322 uninstallPackageLocked(app.processName, -1, false);
12323 }
12324
12325 public void finishInstrumentation(IApplicationThread target,
12326 int resultCode, Bundle results) {
12327 // Refuse possible leaked file descriptors
12328 if (results != null && results.hasFileDescriptors()) {
12329 throw new IllegalArgumentException("File descriptors passed in Intent");
12330 }
12331
12332 synchronized(this) {
12333 ProcessRecord app = getRecordForAppLocked(target);
12334 if (app == null) {
12335 Log.w(TAG, "finishInstrumentation: no app for " + target);
12336 return;
12337 }
12338 final long origId = Binder.clearCallingIdentity();
12339 finishInstrumentationLocked(app, resultCode, results);
12340 Binder.restoreCallingIdentity(origId);
12341 }
12342 }
12343
12344 // =========================================================
12345 // CONFIGURATION
12346 // =========================================================
12347
12348 public ConfigurationInfo getDeviceConfigurationInfo() {
12349 ConfigurationInfo config = new ConfigurationInfo();
12350 synchronized (this) {
12351 config.reqTouchScreen = mConfiguration.touchscreen;
12352 config.reqKeyboardType = mConfiguration.keyboard;
12353 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012354 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12355 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012356 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12357 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012358 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12359 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012360 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12361 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012362 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012363 }
12364 return config;
12365 }
12366
12367 public Configuration getConfiguration() {
12368 Configuration ci;
12369 synchronized(this) {
12370 ci = new Configuration(mConfiguration);
12371 }
12372 return ci;
12373 }
12374
12375 public void updateConfiguration(Configuration values) {
12376 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12377 "updateConfiguration()");
12378
12379 synchronized(this) {
12380 if (values == null && mWindowManager != null) {
12381 // sentinel: fetch the current configuration from the window manager
12382 values = mWindowManager.computeNewConfiguration();
12383 }
12384
12385 final long origId = Binder.clearCallingIdentity();
12386 updateConfigurationLocked(values, null);
12387 Binder.restoreCallingIdentity(origId);
12388 }
12389 }
12390
12391 /**
12392 * Do either or both things: (1) change the current configuration, and (2)
12393 * make sure the given activity is running with the (now) current
12394 * configuration. Returns true if the activity has been left running, or
12395 * false if <var>starting</var> is being destroyed to match the new
12396 * configuration.
12397 */
12398 public boolean updateConfigurationLocked(Configuration values,
12399 HistoryRecord starting) {
12400 int changes = 0;
12401
12402 boolean kept = true;
12403
12404 if (values != null) {
12405 Configuration newConfig = new Configuration(mConfiguration);
12406 changes = newConfig.updateFrom(values);
12407 if (changes != 0) {
12408 if (DEBUG_SWITCH) {
12409 Log.i(TAG, "Updating configuration to: " + values);
12410 }
12411
12412 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12413
12414 if (values.locale != null) {
12415 saveLocaleLocked(values.locale,
12416 !values.locale.equals(mConfiguration.locale),
12417 values.userSetLocale);
12418 }
12419
12420 mConfiguration = newConfig;
12421
12422 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12423 msg.obj = new Configuration(mConfiguration);
12424 mHandler.sendMessage(msg);
12425
12426 final int N = mLRUProcesses.size();
12427 for (int i=0; i<N; i++) {
12428 ProcessRecord app = mLRUProcesses.get(i);
12429 try {
12430 if (app.thread != null) {
12431 app.thread.scheduleConfigurationChanged(mConfiguration);
12432 }
12433 } catch (Exception e) {
12434 }
12435 }
12436 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12437 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12438 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012439
12440 AttributeCache ac = AttributeCache.instance();
12441 if (ac != null) {
12442 ac.updateConfiguration(mConfiguration);
12443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012444 }
12445 }
12446
12447 if (changes != 0 && starting == null) {
12448 // If the configuration changed, and the caller is not already
12449 // in the process of starting an activity, then find the top
12450 // activity to check if its configuration needs to change.
12451 starting = topRunningActivityLocked(null);
12452 }
12453
12454 if (starting != null) {
12455 kept = ensureActivityConfigurationLocked(starting, changes);
12456 if (kept) {
12457 // If this didn't result in the starting activity being
12458 // destroyed, then we need to make sure at this point that all
12459 // other activities are made visible.
12460 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12461 + ", ensuring others are correct.");
12462 ensureActivitiesVisibleLocked(starting, changes);
12463 }
12464 }
12465
12466 return kept;
12467 }
12468
12469 private final boolean relaunchActivityLocked(HistoryRecord r,
12470 int changes, boolean andResume) {
12471 List<ResultInfo> results = null;
12472 List<Intent> newIntents = null;
12473 if (andResume) {
12474 results = r.results;
12475 newIntents = r.newIntents;
12476 }
12477 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12478 + " with results=" + results + " newIntents=" + newIntents
12479 + " andResume=" + andResume);
12480 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12481 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12482 r.task.taskId, r.shortComponentName);
12483
12484 r.startFreezingScreenLocked(r.app, 0);
12485
12486 try {
12487 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12488 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12489 changes, !andResume);
12490 // Note: don't need to call pauseIfSleepingLocked() here, because
12491 // the caller will only pass in 'andResume' if this activity is
12492 // currently resumed, which implies we aren't sleeping.
12493 } catch (RemoteException e) {
12494 return false;
12495 }
12496
12497 if (andResume) {
12498 r.results = null;
12499 r.newIntents = null;
12500 }
12501
12502 return true;
12503 }
12504
12505 /**
12506 * Make sure the given activity matches the current configuration. Returns
12507 * false if the activity had to be destroyed. Returns true if the
12508 * configuration is the same, or the activity will remain running as-is
12509 * for whatever reason. Ensures the HistoryRecord is updated with the
12510 * correct configuration and all other bookkeeping is handled.
12511 */
12512 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12513 int globalChanges) {
12514 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12515
12516 // Short circuit: if the two configurations are the exact same
12517 // object (the common case), then there is nothing to do.
12518 Configuration newConfig = mConfiguration;
12519 if (r.configuration == newConfig) {
12520 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12521 return true;
12522 }
12523
12524 // We don't worry about activities that are finishing.
12525 if (r.finishing) {
12526 if (DEBUG_SWITCH) Log.i(TAG,
12527 "Configuration doesn't matter in finishing " + r);
12528 r.stopFreezingScreenLocked(false);
12529 return true;
12530 }
12531
12532 // Okay we now are going to make this activity have the new config.
12533 // But then we need to figure out how it needs to deal with that.
12534 Configuration oldConfig = r.configuration;
12535 r.configuration = newConfig;
12536
12537 // If the activity isn't currently running, just leave the new
12538 // configuration and it will pick that up next time it starts.
12539 if (r.app == null || r.app.thread == null) {
12540 if (DEBUG_SWITCH) Log.i(TAG,
12541 "Configuration doesn't matter not running " + r);
12542 r.stopFreezingScreenLocked(false);
12543 return true;
12544 }
12545
12546 // If the activity isn't persistent, there is a chance we will
12547 // need to restart it.
12548 if (!r.persistent) {
12549
12550 // Figure out what has changed between the two configurations.
12551 int changes = oldConfig.diff(newConfig);
12552 if (DEBUG_SWITCH) {
12553 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12554 + Integer.toHexString(changes) + ", handles=0x"
12555 + Integer.toHexString(r.info.configChanges));
12556 }
12557 if ((changes&(~r.info.configChanges)) != 0) {
12558 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12559 r.configChangeFlags |= changes;
12560 r.startFreezingScreenLocked(r.app, globalChanges);
12561 if (r.app == null || r.app.thread == null) {
12562 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12563 destroyActivityLocked(r, true);
12564 } else if (r.state == ActivityState.PAUSING) {
12565 // A little annoying: we are waiting for this activity to
12566 // finish pausing. Let's not do anything now, but just
12567 // flag that it needs to be restarted when done pausing.
12568 r.configDestroy = true;
12569 return true;
12570 } else if (r.state == ActivityState.RESUMED) {
12571 // Try to optimize this case: the configuration is changing
12572 // and we need to restart the top, resumed activity.
12573 // Instead of doing the normal handshaking, just say
12574 // "restart!".
12575 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12576 relaunchActivityLocked(r, r.configChangeFlags, true);
12577 r.configChangeFlags = 0;
12578 } else {
12579 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12580 relaunchActivityLocked(r, r.configChangeFlags, false);
12581 r.configChangeFlags = 0;
12582 }
12583
12584 // All done... tell the caller we weren't able to keep this
12585 // activity around.
12586 return false;
12587 }
12588 }
12589
12590 // Default case: the activity can handle this new configuration, so
12591 // hand it over. Note that we don't need to give it the new
12592 // configuration, since we always send configuration changes to all
12593 // process when they happen so it can just use whatever configuration
12594 // it last got.
12595 if (r.app != null && r.app.thread != null) {
12596 try {
12597 r.app.thread.scheduleActivityConfigurationChanged(r);
12598 } catch (RemoteException e) {
12599 // If process died, whatever.
12600 }
12601 }
12602 r.stopFreezingScreenLocked(false);
12603
12604 return true;
12605 }
12606
12607 /**
12608 * Save the locale. You must be inside a synchronized (this) block.
12609 */
12610 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12611 if(isDiff) {
12612 SystemProperties.set("user.language", l.getLanguage());
12613 SystemProperties.set("user.region", l.getCountry());
12614 }
12615
12616 if(isPersist) {
12617 SystemProperties.set("persist.sys.language", l.getLanguage());
12618 SystemProperties.set("persist.sys.country", l.getCountry());
12619 SystemProperties.set("persist.sys.localevar", l.getVariant());
12620 }
12621 }
12622
12623 // =========================================================
12624 // LIFETIME MANAGEMENT
12625 // =========================================================
12626
12627 private final int computeOomAdjLocked(
12628 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12629 if (mAdjSeq == app.adjSeq) {
12630 // This adjustment has already been computed.
12631 return app.curAdj;
12632 }
12633
12634 if (app.thread == null) {
12635 app.adjSeq = mAdjSeq;
12636 return (app.curAdj=EMPTY_APP_ADJ);
12637 }
12638
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012639 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12640 // The max adjustment doesn't allow this app to be anything
12641 // below foreground, so it is not worth doing work for it.
12642 app.adjType = "fixed";
12643 app.adjSeq = mAdjSeq;
12644 app.curRawAdj = app.maxAdj;
12645 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12646 return (app.curAdj=app.maxAdj);
12647 }
12648
12649 app.adjSource = null;
12650 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012651
The Android Open Source Project4df24232009-03-05 14:34:35 -080012652 // Determine the importance of the process, starting with most
12653 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012654 int adj;
12655 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012656 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012657 // The last app on the list is the foreground app.
12658 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012659 app.adjType = "top";
12660 } else if (app.instrumentationClass != null) {
12661 // Don't want to kill running instrumentation.
12662 adj = FOREGROUND_APP_ADJ;
12663 app.adjType = "instr";
12664 } else if (app.persistentActivities > 0) {
12665 // Special persistent activities... shouldn't be used these days.
12666 adj = FOREGROUND_APP_ADJ;
12667 app.adjType = "pers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012668 } else if (app.curReceiver != null ||
12669 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12670 // An app that is currently receiving a broadcast also
12671 // counts as being in the foreground.
12672 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012673 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012674 } else if (app.executingServices.size() > 0) {
12675 // An app that is currently executing a service callback also
12676 // counts as being in the foreground.
12677 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012678 app.adjType = "exec-service";
12679 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012680 // The user is aware of this app, so make it visible.
12681 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012682 app.adjType = "foreground-service";
12683 } else if (app.forcingToForeground != null) {
12684 // The user is aware of this app, so make it visible.
12685 adj = VISIBLE_APP_ADJ;
12686 app.adjType = "force-foreground";
12687 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012688 } else if (app == mHomeProcess) {
12689 // This process is hosting what we currently consider to be the
12690 // home app, so we don't want to let it go into the background.
12691 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012692 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012693 } else if ((N=app.activities.size()) != 0) {
12694 // This app is in the background with paused activities.
12695 adj = hiddenAdj;
12696 for (int j=0; j<N; j++) {
12697 if (((HistoryRecord)app.activities.get(j)).visible) {
12698 // This app has a visible activity!
12699 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012700 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012701 break;
12702 }
12703 }
12704 } else {
12705 // A very not-needed process.
12706 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012707 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012708 }
12709
The Android Open Source Project4df24232009-03-05 14:34:35 -080012710 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012711 // there are applications dependent on our services or providers, but
12712 // this gives us a baseline and makes sure we don't get into an
12713 // infinite recursion.
12714 app.adjSeq = mAdjSeq;
12715 app.curRawAdj = adj;
12716 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12717
Christopher Tate6fa95972009-06-05 18:43:55 -070012718 if (mBackupTarget != null && app == mBackupTarget.app) {
12719 // If possible we want to avoid killing apps while they're being backed up
12720 if (adj > BACKUP_APP_ADJ) {
12721 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12722 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012723 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012724 }
12725 }
12726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012727 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12728 // If this process has active services running in it, we would
12729 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012730 // application from running. By default we put the process in
12731 // with the rest of the background processes; as we scan through
12732 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012733 if (adj > hiddenAdj) {
12734 adj = hiddenAdj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012735 app.adjType = "services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012736 }
12737 final long now = SystemClock.uptimeMillis();
12738 // This process is more important if the top activity is
12739 // bound to the service.
12740 Iterator jt = app.services.iterator();
12741 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12742 ServiceRecord s = (ServiceRecord)jt.next();
12743 if (s.startRequested) {
12744 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12745 // This service has seen some activity within
12746 // recent memory, so we will keep its process ahead
12747 // of the background processes.
12748 if (adj > SECONDARY_SERVER_ADJ) {
12749 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012750 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012751 }
12752 }
12753 }
12754 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12755 Iterator<ConnectionRecord> kt
12756 = s.connections.values().iterator();
12757 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12758 // XXX should compute this based on the max of
12759 // all connected clients.
12760 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012761 if (cr.binding.client == app) {
12762 // Binding to ourself is not interesting.
12763 continue;
12764 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012765 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12766 ProcessRecord client = cr.binding.client;
12767 int myHiddenAdj = hiddenAdj;
12768 if (myHiddenAdj > client.hiddenAdj) {
12769 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12770 myHiddenAdj = client.hiddenAdj;
12771 } else {
12772 myHiddenAdj = VISIBLE_APP_ADJ;
12773 }
12774 }
12775 int clientAdj = computeOomAdjLocked(
12776 client, myHiddenAdj, TOP_APP);
12777 if (adj > clientAdj) {
12778 adj = clientAdj > VISIBLE_APP_ADJ
12779 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012780 app.adjType = "service";
12781 app.adjSource = cr.binding.client;
12782 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012783 }
12784 }
12785 HistoryRecord a = cr.activity;
12786 //if (a != null) {
12787 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12788 //}
12789 if (a != null && adj > FOREGROUND_APP_ADJ &&
12790 (a.state == ActivityState.RESUMED
12791 || a.state == ActivityState.PAUSING)) {
12792 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012793 app.adjType = "service";
12794 app.adjSource = a;
12795 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012796 }
12797 }
12798 }
12799 }
12800 }
12801
12802 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12803 // If this process has published any content providers, then
12804 // its adjustment makes it at least as important as any of the
12805 // processes using those providers, and no less important than
12806 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12807 if (adj > CONTENT_PROVIDER_ADJ) {
12808 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012809 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012810 }
12811 Iterator jt = app.pubProviders.values().iterator();
12812 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12813 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12814 if (cpr.clients.size() != 0) {
12815 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12816 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12817 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012818 if (client == app) {
12819 // Being our own client is not interesting.
12820 continue;
12821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012822 int myHiddenAdj = hiddenAdj;
12823 if (myHiddenAdj > client.hiddenAdj) {
12824 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12825 myHiddenAdj = client.hiddenAdj;
12826 } else {
12827 myHiddenAdj = FOREGROUND_APP_ADJ;
12828 }
12829 }
12830 int clientAdj = computeOomAdjLocked(
12831 client, myHiddenAdj, TOP_APP);
12832 if (adj > clientAdj) {
12833 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012834 ? clientAdj : FOREGROUND_APP_ADJ;
12835 app.adjType = "provider";
12836 app.adjSource = client;
12837 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012838 }
12839 }
12840 }
12841 // If the provider has external (non-framework) process
12842 // dependencies, ensure that its adjustment is at least
12843 // FOREGROUND_APP_ADJ.
12844 if (cpr.externals != 0) {
12845 if (adj > FOREGROUND_APP_ADJ) {
12846 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012847 app.adjType = "provider";
12848 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012849 }
12850 }
12851 }
12852 }
12853
12854 app.curRawAdj = adj;
12855
12856 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12857 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12858 if (adj > app.maxAdj) {
12859 adj = app.maxAdj;
12860 }
12861
12862 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012863 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012864 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12865 : Process.THREAD_GROUP_DEFAULT;
12866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012867 return adj;
12868 }
12869
12870 /**
12871 * Ask a given process to GC right now.
12872 */
12873 final void performAppGcLocked(ProcessRecord app) {
12874 try {
12875 app.lastRequestedGc = SystemClock.uptimeMillis();
12876 if (app.thread != null) {
12877 app.thread.processInBackground();
12878 }
12879 } catch (Exception e) {
12880 // whatever.
12881 }
12882 }
12883
12884 /**
12885 * Returns true if things are idle enough to perform GCs.
12886 */
12887 private final boolean canGcNow() {
12888 return mParallelBroadcasts.size() == 0
12889 && mOrderedBroadcasts.size() == 0
12890 && (mSleeping || (mResumedActivity != null &&
12891 mResumedActivity.idle));
12892 }
12893
12894 /**
12895 * Perform GCs on all processes that are waiting for it, but only
12896 * if things are idle.
12897 */
12898 final void performAppGcsLocked() {
12899 final int N = mProcessesToGc.size();
12900 if (N <= 0) {
12901 return;
12902 }
12903 if (canGcNow()) {
12904 while (mProcessesToGc.size() > 0) {
12905 ProcessRecord proc = mProcessesToGc.remove(0);
12906 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12907 // To avoid spamming the system, we will GC processes one
12908 // at a time, waiting a few seconds between each.
12909 performAppGcLocked(proc);
12910 scheduleAppGcsLocked();
12911 return;
12912 }
12913 }
12914 }
12915 }
12916
12917 /**
12918 * If all looks good, perform GCs on all processes waiting for them.
12919 */
12920 final void performAppGcsIfAppropriateLocked() {
12921 if (canGcNow()) {
12922 performAppGcsLocked();
12923 return;
12924 }
12925 // Still not idle, wait some more.
12926 scheduleAppGcsLocked();
12927 }
12928
12929 /**
12930 * Schedule the execution of all pending app GCs.
12931 */
12932 final void scheduleAppGcsLocked() {
12933 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12934 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12935 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12936 }
12937
12938 /**
12939 * Set up to ask a process to GC itself. This will either do it
12940 * immediately, or put it on the list of processes to gc the next
12941 * time things are idle.
12942 */
12943 final void scheduleAppGcLocked(ProcessRecord app) {
12944 long now = SystemClock.uptimeMillis();
12945 if ((app.lastRequestedGc+5000) > now) {
12946 return;
12947 }
12948 if (!mProcessesToGc.contains(app)) {
12949 mProcessesToGc.add(app);
12950 scheduleAppGcsLocked();
12951 }
12952 }
12953
12954 private final boolean updateOomAdjLocked(
12955 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12956 app.hiddenAdj = hiddenAdj;
12957
12958 if (app.thread == null) {
12959 return true;
12960 }
12961
12962 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12963
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012964 if (app.pid != 0 && app.pid != MY_PID) {
12965 if (app.curRawAdj != app.setRawAdj) {
12966 if (app.curRawAdj > FOREGROUND_APP_ADJ
12967 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12968 // If this app is transitioning from foreground to
12969 // non-foreground, have it do a gc.
12970 scheduleAppGcLocked(app);
12971 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12972 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12973 // Likewise do a gc when an app is moving in to the
12974 // background (such as a service stopping).
12975 scheduleAppGcLocked(app);
12976 }
12977 app.setRawAdj = app.curRawAdj;
12978 }
12979 if (adj != app.setAdj) {
12980 if (Process.setOomAdj(app.pid, adj)) {
12981 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12982 TAG, "Set app " + app.processName +
12983 " oom adj to " + adj);
12984 app.setAdj = adj;
12985 } else {
12986 return false;
12987 }
12988 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012989 if (app.setSchedGroup != app.curSchedGroup) {
12990 app.setSchedGroup = app.curSchedGroup;
12991 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12992 "Setting process group of " + app.processName
12993 + " to " + app.curSchedGroup);
12994 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012995 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012996 try {
12997 Process.setProcessGroup(app.pid, app.curSchedGroup);
12998 } catch (Exception e) {
12999 Log.w(TAG, "Failed setting process group of " + app.pid
13000 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013001 e.printStackTrace();
13002 } finally {
13003 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013004 }
13005 }
13006 if (false) {
13007 if (app.thread != null) {
13008 try {
13009 app.thread.setSchedulingGroup(app.curSchedGroup);
13010 } catch (RemoteException e) {
13011 }
13012 }
13013 }
13014 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013015 }
13016
13017 return true;
13018 }
13019
13020 private final HistoryRecord resumedAppLocked() {
13021 HistoryRecord resumedActivity = mResumedActivity;
13022 if (resumedActivity == null || resumedActivity.app == null) {
13023 resumedActivity = mPausingActivity;
13024 if (resumedActivity == null || resumedActivity.app == null) {
13025 resumedActivity = topRunningActivityLocked(null);
13026 }
13027 }
13028 return resumedActivity;
13029 }
13030
13031 private final boolean updateOomAdjLocked(ProcessRecord app) {
13032 final HistoryRecord TOP_ACT = resumedAppLocked();
13033 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13034 int curAdj = app.curAdj;
13035 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13036 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13037
13038 mAdjSeq++;
13039
13040 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13041 if (res) {
13042 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13043 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13044 if (nowHidden != wasHidden) {
13045 // Changed to/from hidden state, so apps after it in the LRU
13046 // list may also be changed.
13047 updateOomAdjLocked();
13048 }
13049 }
13050 return res;
13051 }
13052
13053 private final boolean updateOomAdjLocked() {
13054 boolean didOomAdj = true;
13055 final HistoryRecord TOP_ACT = resumedAppLocked();
13056 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13057
13058 if (false) {
13059 RuntimeException e = new RuntimeException();
13060 e.fillInStackTrace();
13061 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13062 }
13063
13064 mAdjSeq++;
13065
13066 // First try updating the OOM adjustment for each of the
13067 // application processes based on their current state.
13068 int i = mLRUProcesses.size();
13069 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13070 while (i > 0) {
13071 i--;
13072 ProcessRecord app = mLRUProcesses.get(i);
13073 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13074 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13075 && app.curAdj == curHiddenAdj) {
13076 curHiddenAdj++;
13077 }
13078 } else {
13079 didOomAdj = false;
13080 }
13081 }
13082
13083 // todo: for now pretend like OOM ADJ didn't work, because things
13084 // aren't behaving as expected on Linux -- it's not killing processes.
13085 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13086 }
13087
13088 private final void trimApplications() {
13089 synchronized (this) {
13090 int i;
13091
13092 // First remove any unused application processes whose package
13093 // has been removed.
13094 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13095 final ProcessRecord app = mRemovedProcesses.get(i);
13096 if (app.activities.size() == 0
13097 && app.curReceiver == null && app.services.size() == 0) {
13098 Log.i(
13099 TAG, "Exiting empty application process "
13100 + app.processName + " ("
13101 + (app.thread != null ? app.thread.asBinder() : null)
13102 + ")\n");
13103 if (app.pid > 0 && app.pid != MY_PID) {
13104 Process.killProcess(app.pid);
13105 } else {
13106 try {
13107 app.thread.scheduleExit();
13108 } catch (Exception e) {
13109 // Ignore exceptions.
13110 }
13111 }
13112 cleanUpApplicationRecordLocked(app, false, -1);
13113 mRemovedProcesses.remove(i);
13114
13115 if (app.persistent) {
13116 if (app.persistent) {
13117 addAppLocked(app.info);
13118 }
13119 }
13120 }
13121 }
13122
13123 // Now try updating the OOM adjustment for each of the
13124 // application processes based on their current state.
13125 // If the setOomAdj() API is not supported, then go with our
13126 // back-up plan...
13127 if (!updateOomAdjLocked()) {
13128
13129 // Count how many processes are running services.
13130 int numServiceProcs = 0;
13131 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13132 final ProcessRecord app = mLRUProcesses.get(i);
13133
13134 if (app.persistent || app.services.size() != 0
13135 || app.curReceiver != null
13136 || app.persistentActivities > 0) {
13137 // Don't count processes holding services against our
13138 // maximum process count.
13139 if (localLOGV) Log.v(
13140 TAG, "Not trimming app " + app + " with services: "
13141 + app.services);
13142 numServiceProcs++;
13143 }
13144 }
13145
13146 int curMaxProcs = mProcessLimit;
13147 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13148 if (mAlwaysFinishActivities) {
13149 curMaxProcs = 1;
13150 }
13151 curMaxProcs += numServiceProcs;
13152
13153 // Quit as many processes as we can to get down to the desired
13154 // process count. First remove any processes that no longer
13155 // have activites running in them.
13156 for ( i=0;
13157 i<mLRUProcesses.size()
13158 && mLRUProcesses.size() > curMaxProcs;
13159 i++) {
13160 final ProcessRecord app = mLRUProcesses.get(i);
13161 // Quit an application only if it is not currently
13162 // running any activities.
13163 if (!app.persistent && app.activities.size() == 0
13164 && app.curReceiver == null && app.services.size() == 0) {
13165 Log.i(
13166 TAG, "Exiting empty application process "
13167 + app.processName + " ("
13168 + (app.thread != null ? app.thread.asBinder() : null)
13169 + ")\n");
13170 if (app.pid > 0 && app.pid != MY_PID) {
13171 Process.killProcess(app.pid);
13172 } else {
13173 try {
13174 app.thread.scheduleExit();
13175 } catch (Exception e) {
13176 // Ignore exceptions.
13177 }
13178 }
13179 // todo: For now we assume the application is not buggy
13180 // or evil, and will quit as a result of our request.
13181 // Eventually we need to drive this off of the death
13182 // notification, and kill the process if it takes too long.
13183 cleanUpApplicationRecordLocked(app, false, i);
13184 i--;
13185 }
13186 }
13187
13188 // If we still have too many processes, now from the least
13189 // recently used process we start finishing activities.
13190 if (Config.LOGV) Log.v(
13191 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13192 " of " + curMaxProcs + " processes");
13193 for ( i=0;
13194 i<mLRUProcesses.size()
13195 && mLRUProcesses.size() > curMaxProcs;
13196 i++) {
13197 final ProcessRecord app = mLRUProcesses.get(i);
13198 // Quit the application only if we have a state saved for
13199 // all of its activities.
13200 boolean canQuit = !app.persistent && app.curReceiver == null
13201 && app.services.size() == 0
13202 && app.persistentActivities == 0;
13203 int NUMA = app.activities.size();
13204 int j;
13205 if (Config.LOGV) Log.v(
13206 TAG, "Looking to quit " + app.processName);
13207 for (j=0; j<NUMA && canQuit; j++) {
13208 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13209 if (Config.LOGV) Log.v(
13210 TAG, " " + r.intent.getComponent().flattenToShortString()
13211 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13212 canQuit = (r.haveState || !r.stateNotNeeded)
13213 && !r.visible && r.stopped;
13214 }
13215 if (canQuit) {
13216 // Finish all of the activities, and then the app itself.
13217 for (j=0; j<NUMA; j++) {
13218 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13219 if (!r.finishing) {
13220 destroyActivityLocked(r, false);
13221 }
13222 r.resultTo = null;
13223 }
13224 Log.i(TAG, "Exiting application process "
13225 + app.processName + " ("
13226 + (app.thread != null ? app.thread.asBinder() : null)
13227 + ")\n");
13228 if (app.pid > 0 && app.pid != MY_PID) {
13229 Process.killProcess(app.pid);
13230 } else {
13231 try {
13232 app.thread.scheduleExit();
13233 } catch (Exception e) {
13234 // Ignore exceptions.
13235 }
13236 }
13237 // todo: For now we assume the application is not buggy
13238 // or evil, and will quit as a result of our request.
13239 // Eventually we need to drive this off of the death
13240 // notification, and kill the process if it takes too long.
13241 cleanUpApplicationRecordLocked(app, false, i);
13242 i--;
13243 //dump();
13244 }
13245 }
13246
13247 }
13248
13249 int curMaxActivities = MAX_ACTIVITIES;
13250 if (mAlwaysFinishActivities) {
13251 curMaxActivities = 1;
13252 }
13253
13254 // Finally, if there are too many activities now running, try to
13255 // finish as many as we can to get back down to the limit.
13256 for ( i=0;
13257 i<mLRUActivities.size()
13258 && mLRUActivities.size() > curMaxActivities;
13259 i++) {
13260 final HistoryRecord r
13261 = (HistoryRecord)mLRUActivities.get(i);
13262
13263 // We can finish this one if we have its icicle saved and
13264 // it is not persistent.
13265 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13266 && r.stopped && !r.persistent && !r.finishing) {
13267 final int origSize = mLRUActivities.size();
13268 destroyActivityLocked(r, true);
13269
13270 // This will remove it from the LRU list, so keep
13271 // our index at the same value. Note that this check to
13272 // see if the size changes is just paranoia -- if
13273 // something unexpected happens, we don't want to end up
13274 // in an infinite loop.
13275 if (origSize > mLRUActivities.size()) {
13276 i--;
13277 }
13278 }
13279 }
13280 }
13281 }
13282
13283 /** This method sends the specified signal to each of the persistent apps */
13284 public void signalPersistentProcesses(int sig) throws RemoteException {
13285 if (sig != Process.SIGNAL_USR1) {
13286 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13287 }
13288
13289 synchronized (this) {
13290 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13291 != PackageManager.PERMISSION_GRANTED) {
13292 throw new SecurityException("Requires permission "
13293 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13294 }
13295
13296 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13297 ProcessRecord r = mLRUProcesses.get(i);
13298 if (r.thread != null && r.persistent) {
13299 Process.sendSignal(r.pid, sig);
13300 }
13301 }
13302 }
13303 }
13304
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013305 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013306 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013307
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013308 try {
13309 synchronized (this) {
13310 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13311 // its own permission.
13312 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13313 != PackageManager.PERMISSION_GRANTED) {
13314 throw new SecurityException("Requires permission "
13315 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013316 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013317
13318 if (start && fd == null) {
13319 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013320 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013321
13322 ProcessRecord proc = null;
13323 try {
13324 int pid = Integer.parseInt(process);
13325 synchronized (mPidsSelfLocked) {
13326 proc = mPidsSelfLocked.get(pid);
13327 }
13328 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013329 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013330
13331 if (proc == null) {
13332 HashMap<String, SparseArray<ProcessRecord>> all
13333 = mProcessNames.getMap();
13334 SparseArray<ProcessRecord> procs = all.get(process);
13335 if (procs != null && procs.size() > 0) {
13336 proc = procs.valueAt(0);
13337 }
13338 }
13339
13340 if (proc == null || proc.thread == null) {
13341 throw new IllegalArgumentException("Unknown process: " + process);
13342 }
13343
13344 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13345 if (isSecure) {
13346 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13347 throw new SecurityException("Process not debuggable: " + proc);
13348 }
13349 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013350
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013351 proc.thread.profilerControl(start, path, fd);
13352 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013353 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013354 }
13355 } catch (RemoteException e) {
13356 throw new IllegalStateException("Process disappeared");
13357 } finally {
13358 if (fd != null) {
13359 try {
13360 fd.close();
13361 } catch (IOException e) {
13362 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013363 }
13364 }
13365 }
13366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013367 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13368 public void monitor() {
13369 synchronized (this) { }
13370 }
13371}