blob: 6d04b6b7f846416842d0b283f26a98f2e2ef100b [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import com.android.server.IntentResolver;
21import com.android.server.ProcessMap;
22import com.android.server.ProcessStats;
23import com.android.server.SystemServer;
24import com.android.server.Watchdog;
25import com.android.server.WindowManagerService;
26
27import android.app.Activity;
28import android.app.ActivityManager;
29import android.app.ActivityManagerNative;
30import android.app.ActivityThread;
31import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020032import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.app.Dialog;
34import android.app.IActivityWatcher;
35import android.app.IApplicationThread;
36import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.app.IServiceConnection;
38import android.app.IThumbnailReceiver;
39import android.app.Instrumentation;
40import android.app.PendingIntent;
41import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070042import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020043import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.content.ComponentName;
45import android.content.ContentResolver;
46import android.content.Context;
47import android.content.Intent;
48import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070049import android.content.IIntentReceiver;
50import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.content.pm.ActivityInfo;
52import android.content.pm.ApplicationInfo;
53import android.content.pm.ConfigurationInfo;
54import android.content.pm.IPackageDataObserver;
55import android.content.pm.IPackageManager;
56import android.content.pm.InstrumentationInfo;
57import android.content.pm.PackageManager;
58import android.content.pm.ProviderInfo;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
61import android.content.res.Configuration;
62import android.graphics.Bitmap;
63import android.net.Uri;
Amith Yamasani32dbefd2009-06-19 09:21:17 -070064import android.os.BatteryStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.os.Binder;
66import android.os.Bundle;
67import android.os.Environment;
68import android.os.FileUtils;
69import android.os.Handler;
70import android.os.IBinder;
71import android.os.IPermissionController;
72import android.os.Looper;
73import android.os.Message;
74import android.os.Parcel;
75import android.os.ParcelFileDescriptor;
76import android.os.PowerManager;
77import android.os.Process;
78import android.os.RemoteException;
79import android.os.ServiceManager;
80import android.os.SystemClock;
81import android.os.SystemProperties;
82import android.provider.Checkin;
83import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020084import android.server.data.CrashData;
85import android.server.data.StackTraceElementData;
86import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.text.TextUtils;
88import android.util.Config;
89import android.util.EventLog;
90import android.util.Log;
91import android.util.PrintWriterPrinter;
92import android.util.SparseArray;
93import android.view.Gravity;
94import android.view.LayoutInflater;
95import android.view.View;
96import android.view.WindowManager;
97import android.view.WindowManagerPolicy;
98
99import dalvik.system.Zygote;
100
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200101import java.io.ByteArrayInputStream;
102import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import java.io.File;
104import java.io.FileDescriptor;
105import java.io.FileInputStream;
106import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200107import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.PrintWriter;
109import java.lang.IllegalStateException;
110import java.lang.ref.WeakReference;
111import java.util.ArrayList;
112import java.util.HashMap;
113import java.util.HashSet;
114import java.util.Iterator;
115import java.util.List;
116import java.util.Locale;
117import java.util.Map;
118
119public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
120 static final String TAG = "ActivityManager";
121 static final boolean DEBUG = false;
122 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
123 static final boolean DEBUG_SWITCH = localLOGV || false;
124 static final boolean DEBUG_TASKS = localLOGV || false;
125 static final boolean DEBUG_PAUSE = localLOGV || false;
126 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
127 static final boolean DEBUG_TRANSITION = localLOGV || false;
128 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700129 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 static final boolean DEBUG_SERVICE = localLOGV || false;
131 static final boolean DEBUG_VISBILITY = localLOGV || false;
132 static final boolean DEBUG_PROCESSES = localLOGV || false;
133 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700134 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700135 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean VALIDATE_TOKENS = false;
137 static final boolean SHOW_ACTIVITY_START_TIME = true;
138
139 // Control over CPU and battery monitoring.
140 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
141 static final boolean MONITOR_CPU_USAGE = true;
142 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
143 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
144 static final boolean MONITOR_THREAD_CPU_USAGE = false;
145
146 // Event log tags
147 static final int LOG_CONFIGURATION_CHANGED = 2719;
148 static final int LOG_CPU = 2721;
149 static final int LOG_AM_FINISH_ACTIVITY = 30001;
150 static final int LOG_TASK_TO_FRONT = 30002;
151 static final int LOG_AM_NEW_INTENT = 30003;
152 static final int LOG_AM_CREATE_TASK = 30004;
153 static final int LOG_AM_CREATE_ACTIVITY = 30005;
154 static final int LOG_AM_RESTART_ACTIVITY = 30006;
155 static final int LOG_AM_RESUME_ACTIVITY = 30007;
156 static final int LOG_ANR = 30008;
157 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
158 static final int LOG_AM_PROCESS_BOUND = 30010;
159 static final int LOG_AM_PROCESS_DIED = 30011;
160 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
161 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
162 static final int LOG_AM_PROCESS_START = 30014;
163 static final int LOG_AM_PROCESS_BAD = 30015;
164 static final int LOG_AM_PROCESS_GOOD = 30016;
165 static final int LOG_AM_LOW_MEMORY = 30017;
166 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
167 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
168 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
169 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
170 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
171 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
172 static final int LOG_AM_CREATE_SERVICE = 30030;
173 static final int LOG_AM_DESTROY_SERVICE = 30031;
174 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
175 static final int LOG_AM_DROP_PROCESS = 30033;
176 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
177 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
178 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
179
180 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
181 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
182
Dianne Hackborn1655be42009-05-08 14:29:01 -0700183 // The flags that are set for all calls we make to the package manager.
184 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700185 | PackageManager.GET_SUPPORTS_DENSITIES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 private static final String SYSTEM_SECURE = "ro.secure";
188
189 // This is the maximum number of application processes we would like
190 // to have running. Due to the asynchronous nature of things, we can
191 // temporarily go beyond this limit.
192 static final int MAX_PROCESSES = 2;
193
194 // Set to false to leave processes running indefinitely, relying on
195 // the kernel killing them as resources are required.
196 static final boolean ENFORCE_PROCESS_LIMIT = false;
197
198 // This is the maximum number of activities that we would like to have
199 // running at a given time.
200 static final int MAX_ACTIVITIES = 20;
201
202 // Maximum number of recent tasks that we can remember.
203 static final int MAX_RECENT_TASKS = 20;
204
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700205 // Amount of time after a call to stopAppSwitches() during which we will
206 // prevent further untrusted switches from happening.
207 static final long APP_SWITCH_DELAY_TIME = 5*1000;
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 // How long until we reset a task when the user returns to it. Currently
210 // 30 minutes.
211 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
212
213 // Set to true to disable the icon that is shown while a new activity
214 // is being started.
215 static final boolean SHOW_APP_STARTING_ICON = true;
216
217 // How long we wait until giving up on the last activity to pause. This
218 // is short because it directly impacts the responsiveness of starting the
219 // next activity.
220 static final int PAUSE_TIMEOUT = 500;
221
222 /**
223 * How long we can hold the launch wake lock before giving up.
224 */
225 static final int LAUNCH_TIMEOUT = 10*1000;
226
227 // How long we wait for a launched process to attach to the activity manager
228 // before we decide it's never going to come up for real.
229 static final int PROC_START_TIMEOUT = 10*1000;
230
231 // How long we wait until giving up on the last activity telling us it
232 // is idle.
233 static final int IDLE_TIMEOUT = 10*1000;
234
235 // How long to wait after going idle before forcing apps to GC.
236 static final int GC_TIMEOUT = 5*1000;
237
238 // How long we wait until giving up on an activity telling us it has
239 // finished destroying itself.
240 static final int DESTROY_TIMEOUT = 10*1000;
241
242 // How long we allow a receiver to run before giving up on it.
243 static final int BROADCAST_TIMEOUT = 10*1000;
244
245 // How long we wait for a service to finish executing.
246 static final int SERVICE_TIMEOUT = 20*1000;
247
248 // How long a service needs to be running until restarting its process
249 // is no longer considered to be a relaunch of the service.
250 static final int SERVICE_RESTART_DURATION = 5*1000;
251
252 // Maximum amount of time for there to be no activity on a service before
253 // we consider it non-essential and allow its process to go on the
254 // LRU background list.
255 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
256
257 // How long we wait until we timeout on key dispatching.
258 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
259
260 // The minimum time we allow between crashes, for us to consider this
261 // application to be bad and stop and its services and reject broadcasts.
262 static final int MIN_CRASH_INTERVAL = 60*1000;
263
264 // How long we wait until we timeout on key dispatching during instrumentation.
265 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
266
267 // OOM adjustments for processes in various states:
268
269 // This is a process without anything currently running in it. Definitely
270 // the first to go! Value set in system/rootdir/init.rc on startup.
271 // This value is initalized in the constructor, careful when refering to
272 // this static variable externally.
273 static int EMPTY_APP_ADJ;
274
275 // This is a process with a content provider that does not have any clients
276 // attached to it. If it did have any clients, its adjustment would be the
277 // one for the highest-priority of those processes.
278 static int CONTENT_PROVIDER_ADJ;
279
280 // This is a process only hosting activities that are not visible,
281 // so it can be killed without any disruption. Value set in
282 // system/rootdir/init.rc on startup.
283 final int HIDDEN_APP_MAX_ADJ;
284 static int HIDDEN_APP_MIN_ADJ;
285
The Android Open Source Project4df24232009-03-05 14:34:35 -0800286 // This is a process holding the home application -- we want to try
287 // avoiding killing it, even if it would normally be in the background,
288 // because the user interacts with it so much.
289 final int HOME_APP_ADJ;
290
Christopher Tate6fa95972009-06-05 18:43:55 -0700291 // This is a process currently hosting a backup operation. Killing it
292 // is not entirely fatal but is generally a bad idea.
293 final int BACKUP_APP_ADJ;
294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 // This is a process holding a secondary server -- killing it will not
296 // have much of an impact as far as the user is concerned. Value set in
297 // system/rootdir/init.rc on startup.
298 final int SECONDARY_SERVER_ADJ;
299
300 // This is a process only hosting activities that are visible to the
301 // user, so we'd prefer they don't disappear. Value set in
302 // system/rootdir/init.rc on startup.
303 final int VISIBLE_APP_ADJ;
304
305 // This is the process running the current foreground app. We'd really
306 // rather not kill it! Value set in system/rootdir/init.rc on startup.
307 final int FOREGROUND_APP_ADJ;
308
309 // This is a process running a core server, such as telephony. Definitely
310 // don't want to kill it, but doing so is not completely fatal.
311 static final int CORE_SERVER_ADJ = -12;
312
313 // The system process runs at the default adjustment.
314 static final int SYSTEM_ADJ = -16;
315
316 // Memory pages are 4K.
317 static final int PAGE_SIZE = 4*1024;
318
319 // Corresponding memory levels for above adjustments.
320 final int EMPTY_APP_MEM;
321 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800322 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700323 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 final int SECONDARY_SERVER_MEM;
325 final int VISIBLE_APP_MEM;
326 final int FOREGROUND_APP_MEM;
327
328 final int MY_PID;
329
330 static final String[] EMPTY_STRING_ARRAY = new String[0];
331
332 enum ActivityState {
333 INITIALIZING,
334 RESUMED,
335 PAUSING,
336 PAUSED,
337 STOPPING,
338 STOPPED,
339 FINISHING,
340 DESTROYING,
341 DESTROYED
342 }
343
344 /**
345 * The back history of all previous (and possibly still
346 * running) activities. It contains HistoryRecord objects.
347 */
348 final ArrayList mHistory = new ArrayList();
349
350 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700351 * Description of a request to start a new activity, which has been held
352 * due to app switches being disabled.
353 */
354 class PendingActivityLaunch {
355 HistoryRecord r;
356 HistoryRecord sourceRecord;
357 Uri[] grantedUriPermissions;
358 int grantedMode;
359 boolean onlyIfNeeded;
360 }
361
362 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
363 = new ArrayList<PendingActivityLaunch>();
364
365 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 * List of all active broadcasts that are to be executed immediately
367 * (without waiting for another broadcast to finish). Currently this only
368 * contains broadcasts to registered receivers, to avoid spinning up
369 * a bunch of processes to execute IntentReceiver components.
370 */
371 final ArrayList<BroadcastRecord> mParallelBroadcasts
372 = new ArrayList<BroadcastRecord>();
373
374 /**
375 * List of all active broadcasts that are to be executed one at a time.
376 * The object at the top of the list is the currently activity broadcasts;
377 * those after it are waiting for the top to finish..
378 */
379 final ArrayList<BroadcastRecord> mOrderedBroadcasts
380 = new ArrayList<BroadcastRecord>();
381
382 /**
383 * Set when we current have a BROADCAST_INTENT_MSG in flight.
384 */
385 boolean mBroadcastsScheduled = false;
386
387 /**
388 * Set to indicate whether to issue an onUserLeaving callback when a
389 * newly launched activity is being brought in front of us.
390 */
391 boolean mUserLeaving = false;
392
393 /**
394 * When we are in the process of pausing an activity, before starting the
395 * next one, this variable holds the activity that is currently being paused.
396 */
397 HistoryRecord mPausingActivity = null;
398
399 /**
400 * Current activity that is resumed, or null if there is none.
401 */
402 HistoryRecord mResumedActivity = null;
403
404 /**
405 * Activity we have told the window manager to have key focus.
406 */
407 HistoryRecord mFocusedActivity = null;
408
409 /**
410 * This is the last activity that we put into the paused state. This is
411 * used to determine if we need to do an activity transition while sleeping,
412 * when we normally hold the top activity paused.
413 */
414 HistoryRecord mLastPausedActivity = null;
415
416 /**
417 * List of activities that are waiting for a new activity
418 * to become visible before completing whatever operation they are
419 * supposed to do.
420 */
421 final ArrayList mWaitingVisibleActivities = new ArrayList();
422
423 /**
424 * List of activities that are ready to be stopped, but waiting
425 * for the next activity to settle down before doing so. It contains
426 * HistoryRecord objects.
427 */
428 final ArrayList<HistoryRecord> mStoppingActivities
429 = new ArrayList<HistoryRecord>();
430
431 /**
432 * List of intents that were used to start the most recent tasks.
433 */
434 final ArrayList<TaskRecord> mRecentTasks
435 = new ArrayList<TaskRecord>();
436
437 /**
438 * List of activities that are ready to be finished, but waiting
439 * for the previous activity to settle down before doing so. It contains
440 * HistoryRecord objects.
441 */
442 final ArrayList mFinishingActivities = new ArrayList();
443
444 /**
445 * All of the applications we currently have running organized by name.
446 * The keys are strings of the application package name (as
447 * returned by the package manager), and the keys are ApplicationRecord
448 * objects.
449 */
450 final ProcessMap<ProcessRecord> mProcessNames
451 = new ProcessMap<ProcessRecord>();
452
453 /**
454 * The last time that various processes have crashed.
455 */
456 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
457
458 /**
459 * Set of applications that we consider to be bad, and will reject
460 * incoming broadcasts from (which the user has no control over).
461 * Processes are added to this set when they have crashed twice within
462 * a minimum amount of time; they are removed from it when they are
463 * later restarted (hopefully due to some user action). The value is the
464 * time it was added to the list.
465 */
466 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
467
468 /**
469 * All of the processes we currently have running organized by pid.
470 * The keys are the pid running the application.
471 *
472 * <p>NOTE: This object is protected by its own lock, NOT the global
473 * activity manager lock!
474 */
475 final SparseArray<ProcessRecord> mPidsSelfLocked
476 = new SparseArray<ProcessRecord>();
477
478 /**
479 * All of the processes that have been forced to be foreground. The key
480 * is the pid of the caller who requested it (we hold a death
481 * link on it).
482 */
483 abstract class ForegroundToken implements IBinder.DeathRecipient {
484 int pid;
485 IBinder token;
486 }
487 final SparseArray<ForegroundToken> mForegroundProcesses
488 = new SparseArray<ForegroundToken>();
489
490 /**
491 * List of records for processes that someone had tried to start before the
492 * system was ready. We don't start them at that point, but ensure they
493 * are started by the time booting is complete.
494 */
495 final ArrayList<ProcessRecord> mProcessesOnHold
496 = new ArrayList<ProcessRecord>();
497
498 /**
499 * List of records for processes that we have started and are waiting
500 * for them to call back. This is really only needed when running in
501 * single processes mode, in which case we do not have a unique pid for
502 * each process.
503 */
504 final ArrayList<ProcessRecord> mStartingProcesses
505 = new ArrayList<ProcessRecord>();
506
507 /**
508 * List of persistent applications that are in the process
509 * of being started.
510 */
511 final ArrayList<ProcessRecord> mPersistentStartingProcesses
512 = new ArrayList<ProcessRecord>();
513
514 /**
515 * Processes that are being forcibly torn down.
516 */
517 final ArrayList<ProcessRecord> mRemovedProcesses
518 = new ArrayList<ProcessRecord>();
519
520 /**
521 * List of running applications, sorted by recent usage.
522 * The first entry in the list is the least recently used.
523 * It contains ApplicationRecord objects. This list does NOT include
524 * any persistent application records (since we never want to exit them).
525 */
526 final ArrayList<ProcessRecord> mLRUProcesses
527 = new ArrayList<ProcessRecord>();
528
529 /**
530 * List of processes that should gc as soon as things are idle.
531 */
532 final ArrayList<ProcessRecord> mProcessesToGc
533 = new ArrayList<ProcessRecord>();
534
535 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800536 * This is the process holding what we currently consider to be
537 * the "home" activity.
538 */
539 private ProcessRecord mHomeProcess;
540
541 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 * List of running activities, sorted by recent usage.
543 * The first entry in the list is the least recently used.
544 * It contains HistoryRecord objects.
545 */
546 private final ArrayList mLRUActivities = new ArrayList();
547
548 /**
549 * Set of PendingResultRecord objects that are currently active.
550 */
551 final HashSet mPendingResultRecords = new HashSet();
552
553 /**
554 * Set of IntentSenderRecord objects that are currently active.
555 */
556 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
557 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
558
559 /**
560 * Intent broadcast that we have tried to start, but are
561 * waiting for its application's process to be created. We only
562 * need one (instead of a list) because we always process broadcasts
563 * one at a time, so no others can be started while waiting for this
564 * one.
565 */
566 BroadcastRecord mPendingBroadcast = null;
567
568 /**
569 * Keeps track of all IIntentReceivers that have been registered for
570 * broadcasts. Hash keys are the receiver IBinder, hash value is
571 * a ReceiverList.
572 */
573 final HashMap mRegisteredReceivers = new HashMap();
574
575 /**
576 * Resolver for broadcast intents to registered receivers.
577 * Holds BroadcastFilter (subclass of IntentFilter).
578 */
579 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
580 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
581 @Override
582 protected boolean allowFilterResult(
583 BroadcastFilter filter, List<BroadcastFilter> dest) {
584 IBinder target = filter.receiverList.receiver.asBinder();
585 for (int i=dest.size()-1; i>=0; i--) {
586 if (dest.get(i).receiverList.receiver.asBinder() == target) {
587 return false;
588 }
589 }
590 return true;
591 }
592 };
593
594 /**
595 * State of all active sticky broadcasts. Keys are the action of the
596 * sticky Intent, values are an ArrayList of all broadcasted intents with
597 * that action (which should usually be one).
598 */
599 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
600 new HashMap<String, ArrayList<Intent>>();
601
602 /**
603 * All currently running services.
604 */
605 final HashMap<ComponentName, ServiceRecord> mServices =
606 new HashMap<ComponentName, ServiceRecord>();
607
608 /**
609 * All currently running services indexed by the Intent used to start them.
610 */
611 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
612 new HashMap<Intent.FilterComparison, ServiceRecord>();
613
614 /**
615 * All currently bound service connections. Keys are the IBinder of
616 * the client's IServiceConnection.
617 */
618 final HashMap<IBinder, ConnectionRecord> mServiceConnections
619 = new HashMap<IBinder, ConnectionRecord>();
620
621 /**
622 * List of services that we have been asked to start,
623 * but haven't yet been able to. It is used to hold start requests
624 * while waiting for their corresponding application thread to get
625 * going.
626 */
627 final ArrayList<ServiceRecord> mPendingServices
628 = new ArrayList<ServiceRecord>();
629
630 /**
631 * List of services that are scheduled to restart following a crash.
632 */
633 final ArrayList<ServiceRecord> mRestartingServices
634 = new ArrayList<ServiceRecord>();
635
636 /**
637 * List of services that are in the process of being stopped.
638 */
639 final ArrayList<ServiceRecord> mStoppingServices
640 = new ArrayList<ServiceRecord>();
641
642 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700643 * Backup/restore process management
644 */
645 String mBackupAppName = null;
646 BackupRecord mBackupTarget = null;
647
648 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 * List of PendingThumbnailsRecord objects of clients who are still
650 * waiting to receive all of the thumbnails for a task.
651 */
652 final ArrayList mPendingThumbnails = new ArrayList();
653
654 /**
655 * List of HistoryRecord objects that have been finished and must
656 * still report back to a pending thumbnail receiver.
657 */
658 final ArrayList mCancelledThumbnails = new ArrayList();
659
660 /**
661 * All of the currently running global content providers. Keys are a
662 * string containing the provider name and values are a
663 * ContentProviderRecord object containing the data about it. Note
664 * that a single provider may be published under multiple names, so
665 * there may be multiple entries here for a single one in mProvidersByClass.
666 */
667 final HashMap mProvidersByName = new HashMap();
668
669 /**
670 * All of the currently running global content providers. Keys are a
671 * string containing the provider's implementation class and values are a
672 * ContentProviderRecord object containing the data about it.
673 */
674 final HashMap mProvidersByClass = new HashMap();
675
676 /**
677 * List of content providers who have clients waiting for them. The
678 * application is currently being launched and the provider will be
679 * removed from this list once it is published.
680 */
681 final ArrayList mLaunchingProviders = new ArrayList();
682
683 /**
684 * Global set of specific Uri permissions that have been granted.
685 */
686 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
687 = new SparseArray<HashMap<Uri, UriPermission>>();
688
689 /**
690 * Thread-local storage used to carry caller permissions over through
691 * indirect content-provider access.
692 * @see #ActivityManagerService.openContentUri()
693 */
694 private class Identity {
695 public int pid;
696 public int uid;
697
698 Identity(int _pid, int _uid) {
699 pid = _pid;
700 uid = _uid;
701 }
702 }
703 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
704
705 /**
706 * All information we have collected about the runtime performance of
707 * any user id that can impact battery performance.
708 */
709 final BatteryStatsService mBatteryStatsService;
710
711 /**
712 * information about component usage
713 */
714 final UsageStatsService mUsageStatsService;
715
716 /**
717 * Current configuration information. HistoryRecord objects are given
718 * a reference to this object to indicate which configuration they are
719 * currently running in, so this object must be kept immutable.
720 */
721 Configuration mConfiguration = new Configuration();
722
723 /**
724 * List of initialization arguments to pass to all processes when binding applications to them.
725 * For example, references to the commonly used services.
726 */
727 HashMap<String, IBinder> mAppBindArgs;
728
729 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700730 * Temporary to avoid allocations. Protected by main lock.
731 */
732 final StringBuilder mStringBuilder = new StringBuilder(256);
733
734 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 * Used to control how we initialize the service.
736 */
737 boolean mStartRunning = false;
738 ComponentName mTopComponent;
739 String mTopAction;
740 String mTopData;
741 boolean mSystemReady = false;
742 boolean mBooting = false;
743
744 Context mContext;
745
746 int mFactoryTest;
747
748 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700749 * The time at which we will allow normal application switches again,
750 * after a call to {@link #stopAppSwitches()}.
751 */
752 long mAppSwitchesAllowedTime;
753
754 /**
755 * This is set to true after the first switch after mAppSwitchesAllowedTime
756 * is set; any switches after that will clear the time.
757 */
758 boolean mDidAppSwitch;
759
760 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 * Set while we are wanting to sleep, to prevent any
762 * activities from being started/resumed.
763 */
764 boolean mSleeping = false;
765
766 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700767 * Set if we are shutting down the system, similar to sleeping.
768 */
769 boolean mShuttingDown = false;
770
771 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 * Set when the system is going to sleep, until we have
773 * successfully paused the current activity and released our wake lock.
774 * At that point the system is allowed to actually sleep.
775 */
776 PowerManager.WakeLock mGoingToSleep;
777
778 /**
779 * We don't want to allow the device to go to sleep while in the process
780 * of launching an activity. This is primarily to allow alarm intent
781 * receivers to launch an activity and get that to run before the device
782 * goes back to sleep.
783 */
784 PowerManager.WakeLock mLaunchingActivity;
785
786 /**
787 * Task identifier that activities are currently being started
788 * in. Incremented each time a new task is created.
789 * todo: Replace this with a TokenSpace class that generates non-repeating
790 * integers that won't wrap.
791 */
792 int mCurTask = 1;
793
794 /**
795 * Current sequence id for oom_adj computation traversal.
796 */
797 int mAdjSeq = 0;
798
799 /**
800 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
801 * is set, indicating the user wants processes started in such a way
802 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
803 * running in each process (thus no pre-initialized process, etc).
804 */
805 boolean mSimpleProcessManagement = false;
806
807 /**
808 * System monitoring: number of processes that died since the last
809 * N procs were started.
810 */
811 int[] mProcDeaths = new int[20];
812
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700813 /**
814 * This is set if we had to do a delayed dexopt of an app before launching
815 * it, to increasing the ANR timeouts in that case.
816 */
817 boolean mDidDexOpt;
818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 String mDebugApp = null;
820 boolean mWaitForDebugger = false;
821 boolean mDebugTransient = false;
822 String mOrigDebugApp = null;
823 boolean mOrigWaitForDebugger = false;
824 boolean mAlwaysFinishActivities = false;
825 IActivityWatcher mWatcher = null;
826
827 /**
828 * Callback of last caller to {@link #requestPss}.
829 */
830 Runnable mRequestPssCallback;
831
832 /**
833 * Remaining processes for which we are waiting results from the last
834 * call to {@link #requestPss}.
835 */
836 final ArrayList<ProcessRecord> mRequestPssList
837 = new ArrayList<ProcessRecord>();
838
839 /**
840 * Runtime statistics collection thread. This object's lock is used to
841 * protect all related state.
842 */
843 final Thread mProcessStatsThread;
844
845 /**
846 * Used to collect process stats when showing not responding dialog.
847 * Protected by mProcessStatsThread.
848 */
849 final ProcessStats mProcessStats = new ProcessStats(
850 MONITOR_THREAD_CPU_USAGE);
851 long mLastCpuTime = 0;
852 long mLastWriteTime = 0;
853
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700854 long mInitialStartTime = 0;
855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 /**
857 * Set to true after the system has finished booting.
858 */
859 boolean mBooted = false;
860
861 int mProcessLimit = 0;
862
863 WindowManagerService mWindowManager;
864
865 static ActivityManagerService mSelf;
866 static ActivityThread mSystemThread;
867
868 private final class AppDeathRecipient implements IBinder.DeathRecipient {
869 final ProcessRecord mApp;
870 final int mPid;
871 final IApplicationThread mAppThread;
872
873 AppDeathRecipient(ProcessRecord app, int pid,
874 IApplicationThread thread) {
875 if (localLOGV) Log.v(
876 TAG, "New death recipient " + this
877 + " for thread " + thread.asBinder());
878 mApp = app;
879 mPid = pid;
880 mAppThread = thread;
881 }
882
883 public void binderDied() {
884 if (localLOGV) Log.v(
885 TAG, "Death received in " + this
886 + " for thread " + mAppThread.asBinder());
887 removeRequestedPss(mApp);
888 synchronized(ActivityManagerService.this) {
889 appDiedLocked(mApp, mPid, mAppThread);
890 }
891 }
892 }
893
894 static final int SHOW_ERROR_MSG = 1;
895 static final int SHOW_NOT_RESPONDING_MSG = 2;
896 static final int SHOW_FACTORY_ERROR_MSG = 3;
897 static final int UPDATE_CONFIGURATION_MSG = 4;
898 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
899 static final int WAIT_FOR_DEBUGGER_MSG = 6;
900 static final int BROADCAST_INTENT_MSG = 7;
901 static final int BROADCAST_TIMEOUT_MSG = 8;
902 static final int PAUSE_TIMEOUT_MSG = 9;
903 static final int IDLE_TIMEOUT_MSG = 10;
904 static final int IDLE_NOW_MSG = 11;
905 static final int SERVICE_TIMEOUT_MSG = 12;
906 static final int UPDATE_TIME_ZONE = 13;
907 static final int SHOW_UID_ERROR_MSG = 14;
908 static final int IM_FEELING_LUCKY_MSG = 15;
909 static final int LAUNCH_TIMEOUT_MSG = 16;
910 static final int DESTROY_TIMEOUT_MSG = 17;
911 static final int SERVICE_ERROR_MSG = 18;
912 static final int RESUME_TOP_ACTIVITY_MSG = 19;
913 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700914 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915
916 AlertDialog mUidAlert;
917
918 final Handler mHandler = new Handler() {
919 //public Handler() {
920 // if (localLOGV) Log.v(TAG, "Handler started!");
921 //}
922
923 public void handleMessage(Message msg) {
924 switch (msg.what) {
925 case SHOW_ERROR_MSG: {
926 HashMap data = (HashMap) msg.obj;
927 byte[] crashData = (byte[])data.get("crashData");
928 if (crashData != null) {
929 // This needs to be *un*synchronized to avoid deadlock.
930 ContentResolver resolver = mContext.getContentResolver();
931 Checkin.reportCrash(resolver, crashData);
932 }
933 synchronized (ActivityManagerService.this) {
934 ProcessRecord proc = (ProcessRecord)data.get("app");
935 if (proc != null && proc.crashDialog != null) {
936 Log.e(TAG, "App already has crash dialog: " + proc);
937 return;
938 }
939 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700940 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 Dialog d = new AppErrorDialog(
942 mContext, res, proc,
943 (Integer)data.get("flags"),
944 (String)data.get("shortMsg"),
945 (String)data.get("longMsg"));
946 d.show();
947 proc.crashDialog = d;
948 } else {
949 // The device is asleep, so just pretend that the user
950 // saw a crash dialog and hit "force quit".
951 res.set(0);
952 }
953 }
954 } break;
955 case SHOW_NOT_RESPONDING_MSG: {
956 synchronized (ActivityManagerService.this) {
957 HashMap data = (HashMap) msg.obj;
958 ProcessRecord proc = (ProcessRecord)data.get("app");
959 if (proc != null && proc.anrDialog != null) {
960 Log.e(TAG, "App already has anr dialog: " + proc);
961 return;
962 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800963
964 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
965 null, null, 0, null, null, null,
966 false, false, MY_PID, Process.SYSTEM_UID);
967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
969 mContext, proc, (HistoryRecord)data.get("activity"));
970 d.show();
971 proc.anrDialog = d;
972 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700973
974 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 } break;
976 case SHOW_FACTORY_ERROR_MSG: {
977 Dialog d = new FactoryErrorDialog(
978 mContext, msg.getData().getCharSequence("msg"));
979 d.show();
980 enableScreenAfterBoot();
981 } break;
982 case UPDATE_CONFIGURATION_MSG: {
983 final ContentResolver resolver = mContext.getContentResolver();
984 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
985 } break;
986 case GC_BACKGROUND_PROCESSES_MSG: {
987 synchronized (ActivityManagerService.this) {
988 performAppGcsIfAppropriateLocked();
989 }
990 } break;
991 case WAIT_FOR_DEBUGGER_MSG: {
992 synchronized (ActivityManagerService.this) {
993 ProcessRecord app = (ProcessRecord)msg.obj;
994 if (msg.arg1 != 0) {
995 if (!app.waitedForDebugger) {
996 Dialog d = new AppWaitingForDebuggerDialog(
997 ActivityManagerService.this,
998 mContext, app);
999 app.waitDialog = d;
1000 app.waitedForDebugger = true;
1001 d.show();
1002 }
1003 } else {
1004 if (app.waitDialog != null) {
1005 app.waitDialog.dismiss();
1006 app.waitDialog = null;
1007 }
1008 }
1009 }
1010 } break;
1011 case BROADCAST_INTENT_MSG: {
1012 if (DEBUG_BROADCAST) Log.v(
1013 TAG, "Received BROADCAST_INTENT_MSG");
1014 processNextBroadcast(true);
1015 } break;
1016 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001017 if (mDidDexOpt) {
1018 mDidDexOpt = false;
1019 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1020 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1021 return;
1022 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 broadcastTimeout();
1024 } break;
1025 case PAUSE_TIMEOUT_MSG: {
1026 IBinder token = (IBinder)msg.obj;
1027 // We don't at this point know if the activity is fullscreen,
1028 // so we need to be conservative and assume it isn't.
1029 Log.w(TAG, "Activity pause timeout for " + token);
1030 activityPaused(token, null, true);
1031 } break;
1032 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001033 if (mDidDexOpt) {
1034 mDidDexOpt = false;
1035 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1036 nmsg.obj = msg.obj;
1037 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1038 return;
1039 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 // We don't at this point know if the activity is fullscreen,
1041 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001042 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 Log.w(TAG, "Activity idle timeout for " + token);
1044 activityIdleInternal(token, true);
1045 } break;
1046 case DESTROY_TIMEOUT_MSG: {
1047 IBinder token = (IBinder)msg.obj;
1048 // We don't at this point know if the activity is fullscreen,
1049 // so we need to be conservative and assume it isn't.
1050 Log.w(TAG, "Activity destroy timeout for " + token);
1051 activityDestroyed(token);
1052 } break;
1053 case IDLE_NOW_MSG: {
1054 IBinder token = (IBinder)msg.obj;
1055 activityIdle(token);
1056 } break;
1057 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001058 if (mDidDexOpt) {
1059 mDidDexOpt = false;
1060 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1061 nmsg.obj = msg.obj;
1062 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1063 return;
1064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 serviceTimeout((ProcessRecord)msg.obj);
1066 } break;
1067 case UPDATE_TIME_ZONE: {
1068 synchronized (ActivityManagerService.this) {
1069 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1070 ProcessRecord r = mLRUProcesses.get(i);
1071 if (r.thread != null) {
1072 try {
1073 r.thread.updateTimeZone();
1074 } catch (RemoteException ex) {
1075 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1076 }
1077 }
1078 }
1079 }
1080 break;
1081 }
1082 case SHOW_UID_ERROR_MSG: {
1083 // XXX This is a temporary dialog, no need to localize.
1084 AlertDialog d = new BaseErrorDialog(mContext);
1085 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1086 d.setCancelable(false);
1087 d.setTitle("System UIDs Inconsistent");
1088 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1089 d.setButton("I'm Feeling Lucky",
1090 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1091 mUidAlert = d;
1092 d.show();
1093 } break;
1094 case IM_FEELING_LUCKY_MSG: {
1095 if (mUidAlert != null) {
1096 mUidAlert.dismiss();
1097 mUidAlert = null;
1098 }
1099 } break;
1100 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001101 if (mDidDexOpt) {
1102 mDidDexOpt = false;
1103 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1104 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1105 return;
1106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 synchronized (ActivityManagerService.this) {
1108 if (mLaunchingActivity.isHeld()) {
1109 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1110 mLaunchingActivity.release();
1111 }
1112 }
1113 } break;
1114 case SERVICE_ERROR_MSG: {
1115 ServiceRecord srv = (ServiceRecord)msg.obj;
1116 // This needs to be *un*synchronized to avoid deadlock.
1117 Checkin.logEvent(mContext.getContentResolver(),
1118 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1119 srv.name.toShortString());
1120 } break;
1121 case RESUME_TOP_ACTIVITY_MSG: {
1122 synchronized (ActivityManagerService.this) {
1123 resumeTopActivityLocked(null);
1124 }
1125 }
1126 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001127 if (mDidDexOpt) {
1128 mDidDexOpt = false;
1129 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1130 nmsg.obj = msg.obj;
1131 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1132 return;
1133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 ProcessRecord app = (ProcessRecord)msg.obj;
1135 synchronized (ActivityManagerService.this) {
1136 processStartTimedOutLocked(app);
1137 }
1138 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001139 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1140 synchronized (ActivityManagerService.this) {
1141 doPendingActivityLaunchesLocked(true);
1142 }
1143 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 }
1145 }
1146 };
1147
1148 public static void setSystemProcess() {
1149 try {
1150 ActivityManagerService m = mSelf;
1151
1152 ServiceManager.addService("activity", m);
1153 ServiceManager.addService("meminfo", new MemBinder(m));
1154 if (MONITOR_CPU_USAGE) {
1155 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1156 }
1157 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1158 ServiceManager.addService("activity.services", new ServicesBinder(m));
1159 ServiceManager.addService("activity.senders", new SendersBinder(m));
1160 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1161 ServiceManager.addService("permission", new PermissionController(m));
1162
1163 ApplicationInfo info =
1164 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001165 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 synchronized (mSelf) {
1167 ProcessRecord app = mSelf.newProcessRecordLocked(
1168 mSystemThread.getApplicationThread(), info,
1169 info.processName);
1170 app.persistent = true;
1171 app.pid = Process.myPid();
1172 app.maxAdj = SYSTEM_ADJ;
1173 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1174 synchronized (mSelf.mPidsSelfLocked) {
1175 mSelf.mPidsSelfLocked.put(app.pid, app);
1176 }
1177 mSelf.updateLRUListLocked(app, true);
1178 }
1179 } catch (PackageManager.NameNotFoundException e) {
1180 throw new RuntimeException(
1181 "Unable to find android system package", e);
1182 }
1183 }
1184
1185 public void setWindowManager(WindowManagerService wm) {
1186 mWindowManager = wm;
1187 }
1188
1189 public static final Context main(int factoryTest) {
1190 AThread thr = new AThread();
1191 thr.start();
1192
1193 synchronized (thr) {
1194 while (thr.mService == null) {
1195 try {
1196 thr.wait();
1197 } catch (InterruptedException e) {
1198 }
1199 }
1200 }
1201
1202 ActivityManagerService m = thr.mService;
1203 mSelf = m;
1204 ActivityThread at = ActivityThread.systemMain();
1205 mSystemThread = at;
1206 Context context = at.getSystemContext();
1207 m.mContext = context;
1208 m.mFactoryTest = factoryTest;
1209 PowerManager pm =
1210 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1211 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1212 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1213 m.mLaunchingActivity.setReferenceCounted(false);
1214
1215 m.mBatteryStatsService.publish(context);
1216 m.mUsageStatsService.publish(context);
1217
1218 synchronized (thr) {
1219 thr.mReady = true;
1220 thr.notifyAll();
1221 }
1222
1223 m.startRunning(null, null, null, null);
1224
1225 return context;
1226 }
1227
1228 public static ActivityManagerService self() {
1229 return mSelf;
1230 }
1231
1232 static class AThread extends Thread {
1233 ActivityManagerService mService;
1234 boolean mReady = false;
1235
1236 public AThread() {
1237 super("ActivityManager");
1238 }
1239
1240 public void run() {
1241 Looper.prepare();
1242
1243 android.os.Process.setThreadPriority(
1244 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1245
1246 ActivityManagerService m = new ActivityManagerService();
1247
1248 synchronized (this) {
1249 mService = m;
1250 notifyAll();
1251 }
1252
1253 synchronized (this) {
1254 while (!mReady) {
1255 try {
1256 wait();
1257 } catch (InterruptedException e) {
1258 }
1259 }
1260 }
1261
1262 Looper.loop();
1263 }
1264 }
1265
1266 static class BroadcastsBinder extends Binder {
1267 ActivityManagerService mActivityManagerService;
1268 BroadcastsBinder(ActivityManagerService activityManagerService) {
1269 mActivityManagerService = activityManagerService;
1270 }
1271
1272 @Override
1273 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1274 mActivityManagerService.dumpBroadcasts(pw);
1275 }
1276 }
1277
1278 static class ServicesBinder extends Binder {
1279 ActivityManagerService mActivityManagerService;
1280 ServicesBinder(ActivityManagerService activityManagerService) {
1281 mActivityManagerService = activityManagerService;
1282 }
1283
1284 @Override
1285 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1286 mActivityManagerService.dumpServices(pw);
1287 }
1288 }
1289
1290 static class SendersBinder extends Binder {
1291 ActivityManagerService mActivityManagerService;
1292 SendersBinder(ActivityManagerService activityManagerService) {
1293 mActivityManagerService = activityManagerService;
1294 }
1295
1296 @Override
1297 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1298 mActivityManagerService.dumpSenders(pw);
1299 }
1300 }
1301
1302 static class ProvidersBinder extends Binder {
1303 ActivityManagerService mActivityManagerService;
1304 ProvidersBinder(ActivityManagerService activityManagerService) {
1305 mActivityManagerService = activityManagerService;
1306 }
1307
1308 @Override
1309 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1310 mActivityManagerService.dumpProviders(pw);
1311 }
1312 }
1313
1314 static class MemBinder extends Binder {
1315 ActivityManagerService mActivityManagerService;
1316 MemBinder(ActivityManagerService activityManagerService) {
1317 mActivityManagerService = activityManagerService;
1318 }
1319
1320 @Override
1321 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1322 ActivityManagerService service = mActivityManagerService;
1323 ArrayList<ProcessRecord> procs;
1324 synchronized (mActivityManagerService) {
1325 if (args != null && args.length > 0
1326 && args[0].charAt(0) != '-') {
1327 procs = new ArrayList<ProcessRecord>();
1328 int pid = -1;
1329 try {
1330 pid = Integer.parseInt(args[0]);
1331 } catch (NumberFormatException e) {
1332
1333 }
1334 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1335 ProcessRecord proc = service.mLRUProcesses.get(i);
1336 if (proc.pid == pid) {
1337 procs.add(proc);
1338 } else if (proc.processName.equals(args[0])) {
1339 procs.add(proc);
1340 }
1341 }
1342 if (procs.size() <= 0) {
1343 pw.println("No process found for: " + args[0]);
1344 return;
1345 }
1346 } else {
1347 procs = service.mLRUProcesses;
1348 }
1349 }
1350 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1351 }
1352 }
1353
1354 static class CpuBinder extends Binder {
1355 ActivityManagerService mActivityManagerService;
1356 CpuBinder(ActivityManagerService activityManagerService) {
1357 mActivityManagerService = activityManagerService;
1358 }
1359
1360 @Override
1361 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1362 synchronized (mActivityManagerService.mProcessStatsThread) {
1363 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1364 }
1365 }
1366 }
1367
1368 private ActivityManagerService() {
1369 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1370 if (v != null && Integer.getInteger(v) != 0) {
1371 mSimpleProcessManagement = true;
1372 }
1373 v = System.getenv("ANDROID_DEBUG_APP");
1374 if (v != null) {
1375 mSimpleProcessManagement = true;
1376 }
1377
1378 MY_PID = Process.myPid();
1379
1380 File dataDir = Environment.getDataDirectory();
1381 File systemDir = new File(dataDir, "system");
1382 systemDir.mkdirs();
1383 mBatteryStatsService = new BatteryStatsService(new File(
1384 systemDir, "batterystats.bin").toString());
1385 mBatteryStatsService.getActiveStatistics().readLocked();
1386 mBatteryStatsService.getActiveStatistics().writeLocked();
1387
1388 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001389 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390
1391 mConfiguration.makeDefault();
1392 mProcessStats.init();
1393
1394 // Add ourself to the Watchdog monitors.
1395 Watchdog.getInstance().addMonitor(this);
1396
1397 // These values are set in system/rootdir/init.rc on startup.
1398 FOREGROUND_APP_ADJ =
1399 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1400 VISIBLE_APP_ADJ =
1401 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1402 SECONDARY_SERVER_ADJ =
1403 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001404 BACKUP_APP_ADJ =
1405 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001406 HOME_APP_ADJ =
1407 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 HIDDEN_APP_MIN_ADJ =
1409 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1410 CONTENT_PROVIDER_ADJ =
1411 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1412 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1413 EMPTY_APP_ADJ =
1414 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1415 FOREGROUND_APP_MEM =
1416 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1417 VISIBLE_APP_MEM =
1418 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1419 SECONDARY_SERVER_MEM =
1420 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001421 BACKUP_APP_MEM =
1422 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001423 HOME_APP_MEM =
1424 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 HIDDEN_APP_MEM =
1426 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1427 EMPTY_APP_MEM =
1428 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1429
1430 mProcessStatsThread = new Thread("ProcessStats") {
1431 public void run() {
1432 while (true) {
1433 try {
1434 try {
1435 synchronized(this) {
1436 final long now = SystemClock.uptimeMillis();
1437 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1438 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1439 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1440 // + ", write delay=" + nextWriteDelay);
1441 if (nextWriteDelay < nextCpuDelay) {
1442 nextCpuDelay = nextWriteDelay;
1443 }
1444 if (nextCpuDelay > 0) {
1445 this.wait(nextCpuDelay);
1446 }
1447 }
1448 } catch (InterruptedException e) {
1449 }
1450
1451 updateCpuStatsNow();
1452 } catch (Exception e) {
1453 Log.e(TAG, "Unexpected exception collecting process stats", e);
1454 }
1455 }
1456 }
1457 };
1458 mProcessStatsThread.start();
1459 }
1460
1461 @Override
1462 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1463 throws RemoteException {
1464 try {
1465 return super.onTransact(code, data, reply, flags);
1466 } catch (RuntimeException e) {
1467 // The activity manager only throws security exceptions, so let's
1468 // log all others.
1469 if (!(e instanceof SecurityException)) {
1470 Log.e(TAG, "Activity Manager Crash", e);
1471 }
1472 throw e;
1473 }
1474 }
1475
1476 void updateCpuStats() {
1477 synchronized (mProcessStatsThread) {
1478 final long now = SystemClock.uptimeMillis();
1479 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1480 mProcessStatsThread.notify();
1481 }
1482 }
1483 }
1484
1485 void updateCpuStatsNow() {
1486 synchronized (mProcessStatsThread) {
1487 final long now = SystemClock.uptimeMillis();
1488 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 if (MONITOR_CPU_USAGE &&
1491 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1492 mLastCpuTime = now;
1493 haveNewCpuStats = true;
1494 mProcessStats.update();
1495 //Log.i(TAG, mProcessStats.printCurrentState());
1496 //Log.i(TAG, "Total CPU usage: "
1497 // + mProcessStats.getTotalCpuPercent() + "%");
1498
1499 // Log the cpu usage if the property is set.
1500 if ("true".equals(SystemProperties.get("events.cpu"))) {
1501 int user = mProcessStats.getLastUserTime();
1502 int system = mProcessStats.getLastSystemTime();
1503 int iowait = mProcessStats.getLastIoWaitTime();
1504 int irq = mProcessStats.getLastIrqTime();
1505 int softIrq = mProcessStats.getLastSoftIrqTime();
1506 int idle = mProcessStats.getLastIdleTime();
1507
1508 int total = user + system + iowait + irq + softIrq + idle;
1509 if (total == 0) total = 1;
1510
1511 EventLog.writeEvent(LOG_CPU,
1512 ((user+system+iowait+irq+softIrq) * 100) / total,
1513 (user * 100) / total,
1514 (system * 100) / total,
1515 (iowait * 100) / total,
1516 (irq * 100) / total,
1517 (softIrq * 100) / total);
1518 }
1519 }
1520
Amith Yamasani819f9282009-06-24 23:18:15 -07001521 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001522 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 synchronized(mPidsSelfLocked) {
1524 if (haveNewCpuStats) {
1525 if (mBatteryStatsService.isOnBattery()) {
1526 final int N = mProcessStats.countWorkingStats();
1527 for (int i=0; i<N; i++) {
1528 ProcessStats.Stats st
1529 = mProcessStats.getWorkingStats(i);
1530 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1531 if (pr != null) {
1532 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1533 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001534 } else {
1535 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001536 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001537 if (ps != null) {
1538 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1539 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 }
1541 }
1542 }
1543 }
1544 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1547 mLastWriteTime = now;
1548 mBatteryStatsService.getActiveStatistics().writeLocked();
1549 }
1550 }
1551 }
1552 }
1553
1554 /**
1555 * Initialize the application bind args. These are passed to each
1556 * process when the bindApplication() IPC is sent to the process. They're
1557 * lazily setup to make sure the services are running when they're asked for.
1558 */
1559 private HashMap<String, IBinder> getCommonServicesLocked() {
1560 if (mAppBindArgs == null) {
1561 mAppBindArgs = new HashMap<String, IBinder>();
1562
1563 // Setup the application init args
1564 mAppBindArgs.put("package", ServiceManager.getService("package"));
1565 mAppBindArgs.put("window", ServiceManager.getService("window"));
1566 mAppBindArgs.put(Context.ALARM_SERVICE,
1567 ServiceManager.getService(Context.ALARM_SERVICE));
1568 }
1569 return mAppBindArgs;
1570 }
1571
1572 private final void setFocusedActivityLocked(HistoryRecord r) {
1573 if (mFocusedActivity != r) {
1574 mFocusedActivity = r;
1575 mWindowManager.setFocusedApp(r, true);
1576 }
1577 }
1578
1579 private final void updateLRUListLocked(ProcessRecord app,
1580 boolean oomAdj) {
1581 // put it on the LRU to keep track of when it should be exited.
1582 int lrui = mLRUProcesses.indexOf(app);
1583 if (lrui >= 0) mLRUProcesses.remove(lrui);
1584 mLRUProcesses.add(app);
1585 //Log.i(TAG, "Putting proc to front: " + app.processName);
1586 if (oomAdj) {
1587 updateOomAdjLocked();
1588 }
1589 }
1590
1591 private final boolean updateLRUListLocked(HistoryRecord r) {
1592 final boolean hadit = mLRUActivities.remove(r);
1593 mLRUActivities.add(r);
1594 return hadit;
1595 }
1596
1597 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1598 int i = mHistory.size()-1;
1599 while (i >= 0) {
1600 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1601 if (!r.finishing && r != notTop) {
1602 return r;
1603 }
1604 i--;
1605 }
1606 return null;
1607 }
1608
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001609 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1610 int i = mHistory.size()-1;
1611 while (i >= 0) {
1612 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1613 if (!r.finishing && !r.delayedResume && r != notTop) {
1614 return r;
1615 }
1616 i--;
1617 }
1618 return null;
1619 }
1620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 /**
1622 * This is a simplified version of topRunningActivityLocked that provides a number of
1623 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1624 *
1625 * @param token If non-null, any history records matching this token will be skipped.
1626 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1627 *
1628 * @return Returns the HistoryRecord of the next activity on the stack.
1629 */
1630 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1631 int i = mHistory.size()-1;
1632 while (i >= 0) {
1633 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1634 // Note: the taskId check depends on real taskId fields being non-zero
1635 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1636 return r;
1637 }
1638 i--;
1639 }
1640 return null;
1641 }
1642
1643 private final ProcessRecord getProcessRecordLocked(
1644 String processName, int uid) {
1645 if (uid == Process.SYSTEM_UID) {
1646 // The system gets to run in any process. If there are multiple
1647 // processes with the same uid, just pick the first (this
1648 // should never happen).
1649 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1650 processName);
1651 return procs != null ? procs.valueAt(0) : null;
1652 }
1653 ProcessRecord proc = mProcessNames.get(processName, uid);
1654 return proc;
1655 }
1656
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001657 private void ensurePackageDexOpt(String packageName) {
1658 IPackageManager pm = ActivityThread.getPackageManager();
1659 try {
1660 if (pm.performDexOpt(packageName)) {
1661 mDidDexOpt = true;
1662 }
1663 } catch (RemoteException e) {
1664 }
1665 }
1666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 private boolean isNextTransitionForward() {
1668 int transit = mWindowManager.getPendingAppTransition();
1669 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1670 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1671 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1672 }
1673
1674 private final boolean realStartActivityLocked(HistoryRecord r,
1675 ProcessRecord app, boolean andResume, boolean checkConfig)
1676 throws RemoteException {
1677
1678 r.startFreezingScreenLocked(app, 0);
1679 mWindowManager.setAppVisibility(r, true);
1680
1681 // Have the window manager re-evaluate the orientation of
1682 // the screen based on the new activity order. Note that
1683 // as a result of this, it can call back into the activity
1684 // manager with a new orientation. We don't care about that,
1685 // because the activity is not currently running so we are
1686 // just restarting it anyway.
1687 if (checkConfig) {
1688 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001689 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 r.mayFreezeScreenLocked(app) ? r : null);
1691 updateConfigurationLocked(config, r);
1692 }
1693
1694 r.app = app;
1695
1696 if (localLOGV) Log.v(TAG, "Launching: " + r);
1697
1698 int idx = app.activities.indexOf(r);
1699 if (idx < 0) {
1700 app.activities.add(r);
1701 }
1702 updateLRUListLocked(app, true);
1703
1704 try {
1705 if (app.thread == null) {
1706 throw new RemoteException();
1707 }
1708 List<ResultInfo> results = null;
1709 List<Intent> newIntents = null;
1710 if (andResume) {
1711 results = r.results;
1712 newIntents = r.newIntents;
1713 }
1714 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1715 + " icicle=" + r.icicle
1716 + " with results=" + results + " newIntents=" + newIntents
1717 + " andResume=" + andResume);
1718 if (andResume) {
1719 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1720 System.identityHashCode(r),
1721 r.task.taskId, r.shortComponentName);
1722 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001723 if (r.isHomeActivity) {
1724 mHomeProcess = app;
1725 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001726 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1728 r.info, r.icicle, results, newIntents, !andResume,
1729 isNextTransitionForward());
1730 // Update usage stats for launched activity
1731 updateUsageStats(r, true);
1732 } catch (RemoteException e) {
1733 if (r.launchFailed) {
1734 // This is the second time we failed -- finish activity
1735 // and give up.
1736 Log.e(TAG, "Second failure launching "
1737 + r.intent.getComponent().flattenToShortString()
1738 + ", giving up", e);
1739 appDiedLocked(app, app.pid, app.thread);
1740 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1741 "2nd-crash");
1742 return false;
1743 }
1744
1745 // This is the first time we failed -- restart process and
1746 // retry.
1747 app.activities.remove(r);
1748 throw e;
1749 }
1750
1751 r.launchFailed = false;
1752 if (updateLRUListLocked(r)) {
1753 Log.w(TAG, "Activity " + r
1754 + " being launched, but already in LRU list");
1755 }
1756
1757 if (andResume) {
1758 // As part of the process of launching, ActivityThread also performs
1759 // a resume.
1760 r.state = ActivityState.RESUMED;
1761 r.icicle = null;
1762 r.haveState = false;
1763 r.stopped = false;
1764 mResumedActivity = r;
1765 r.task.touchActiveTime();
1766 completeResumeLocked(r);
1767 pauseIfSleepingLocked();
1768 } else {
1769 // This activity is not starting in the resumed state... which
1770 // should look like we asked it to pause+stop (but remain visible),
1771 // and it has done so and reported back the current icicle and
1772 // other state.
1773 r.state = ActivityState.STOPPED;
1774 r.stopped = true;
1775 }
1776
1777 return true;
1778 }
1779
1780 private final void startSpecificActivityLocked(HistoryRecord r,
1781 boolean andResume, boolean checkConfig) {
1782 // Is this activity's application already running?
1783 ProcessRecord app = getProcessRecordLocked(r.processName,
1784 r.info.applicationInfo.uid);
1785
1786 if (r.startTime == 0) {
1787 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001788 if (mInitialStartTime == 0) {
1789 mInitialStartTime = r.startTime;
1790 }
1791 } else if (mInitialStartTime == 0) {
1792 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 }
1794
1795 if (app != null && app.thread != null) {
1796 try {
1797 realStartActivityLocked(r, app, andResume, checkConfig);
1798 return;
1799 } catch (RemoteException e) {
1800 Log.w(TAG, "Exception when starting activity "
1801 + r.intent.getComponent().flattenToShortString(), e);
1802 }
1803
1804 // If a dead object exception was thrown -- fall through to
1805 // restart the application.
1806 }
1807
1808 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1809 "activity", r.intent.getComponent());
1810 }
1811
1812 private final ProcessRecord startProcessLocked(String processName,
1813 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1814 String hostingType, ComponentName hostingName) {
1815 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1816 // We don't have to do anything more if:
1817 // (1) There is an existing application record; and
1818 // (2) The caller doesn't think it is dead, OR there is no thread
1819 // object attached to it so we know it couldn't have crashed; and
1820 // (3) There is a pid assigned to it, so it is either starting or
1821 // already running.
1822 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1823 + " app=" + app + " knownToBeDead=" + knownToBeDead
1824 + " thread=" + (app != null ? app.thread : null)
1825 + " pid=" + (app != null ? app.pid : -1));
1826 if (app != null &&
1827 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1828 return app;
1829 }
1830
1831 String hostingNameStr = hostingName != null
1832 ? hostingName.flattenToShortString() : null;
1833
1834 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1835 // If we are in the background, then check to see if this process
1836 // is bad. If so, we will just silently fail.
1837 if (mBadProcesses.get(info.processName, info.uid) != null) {
1838 return null;
1839 }
1840 } else {
1841 // When the user is explicitly starting a process, then clear its
1842 // crash count so that we won't make it bad until they see at
1843 // least one crash dialog again, and make the process good again
1844 // if it had been bad.
1845 mProcessCrashTimes.remove(info.processName, info.uid);
1846 if (mBadProcesses.get(info.processName, info.uid) != null) {
1847 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1848 info.processName);
1849 mBadProcesses.remove(info.processName, info.uid);
1850 if (app != null) {
1851 app.bad = false;
1852 }
1853 }
1854 }
1855
1856 if (app == null) {
1857 app = newProcessRecordLocked(null, info, processName);
1858 mProcessNames.put(processName, info.uid, app);
1859 } else {
1860 // If this is a new package in the process, add the package to the list
1861 app.addPackage(info.packageName);
1862 }
1863
1864 // If the system is not ready yet, then hold off on starting this
1865 // process until it is.
1866 if (!mSystemReady
1867 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1868 if (!mProcessesOnHold.contains(app)) {
1869 mProcessesOnHold.add(app);
1870 }
1871 return app;
1872 }
1873
1874 startProcessLocked(app, hostingType, hostingNameStr);
1875 return (app.pid != 0) ? app : null;
1876 }
1877
1878 private final void startProcessLocked(ProcessRecord app,
1879 String hostingType, String hostingNameStr) {
1880 if (app.pid > 0 && app.pid != MY_PID) {
1881 synchronized (mPidsSelfLocked) {
1882 mPidsSelfLocked.remove(app.pid);
1883 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1884 }
1885 app.pid = 0;
1886 }
1887
1888 mProcessesOnHold.remove(app);
1889
1890 updateCpuStats();
1891
1892 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1893 mProcDeaths[0] = 0;
1894
1895 try {
1896 int uid = app.info.uid;
1897 int[] gids = null;
1898 try {
1899 gids = mContext.getPackageManager().getPackageGids(
1900 app.info.packageName);
1901 } catch (PackageManager.NameNotFoundException e) {
1902 Log.w(TAG, "Unable to retrieve gids", e);
1903 }
1904 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1905 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1906 && mTopComponent != null
1907 && app.processName.equals(mTopComponent.getPackageName())) {
1908 uid = 0;
1909 }
1910 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1911 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1912 uid = 0;
1913 }
1914 }
1915 int debugFlags = 0;
1916 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1917 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1918 }
1919 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1920 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1921 }
1922 if ("1".equals(SystemProperties.get("debug.assert"))) {
1923 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1924 }
1925 int pid = Process.start("android.app.ActivityThread",
1926 mSimpleProcessManagement ? app.processName : null, uid, uid,
1927 gids, debugFlags, null);
1928 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1929 synchronized (bs) {
1930 if (bs.isOnBattery()) {
1931 app.batteryStats.incStartsLocked();
1932 }
1933 }
1934
1935 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1936 app.processName, hostingType,
1937 hostingNameStr != null ? hostingNameStr : "");
1938
1939 if (app.persistent) {
1940 Watchdog.getInstance().processStarted(app, app.processName, pid);
1941 }
1942
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001943 StringBuilder buf = mStringBuilder;
1944 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 buf.append("Start proc ");
1946 buf.append(app.processName);
1947 buf.append(" for ");
1948 buf.append(hostingType);
1949 if (hostingNameStr != null) {
1950 buf.append(" ");
1951 buf.append(hostingNameStr);
1952 }
1953 buf.append(": pid=");
1954 buf.append(pid);
1955 buf.append(" uid=");
1956 buf.append(uid);
1957 buf.append(" gids={");
1958 if (gids != null) {
1959 for (int gi=0; gi<gids.length; gi++) {
1960 if (gi != 0) buf.append(", ");
1961 buf.append(gids[gi]);
1962
1963 }
1964 }
1965 buf.append("}");
1966 Log.i(TAG, buf.toString());
1967 if (pid == 0 || pid == MY_PID) {
1968 // Processes are being emulated with threads.
1969 app.pid = MY_PID;
1970 app.removed = false;
1971 mStartingProcesses.add(app);
1972 } else if (pid > 0) {
1973 app.pid = pid;
1974 app.removed = false;
1975 synchronized (mPidsSelfLocked) {
1976 this.mPidsSelfLocked.put(pid, app);
1977 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1978 msg.obj = app;
1979 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1980 }
1981 } else {
1982 app.pid = 0;
1983 RuntimeException e = new RuntimeException(
1984 "Failure starting process " + app.processName
1985 + ": returned pid=" + pid);
1986 Log.e(TAG, e.getMessage(), e);
1987 }
1988 } catch (RuntimeException e) {
1989 // XXX do better error recovery.
1990 app.pid = 0;
1991 Log.e(TAG, "Failure starting process " + app.processName, e);
1992 }
1993 }
1994
1995 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1996 if (mPausingActivity != null) {
1997 RuntimeException e = new RuntimeException();
1998 Log.e(TAG, "Trying to pause when pause is already pending for "
1999 + mPausingActivity, e);
2000 }
2001 HistoryRecord prev = mResumedActivity;
2002 if (prev == null) {
2003 RuntimeException e = new RuntimeException();
2004 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2005 resumeTopActivityLocked(null);
2006 return;
2007 }
2008 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2009 mResumedActivity = null;
2010 mPausingActivity = prev;
2011 mLastPausedActivity = prev;
2012 prev.state = ActivityState.PAUSING;
2013 prev.task.touchActiveTime();
2014
2015 updateCpuStats();
2016
2017 if (prev.app != null && prev.app.thread != null) {
2018 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2019 try {
2020 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2021 System.identityHashCode(prev),
2022 prev.shortComponentName);
2023 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2024 prev.configChangeFlags);
2025 updateUsageStats(prev, false);
2026 } catch (Exception e) {
2027 // Ignore exception, if process died other code will cleanup.
2028 Log.w(TAG, "Exception thrown during pause", e);
2029 mPausingActivity = null;
2030 mLastPausedActivity = null;
2031 }
2032 } else {
2033 mPausingActivity = null;
2034 mLastPausedActivity = null;
2035 }
2036
2037 // If we are not going to sleep, we want to ensure the device is
2038 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002039 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 mLaunchingActivity.acquire();
2041 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2042 // To be safe, don't allow the wake lock to be held for too long.
2043 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2044 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2045 }
2046 }
2047
2048
2049 if (mPausingActivity != null) {
2050 // Have the window manager pause its key dispatching until the new
2051 // activity has started. If we're pausing the activity just because
2052 // the screen is being turned off and the UI is sleeping, don't interrupt
2053 // key dispatch; the same activity will pick it up again on wakeup.
2054 if (!uiSleeping) {
2055 prev.pauseKeyDispatchingLocked();
2056 } else {
2057 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2058 }
2059
2060 // Schedule a pause timeout in case the app doesn't respond.
2061 // We don't give it much time because this directly impacts the
2062 // responsiveness seen by the user.
2063 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2064 msg.obj = prev;
2065 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2066 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2067 } else {
2068 // This activity failed to schedule the
2069 // pause, so just treat it as being paused now.
2070 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2071 resumeTopActivityLocked(null);
2072 }
2073 }
2074
2075 private final void completePauseLocked() {
2076 HistoryRecord prev = mPausingActivity;
2077 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2078
2079 if (prev != null) {
2080 if (prev.finishing) {
2081 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2082 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2083 } else if (prev.app != null) {
2084 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2085 if (prev.waitingVisible) {
2086 prev.waitingVisible = false;
2087 mWaitingVisibleActivities.remove(prev);
2088 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2089 TAG, "Complete pause, no longer waiting: " + prev);
2090 }
2091 if (prev.configDestroy) {
2092 // The previous is being paused because the configuration
2093 // is changing, which means it is actually stopping...
2094 // To juggle the fact that we are also starting a new
2095 // instance right now, we need to first completely stop
2096 // the current instance before starting the new one.
2097 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2098 destroyActivityLocked(prev, true);
2099 } else {
2100 mStoppingActivities.add(prev);
2101 if (mStoppingActivities.size() > 3) {
2102 // If we already have a few activities waiting to stop,
2103 // then give up on things going idle and start clearing
2104 // them out.
2105 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2106 Message msg = Message.obtain();
2107 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2108 mHandler.sendMessage(msg);
2109 }
2110 }
2111 } else {
2112 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2113 prev = null;
2114 }
2115 mPausingActivity = null;
2116 }
2117
Dianne Hackborn55280a92009-05-07 15:53:46 -07002118 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 resumeTopActivityLocked(prev);
2120 } else {
2121 if (mGoingToSleep.isHeld()) {
2122 mGoingToSleep.release();
2123 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002124 if (mShuttingDown) {
2125 notifyAll();
2126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 }
2128
2129 if (prev != null) {
2130 prev.resumeKeyDispatchingLocked();
2131 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002132
2133 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2134 long diff = 0;
2135 synchronized (mProcessStatsThread) {
2136 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2137 }
2138 if (diff > 0) {
2139 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2140 synchronized (bsi) {
2141 BatteryStatsImpl.Uid.Proc ps =
2142 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2143 prev.info.packageName);
2144 if (ps != null) {
2145 ps.addForegroundTimeLocked(diff);
2146 }
2147 }
2148 }
2149 }
2150 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 }
2152
2153 /**
2154 * Once we know that we have asked an application to put an activity in
2155 * the resumed state (either by launching it or explicitly telling it),
2156 * this function updates the rest of our state to match that fact.
2157 */
2158 private final void completeResumeLocked(HistoryRecord next) {
2159 next.idle = false;
2160 next.results = null;
2161 next.newIntents = null;
2162
2163 // schedule an idle timeout in case the app doesn't do it for us.
2164 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2165 msg.obj = next;
2166 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2167
2168 if (false) {
2169 // The activity was never told to pause, so just keep
2170 // things going as-is. To maintain our own state,
2171 // we need to emulate it coming back and saying it is
2172 // idle.
2173 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2174 msg.obj = next;
2175 mHandler.sendMessage(msg);
2176 }
2177
2178 next.thumbnail = null;
2179 setFocusedActivityLocked(next);
2180 next.resumeKeyDispatchingLocked();
2181 ensureActivitiesVisibleLocked(null, 0);
2182 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002183
2184 // Mark the point when the activity is resuming
2185 // TODO: To be more accurate, the mark should be before the onCreate,
2186 // not after the onResume. But for subsequent starts, onResume is fine.
2187 if (next.app != null) {
2188 synchronized (mProcessStatsThread) {
2189 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2190 }
2191 } else {
2192 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2193 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 }
2195
2196 /**
2197 * Make sure that all activities that need to be visible (that is, they
2198 * currently can be seen by the user) actually are.
2199 */
2200 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2201 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2202 if (DEBUG_VISBILITY) Log.v(
2203 TAG, "ensureActivitiesVisible behind " + top
2204 + " configChanges=0x" + Integer.toHexString(configChanges));
2205
2206 // If the top activity is not fullscreen, then we need to
2207 // make sure any activities under it are now visible.
2208 final int count = mHistory.size();
2209 int i = count-1;
2210 while (mHistory.get(i) != top) {
2211 i--;
2212 }
2213 HistoryRecord r;
2214 boolean behindFullscreen = false;
2215 for (; i>=0; i--) {
2216 r = (HistoryRecord)mHistory.get(i);
2217 if (DEBUG_VISBILITY) Log.v(
2218 TAG, "Make visible? " + r + " finishing=" + r.finishing
2219 + " state=" + r.state);
2220 if (r.finishing) {
2221 continue;
2222 }
2223
2224 final boolean doThisProcess = onlyThisProcess == null
2225 || onlyThisProcess.equals(r.processName);
2226
2227 // First: if this is not the current activity being started, make
2228 // sure it matches the current configuration.
2229 if (r != starting && doThisProcess) {
2230 ensureActivityConfigurationLocked(r, 0);
2231 }
2232
2233 if (r.app == null || r.app.thread == null) {
2234 if (onlyThisProcess == null
2235 || onlyThisProcess.equals(r.processName)) {
2236 // This activity needs to be visible, but isn't even
2237 // running... get it started, but don't resume it
2238 // at this point.
2239 if (DEBUG_VISBILITY) Log.v(
2240 TAG, "Start and freeze screen for " + r);
2241 if (r != starting) {
2242 r.startFreezingScreenLocked(r.app, configChanges);
2243 }
2244 if (!r.visible) {
2245 if (DEBUG_VISBILITY) Log.v(
2246 TAG, "Starting and making visible: " + r);
2247 mWindowManager.setAppVisibility(r, true);
2248 }
2249 if (r != starting) {
2250 startSpecificActivityLocked(r, false, false);
2251 }
2252 }
2253
2254 } else if (r.visible) {
2255 // If this activity is already visible, then there is nothing
2256 // else to do here.
2257 if (DEBUG_VISBILITY) Log.v(
2258 TAG, "Skipping: already visible at " + r);
2259 r.stopFreezingScreenLocked(false);
2260
2261 } else if (onlyThisProcess == null) {
2262 // This activity is not currently visible, but is running.
2263 // Tell it to become visible.
2264 r.visible = true;
2265 if (r.state != ActivityState.RESUMED && r != starting) {
2266 // If this activity is paused, tell it
2267 // to now show its window.
2268 if (DEBUG_VISBILITY) Log.v(
2269 TAG, "Making visible and scheduling visibility: " + r);
2270 try {
2271 mWindowManager.setAppVisibility(r, true);
2272 r.app.thread.scheduleWindowVisibility(r, true);
2273 r.stopFreezingScreenLocked(false);
2274 } catch (Exception e) {
2275 // Just skip on any failure; we'll make it
2276 // visible when it next restarts.
2277 Log.w(TAG, "Exception thrown making visibile: "
2278 + r.intent.getComponent(), e);
2279 }
2280 }
2281 }
2282
2283 // Aggregate current change flags.
2284 configChanges |= r.configChangeFlags;
2285
2286 if (r.fullscreen) {
2287 // At this point, nothing else needs to be shown
2288 if (DEBUG_VISBILITY) Log.v(
2289 TAG, "Stopping: fullscreen at " + r);
2290 behindFullscreen = true;
2291 i--;
2292 break;
2293 }
2294 }
2295
2296 // Now for any activities that aren't visible to the user, make
2297 // sure they no longer are keeping the screen frozen.
2298 while (i >= 0) {
2299 r = (HistoryRecord)mHistory.get(i);
2300 if (DEBUG_VISBILITY) Log.v(
2301 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2302 + " state=" + r.state
2303 + " behindFullscreen=" + behindFullscreen);
2304 if (!r.finishing) {
2305 if (behindFullscreen) {
2306 if (r.visible) {
2307 if (DEBUG_VISBILITY) Log.v(
2308 TAG, "Making invisible: " + r);
2309 r.visible = false;
2310 try {
2311 mWindowManager.setAppVisibility(r, false);
2312 if ((r.state == ActivityState.STOPPING
2313 || r.state == ActivityState.STOPPED)
2314 && r.app != null && r.app.thread != null) {
2315 if (DEBUG_VISBILITY) Log.v(
2316 TAG, "Scheduling invisibility: " + r);
2317 r.app.thread.scheduleWindowVisibility(r, false);
2318 }
2319 } catch (Exception e) {
2320 // Just skip on any failure; we'll make it
2321 // visible when it next restarts.
2322 Log.w(TAG, "Exception thrown making hidden: "
2323 + r.intent.getComponent(), e);
2324 }
2325 } else {
2326 if (DEBUG_VISBILITY) Log.v(
2327 TAG, "Already invisible: " + r);
2328 }
2329 } else if (r.fullscreen) {
2330 if (DEBUG_VISBILITY) Log.v(
2331 TAG, "Now behindFullscreen: " + r);
2332 behindFullscreen = true;
2333 }
2334 }
2335 i--;
2336 }
2337 }
2338
2339 /**
2340 * Version of ensureActivitiesVisible that can easily be called anywhere.
2341 */
2342 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2343 int configChanges) {
2344 HistoryRecord r = topRunningActivityLocked(null);
2345 if (r != null) {
2346 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2347 }
2348 }
2349
2350 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2351 if (resumed) {
2352 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2353 } else {
2354 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2355 }
2356 }
2357
2358 /**
2359 * Ensure that the top activity in the stack is resumed.
2360 *
2361 * @param prev The previously resumed activity, for when in the process
2362 * of pausing; can be null to call from elsewhere.
2363 *
2364 * @return Returns true if something is being resumed, or false if
2365 * nothing happened.
2366 */
2367 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2368 // Find the first activity that is not finishing.
2369 HistoryRecord next = topRunningActivityLocked(null);
2370
2371 // Remember how we'll process this pause/resume situation, and ensure
2372 // that the state is reset however we wind up proceeding.
2373 final boolean userLeaving = mUserLeaving;
2374 mUserLeaving = false;
2375
2376 if (next == null) {
2377 // There are no more activities! Let's just start up the
2378 // Launcher...
2379 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2380 && mTopAction == null) {
2381 // We are running in factory test mode, but unable to find
2382 // the factory test app, so just sit around displaying the
2383 // error message and don't try to start anything.
2384 return false;
2385 }
2386 Intent intent = new Intent(
2387 mTopAction,
2388 mTopData != null ? Uri.parse(mTopData) : null);
2389 intent.setComponent(mTopComponent);
2390 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2391 intent.addCategory(Intent.CATEGORY_HOME);
2392 }
2393 ActivityInfo aInfo =
2394 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002395 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002396 if (aInfo != null) {
2397 intent.setComponent(new ComponentName(
2398 aInfo.applicationInfo.packageName, aInfo.name));
2399 // Don't do this if the home app is currently being
2400 // instrumented.
2401 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2402 aInfo.applicationInfo.uid);
2403 if (app == null || app.instrumentationClass == null) {
2404 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2405 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002406 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002407 }
2408 }
2409 return true;
2410 }
2411
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002412 next.delayedResume = false;
2413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002414 // If the top activity is the resumed one, nothing to do.
2415 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2416 // Make sure we have executed any pending transitions, since there
2417 // should be nothing left to do at this point.
2418 mWindowManager.executeAppTransition();
2419 return false;
2420 }
2421
2422 // If we are sleeping, and there is no resumed activity, and the top
2423 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002424 if ((mSleeping || mShuttingDown)
2425 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002426 // Make sure we have executed any pending transitions, since there
2427 // should be nothing left to do at this point.
2428 mWindowManager.executeAppTransition();
2429 return false;
2430 }
2431
2432 // The activity may be waiting for stop, but that is no longer
2433 // appropriate for it.
2434 mStoppingActivities.remove(next);
2435 mWaitingVisibleActivities.remove(next);
2436
2437 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2438
2439 // If we are currently pausing an activity, then don't do anything
2440 // until that is done.
2441 if (mPausingActivity != null) {
2442 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2443 return false;
2444 }
2445
2446 // We need to start pausing the current activity so the top one
2447 // can be resumed...
2448 if (mResumedActivity != null) {
2449 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2450 startPausingLocked(userLeaving, false);
2451 return true;
2452 }
2453
2454 if (prev != null && prev != next) {
2455 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2456 prev.waitingVisible = true;
2457 mWaitingVisibleActivities.add(prev);
2458 if (DEBUG_SWITCH) Log.v(
2459 TAG, "Resuming top, waiting visible to hide: " + prev);
2460 } else {
2461 // The next activity is already visible, so hide the previous
2462 // activity's windows right now so we can show the new one ASAP.
2463 // We only do this if the previous is finishing, which should mean
2464 // it is on top of the one being resumed so hiding it quickly
2465 // is good. Otherwise, we want to do the normal route of allowing
2466 // the resumed activity to be shown so we can decide if the
2467 // previous should actually be hidden depending on whether the
2468 // new one is found to be full-screen or not.
2469 if (prev.finishing) {
2470 mWindowManager.setAppVisibility(prev, false);
2471 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2472 + prev + ", waitingVisible="
2473 + (prev != null ? prev.waitingVisible : null)
2474 + ", nowVisible=" + next.nowVisible);
2475 } else {
2476 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2477 + prev + ", waitingVisible="
2478 + (prev != null ? prev.waitingVisible : null)
2479 + ", nowVisible=" + next.nowVisible);
2480 }
2481 }
2482 }
2483
2484 // We are starting up the next activity, so tell the window manager
2485 // that the previous one will be hidden soon. This way it can know
2486 // to ignore it when computing the desired screen orientation.
2487 if (prev != null) {
2488 if (prev.finishing) {
2489 if (DEBUG_TRANSITION) Log.v(TAG,
2490 "Prepare close transition: prev=" + prev);
2491 mWindowManager.prepareAppTransition(prev.task == next.task
2492 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2493 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2494 mWindowManager.setAppWillBeHidden(prev);
2495 mWindowManager.setAppVisibility(prev, false);
2496 } else {
2497 if (DEBUG_TRANSITION) Log.v(TAG,
2498 "Prepare open transition: prev=" + prev);
2499 mWindowManager.prepareAppTransition(prev.task == next.task
2500 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2501 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2502 }
2503 if (false) {
2504 mWindowManager.setAppWillBeHidden(prev);
2505 mWindowManager.setAppVisibility(prev, false);
2506 }
2507 } else if (mHistory.size() > 1) {
2508 if (DEBUG_TRANSITION) Log.v(TAG,
2509 "Prepare open transition: no previous");
2510 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2511 }
2512
2513 if (next.app != null && next.app.thread != null) {
2514 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2515
2516 // This activity is now becoming visible.
2517 mWindowManager.setAppVisibility(next, true);
2518
2519 HistoryRecord lastResumedActivity = mResumedActivity;
2520 ActivityState lastState = next.state;
2521
2522 updateCpuStats();
2523
2524 next.state = ActivityState.RESUMED;
2525 mResumedActivity = next;
2526 next.task.touchActiveTime();
2527 updateLRUListLocked(next.app, true);
2528 updateLRUListLocked(next);
2529
2530 // Have the window manager re-evaluate the orientation of
2531 // the screen based on the new activity order.
2532 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002533 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 next.mayFreezeScreenLocked(next.app) ? next : null);
2535 if (config != null) {
2536 next.frozenBeforeDestroy = true;
2537 }
2538 if (!updateConfigurationLocked(config, next)) {
2539 // The configuration update wasn't able to keep the existing
2540 // instance of the activity, and instead started a new one.
2541 // We should be all done, but let's just make sure our activity
2542 // is still at the top and schedule another run if something
2543 // weird happened.
2544 HistoryRecord nextNext = topRunningActivityLocked(null);
2545 if (DEBUG_SWITCH) Log.i(TAG,
2546 "Activity config changed during resume: " + next
2547 + ", new next: " + nextNext);
2548 if (nextNext != next) {
2549 // Do over!
2550 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2551 }
2552 mWindowManager.executeAppTransition();
2553 return true;
2554 }
2555
2556 try {
2557 // Deliver all pending results.
2558 ArrayList a = next.results;
2559 if (a != null) {
2560 final int N = a.size();
2561 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002562 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002563 TAG, "Delivering results to " + next
2564 + ": " + a);
2565 next.app.thread.scheduleSendResult(next, a);
2566 }
2567 }
2568
2569 if (next.newIntents != null) {
2570 next.app.thread.scheduleNewIntent(next.newIntents, next);
2571 }
2572
2573 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2574 System.identityHashCode(next),
2575 next.task.taskId, next.shortComponentName);
2576 updateUsageStats(next, true);
2577
2578 next.app.thread.scheduleResumeActivity(next,
2579 isNextTransitionForward());
2580 pauseIfSleepingLocked();
2581
2582 } catch (Exception e) {
2583 // Whoops, need to restart this activity!
2584 next.state = lastState;
2585 mResumedActivity = lastResumedActivity;
2586 if (Config.LOGD) Log.d(TAG,
2587 "Restarting because process died: " + next);
2588 if (!next.hasBeenLaunched) {
2589 next.hasBeenLaunched = true;
2590 } else {
2591 if (SHOW_APP_STARTING_ICON) {
2592 mWindowManager.setAppStartingWindow(
2593 next, next.packageName, next.theme,
2594 next.nonLocalizedLabel,
2595 next.labelRes, next.icon, null, true);
2596 }
2597 }
2598 startSpecificActivityLocked(next, true, false);
2599 return true;
2600 }
2601
2602 // From this point on, if something goes wrong there is no way
2603 // to recover the activity.
2604 try {
2605 next.visible = true;
2606 completeResumeLocked(next);
2607 } catch (Exception e) {
2608 // If any exception gets thrown, toss away this
2609 // activity and try the next one.
2610 Log.w(TAG, "Exception thrown during resume of " + next, e);
2611 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2612 "resume-exception");
2613 return true;
2614 }
2615
2616 // Didn't need to use the icicle, and it is now out of date.
2617 next.icicle = null;
2618 next.haveState = false;
2619 next.stopped = false;
2620
2621 } else {
2622 // Whoops, need to restart this activity!
2623 if (!next.hasBeenLaunched) {
2624 next.hasBeenLaunched = true;
2625 } else {
2626 if (SHOW_APP_STARTING_ICON) {
2627 mWindowManager.setAppStartingWindow(
2628 next, next.packageName, next.theme,
2629 next.nonLocalizedLabel,
2630 next.labelRes, next.icon, null, true);
2631 }
2632 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2633 }
2634 startSpecificActivityLocked(next, true, true);
2635 }
2636
2637 return true;
2638 }
2639
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002640 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2641 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002642 final int NH = mHistory.size();
2643
2644 int addPos = -1;
2645
2646 if (!newTask) {
2647 // If starting in an existing task, find where that is...
2648 HistoryRecord next = null;
2649 boolean startIt = true;
2650 for (int i = NH-1; i >= 0; i--) {
2651 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2652 if (p.finishing) {
2653 continue;
2654 }
2655 if (p.task == r.task) {
2656 // Here it is! Now, if this is not yet visible to the
2657 // user, then just add it without starting; it will
2658 // get started when the user navigates back to it.
2659 addPos = i+1;
2660 if (!startIt) {
2661 mHistory.add(addPos, r);
2662 r.inHistory = true;
2663 r.task.numActivities++;
2664 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2665 r.info.screenOrientation, r.fullscreen);
2666 if (VALIDATE_TOKENS) {
2667 mWindowManager.validateAppTokens(mHistory);
2668 }
2669 return;
2670 }
2671 break;
2672 }
2673 if (p.fullscreen) {
2674 startIt = false;
2675 }
2676 next = p;
2677 }
2678 }
2679
2680 // Place a new activity at top of stack, so it is next to interact
2681 // with the user.
2682 if (addPos < 0) {
2683 addPos = mHistory.size();
2684 }
2685
2686 // If we are not placing the new activity frontmost, we do not want
2687 // to deliver the onUserLeaving callback to the actual frontmost
2688 // activity
2689 if (addPos < NH) {
2690 mUserLeaving = false;
2691 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2692 }
2693
2694 // Slot the activity into the history stack and proceed
2695 mHistory.add(addPos, r);
2696 r.inHistory = true;
2697 r.frontOfTask = newTask;
2698 r.task.numActivities++;
2699 if (NH > 0) {
2700 // We want to show the starting preview window if we are
2701 // switching to a new task, or the next activity's process is
2702 // not currently running.
2703 boolean showStartingIcon = newTask;
2704 ProcessRecord proc = r.app;
2705 if (proc == null) {
2706 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2707 }
2708 if (proc == null || proc.thread == null) {
2709 showStartingIcon = true;
2710 }
2711 if (DEBUG_TRANSITION) Log.v(TAG,
2712 "Prepare open transition: starting " + r);
2713 mWindowManager.prepareAppTransition(newTask
2714 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2715 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2716 mWindowManager.addAppToken(
2717 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2718 boolean doShow = true;
2719 if (newTask) {
2720 // Even though this activity is starting fresh, we still need
2721 // to reset it to make sure we apply affinities to move any
2722 // existing activities from other tasks in to it.
2723 // If the caller has requested that the target task be
2724 // reset, then do so.
2725 if ((r.intent.getFlags()
2726 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2727 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002728 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002729 }
2730 }
2731 if (SHOW_APP_STARTING_ICON && doShow) {
2732 // Figure out if we are transitioning from another activity that is
2733 // "has the same starting icon" as the next one. This allows the
2734 // window manager to keep the previous window it had previously
2735 // created, if it still had one.
2736 HistoryRecord prev = mResumedActivity;
2737 if (prev != null) {
2738 // We don't want to reuse the previous starting preview if:
2739 // (1) The current activity is in a different task.
2740 if (prev.task != r.task) prev = null;
2741 // (2) The current activity is already displayed.
2742 else if (prev.nowVisible) prev = null;
2743 }
2744 mWindowManager.setAppStartingWindow(
2745 r, r.packageName, r.theme, r.nonLocalizedLabel,
2746 r.labelRes, r.icon, prev, showStartingIcon);
2747 }
2748 } else {
2749 // If this is the first activity, don't do any fancy animations,
2750 // because there is nothing for it to animate on top of.
2751 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2752 r.info.screenOrientation, r.fullscreen);
2753 }
2754 if (VALIDATE_TOKENS) {
2755 mWindowManager.validateAppTokens(mHistory);
2756 }
2757
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002758 if (doResume) {
2759 resumeTopActivityLocked(null);
2760 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002761 }
2762
2763 /**
2764 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002765 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2766 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002767 * an instance of that activity in the stack and, if found, finish all
2768 * activities on top of it and return the instance.
2769 *
2770 * @param newR Description of the new activity being started.
2771 * @return Returns the old activity that should be continue to be used,
2772 * or null if none was found.
2773 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002774 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 HistoryRecord newR, boolean doClear) {
2776 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002777
2778 // First find the requested task.
2779 while (i > 0) {
2780 i--;
2781 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2782 if (r.task.taskId == taskId) {
2783 i++;
2784 break;
2785 }
2786 }
2787
2788 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 while (i > 0) {
2790 i--;
2791 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2792 if (r.finishing) {
2793 continue;
2794 }
2795 if (r.task.taskId != taskId) {
2796 return null;
2797 }
2798 if (r.realActivity.equals(newR.realActivity)) {
2799 // Here it is! Now finish everything in front...
2800 HistoryRecord ret = r;
2801 if (doClear) {
2802 while (i < (mHistory.size()-1)) {
2803 i++;
2804 r = (HistoryRecord)mHistory.get(i);
2805 if (r.finishing) {
2806 continue;
2807 }
2808 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2809 null, "clear")) {
2810 i--;
2811 }
2812 }
2813 }
2814
2815 // Finally, if this is a normal launch mode (that is, not
2816 // expecting onNewIntent()), then we will finish the current
2817 // instance of the activity so a new fresh one can be started.
2818 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2819 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002820 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 if (index >= 0) {
2822 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2823 null, "clear");
2824 }
2825 return null;
2826 }
2827 }
2828
2829 return ret;
2830 }
2831 }
2832
2833 return null;
2834 }
2835
2836 /**
2837 * Find the activity in the history stack within the given task. Returns
2838 * the index within the history at which it's found, or < 0 if not found.
2839 */
2840 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2841 int i = mHistory.size();
2842 while (i > 0) {
2843 i--;
2844 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2845 if (candidate.task.taskId != task) {
2846 break;
2847 }
2848 if (candidate.realActivity.equals(r.realActivity)) {
2849 return i;
2850 }
2851 }
2852
2853 return -1;
2854 }
2855
2856 /**
2857 * Reorder the history stack so that the activity at the given index is
2858 * brought to the front.
2859 */
2860 private final HistoryRecord moveActivityToFrontLocked(int where) {
2861 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2862 int top = mHistory.size();
2863 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2864 mHistory.add(top, newTop);
2865 oldTop.frontOfTask = false;
2866 newTop.frontOfTask = true;
2867 return newTop;
2868 }
2869
2870 /**
2871 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2872 * method will be called at the proper time.
2873 */
2874 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2875 boolean sent = false;
2876 if (r.state == ActivityState.RESUMED
2877 && r.app != null && r.app.thread != null) {
2878 try {
2879 ArrayList<Intent> ar = new ArrayList<Intent>();
2880 ar.add(new Intent(intent));
2881 r.app.thread.scheduleNewIntent(ar, r);
2882 sent = true;
2883 } catch (Exception e) {
2884 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2885 }
2886 }
2887 if (!sent) {
2888 r.addNewIntentLocked(new Intent(intent));
2889 }
2890 }
2891
2892 private final void logStartActivity(int tag, HistoryRecord r,
2893 TaskRecord task) {
2894 EventLog.writeEvent(tag,
2895 System.identityHashCode(r), task.taskId,
2896 r.shortComponentName, r.intent.getAction(),
2897 r.intent.getType(), r.intent.getDataString(),
2898 r.intent.getFlags());
2899 }
2900
2901 private final int startActivityLocked(IApplicationThread caller,
2902 Intent intent, String resolvedType,
2903 Uri[] grantedUriPermissions,
2904 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2905 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002906 int callingPid, int callingUid, boolean onlyIfNeeded,
2907 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 Log.i(TAG, "Starting activity: " + intent);
2909
2910 HistoryRecord sourceRecord = null;
2911 HistoryRecord resultRecord = null;
2912 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002913 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07002914 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2916 if (index >= 0) {
2917 sourceRecord = (HistoryRecord)mHistory.get(index);
2918 if (requestCode >= 0 && !sourceRecord.finishing) {
2919 resultRecord = sourceRecord;
2920 }
2921 }
2922 }
2923
2924 int launchFlags = intent.getFlags();
2925
2926 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2927 && sourceRecord != null) {
2928 // Transfer the result target from the source activity to the new
2929 // one being started, including any failures.
2930 if (requestCode >= 0) {
2931 return START_FORWARD_AND_REQUEST_CONFLICT;
2932 }
2933 resultRecord = sourceRecord.resultTo;
2934 resultWho = sourceRecord.resultWho;
2935 requestCode = sourceRecord.requestCode;
2936 sourceRecord.resultTo = null;
2937 if (resultRecord != null) {
2938 resultRecord.removeResultsLocked(
2939 sourceRecord, resultWho, requestCode);
2940 }
2941 }
2942
2943 int err = START_SUCCESS;
2944
2945 if (intent.getComponent() == null) {
2946 // We couldn't find a class that can handle the given Intent.
2947 // That's the end of that!
2948 err = START_INTENT_NOT_RESOLVED;
2949 }
2950
2951 if (err == START_SUCCESS && aInfo == null) {
2952 // We couldn't find the specific class specified in the Intent.
2953 // Also the end of the line.
2954 err = START_CLASS_NOT_FOUND;
2955 }
2956
2957 ProcessRecord callerApp = null;
2958 if (err == START_SUCCESS && caller != null) {
2959 callerApp = getRecordForAppLocked(caller);
2960 if (callerApp != null) {
2961 callingPid = callerApp.pid;
2962 callingUid = callerApp.info.uid;
2963 } else {
2964 Log.w(TAG, "Unable to find app for caller " + caller
2965 + " (pid=" + callingPid + ") when starting: "
2966 + intent.toString());
2967 err = START_PERMISSION_DENIED;
2968 }
2969 }
2970
2971 if (err != START_SUCCESS) {
2972 if (resultRecord != null) {
2973 sendActivityResultLocked(-1,
2974 resultRecord, resultWho, requestCode,
2975 Activity.RESULT_CANCELED, null);
2976 }
2977 return err;
2978 }
2979
2980 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2981 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2982 if (perm != PackageManager.PERMISSION_GRANTED) {
2983 if (resultRecord != null) {
2984 sendActivityResultLocked(-1,
2985 resultRecord, resultWho, requestCode,
2986 Activity.RESULT_CANCELED, null);
2987 }
2988 String msg = "Permission Denial: starting " + intent.toString()
2989 + " from " + callerApp + " (pid=" + callingPid
2990 + ", uid=" + callingUid + ")"
2991 + " requires " + aInfo.permission;
2992 Log.w(TAG, msg);
2993 throw new SecurityException(msg);
2994 }
2995
2996 if (mWatcher != null) {
2997 boolean abort = false;
2998 try {
2999 // The Intent we give to the watcher has the extra data
3000 // stripped off, since it can contain private information.
3001 Intent watchIntent = intent.cloneFilter();
3002 abort = !mWatcher.activityStarting(watchIntent,
3003 aInfo.applicationInfo.packageName);
3004 } catch (RemoteException e) {
3005 mWatcher = null;
3006 }
3007
3008 if (abort) {
3009 if (resultRecord != null) {
3010 sendActivityResultLocked(-1,
3011 resultRecord, resultWho, requestCode,
3012 Activity.RESULT_CANCELED, null);
3013 }
3014 // We pretend to the caller that it was really started, but
3015 // they will just get a cancel result.
3016 return START_SUCCESS;
3017 }
3018 }
3019
3020 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3021 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003022 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003023
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003024 if (mResumedActivity == null
3025 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3026 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3027 PendingActivityLaunch pal = new PendingActivityLaunch();
3028 pal.r = r;
3029 pal.sourceRecord = sourceRecord;
3030 pal.grantedUriPermissions = grantedUriPermissions;
3031 pal.grantedMode = grantedMode;
3032 pal.onlyIfNeeded = onlyIfNeeded;
3033 mPendingActivityLaunches.add(pal);
3034 return START_SWITCHES_CANCELED;
3035 }
3036 }
3037
3038 if (mDidAppSwitch) {
3039 // This is the second allowed switch since we stopped switches,
3040 // so now just generally allow switches. Use case: user presses
3041 // home (switches disabled, switch to home, mDidAppSwitch now true);
3042 // user taps a home icon (coming from home so allowed, we hit here
3043 // and now allow anyone to switch again).
3044 mAppSwitchesAllowedTime = 0;
3045 } else {
3046 mDidAppSwitch = true;
3047 }
3048
3049 doPendingActivityLaunchesLocked(false);
3050
3051 return startActivityUncheckedLocked(r, sourceRecord,
3052 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3053 }
3054
3055 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3056 final int N = mPendingActivityLaunches.size();
3057 if (N <= 0) {
3058 return;
3059 }
3060 for (int i=0; i<N; i++) {
3061 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3062 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3063 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3064 doResume && i == (N-1));
3065 }
3066 mPendingActivityLaunches.clear();
3067 }
3068
3069 private final int startActivityUncheckedLocked(HistoryRecord r,
3070 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3071 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3072 final Intent intent = r.intent;
3073 final int callingUid = r.launchedFromUid;
3074
3075 int launchFlags = intent.getFlags();
3076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003077 // We'll invoke onUserLeaving before onPause only if the launching
3078 // activity did not explicitly state that this is an automated launch.
3079 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3080 if (DEBUG_USER_LEAVING) Log.v(TAG,
3081 "startActivity() => mUserLeaving=" + mUserLeaving);
3082
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003083 // If the caller has asked not to resume at this point, we make note
3084 // of this in the record so that we can skip it when trying to find
3085 // the top running activity.
3086 if (!doResume) {
3087 r.delayedResume = true;
3088 }
3089
3090 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3091 != 0 ? r : null;
3092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003093 // If the onlyIfNeeded flag is set, then we can do this if the activity
3094 // being launched is the same as the one making the call... or, as
3095 // a special case, if we do not know the caller then we count the
3096 // current top activity as the caller.
3097 if (onlyIfNeeded) {
3098 HistoryRecord checkedCaller = sourceRecord;
3099 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003100 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 }
3102 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3103 // Caller is not the same as launcher, so always needed.
3104 onlyIfNeeded = false;
3105 }
3106 }
3107
3108 if (grantedUriPermissions != null && callingUid > 0) {
3109 for (int i=0; i<grantedUriPermissions.length; i++) {
3110 grantUriPermissionLocked(callingUid, r.packageName,
3111 grantedUriPermissions[i], grantedMode, r);
3112 }
3113 }
3114
3115 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3116 intent, r);
3117
3118 if (sourceRecord == null) {
3119 // This activity is not being started from another... in this
3120 // case we -always- start a new task.
3121 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3122 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3123 + intent);
3124 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3125 }
3126 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3127 // The original activity who is starting us is running as a single
3128 // instance... this new activity it is starting must go on its
3129 // own task.
3130 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3131 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3132 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3133 // The activity being started is a single instance... it always
3134 // gets launched into its own task.
3135 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3136 }
3137
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003138 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003139 // For whatever reason this activity is being launched into a new
3140 // task... yet the caller has requested a result back. Well, that
3141 // is pretty messed up, so instead immediately send back a cancel
3142 // and let the new task continue launched as normal without a
3143 // dependency on its originator.
3144 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3145 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003146 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 Activity.RESULT_CANCELED, null);
3148 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149 }
3150
3151 boolean addingToTask = false;
3152 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3153 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3154 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3155 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3156 // If bring to front is requested, and no result is requested, and
3157 // we can find a task that was started with this same
3158 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003159 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 // See if there is a task to bring to the front. If this is
3161 // a SINGLE_INSTANCE activity, there can be one and only one
3162 // instance of it in the history, and it is always in its own
3163 // unique task, so we do a special search.
3164 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3165 ? findTaskLocked(intent, r.info)
3166 : findActivityLocked(intent, r.info);
3167 if (taskTop != null) {
3168 if (taskTop.task.intent == null) {
3169 // This task was started because of movement of
3170 // the activity based on affinity... now that we
3171 // are actually launching it, we can assign the
3172 // base intent.
3173 taskTop.task.setIntent(intent, r.info);
3174 }
3175 // If the target task is not in the front, then we need
3176 // to bring it to the front... except... well, with
3177 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3178 // to have the same behavior as if a new instance was
3179 // being started, which means not bringing it to the front
3180 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003181 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 if (curTop.task != taskTop.task) {
3183 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3184 boolean callerAtFront = sourceRecord == null
3185 || curTop.task == sourceRecord.task;
3186 if (callerAtFront) {
3187 // We really do want to push this one into the
3188 // user's face, right now.
3189 moveTaskToFrontLocked(taskTop.task);
3190 }
3191 }
3192 // If the caller has requested that the target task be
3193 // reset, then do so.
3194 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3195 taskTop = resetTaskIfNeededLocked(taskTop, r);
3196 }
3197 if (onlyIfNeeded) {
3198 // We don't need to start a new activity, and
3199 // the client said not to do anything if that
3200 // is the case, so this is it! And for paranoia, make
3201 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003202 if (doResume) {
3203 resumeTopActivityLocked(null);
3204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003205 return START_RETURN_INTENT_TO_CALLER;
3206 }
3207 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3208 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3209 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3210 // In this situation we want to remove all activities
3211 // from the task up to the one being started. In most
3212 // cases this means we are resetting the task to its
3213 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003214 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003215 taskTop.task.taskId, r, true);
3216 if (top != null) {
3217 if (top.frontOfTask) {
3218 // Activity aliases may mean we use different
3219 // intents for the top activity, so make sure
3220 // the task now has the identity of the new
3221 // intent.
3222 top.task.setIntent(r.intent, r.info);
3223 }
3224 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3225 deliverNewIntentLocked(top, r.intent);
3226 } else {
3227 // A special case: we need to
3228 // start the activity because it is not currently
3229 // running, and the caller has asked to clear the
3230 // current task to have this activity at the top.
3231 addingToTask = true;
3232 // Now pretend like this activity is being started
3233 // by the top of its task, so it is put in the
3234 // right place.
3235 sourceRecord = taskTop;
3236 }
3237 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3238 // In this case the top activity on the task is the
3239 // same as the one being launched, so we take that
3240 // as a request to bring the task to the foreground.
3241 // If the top activity in the task is the root
3242 // activity, deliver this new intent to it if it
3243 // desires.
3244 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3245 && taskTop.realActivity.equals(r.realActivity)) {
3246 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3247 if (taskTop.frontOfTask) {
3248 taskTop.task.setIntent(r.intent, r.info);
3249 }
3250 deliverNewIntentLocked(taskTop, r.intent);
3251 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3252 // In this case we are launching the root activity
3253 // of the task, but with a different intent. We
3254 // should start a new instance on top.
3255 addingToTask = true;
3256 sourceRecord = taskTop;
3257 }
3258 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3259 // In this case an activity is being launched in to an
3260 // existing task, without resetting that task. This
3261 // is typically the situation of launching an activity
3262 // from a notification or shortcut. We want to place
3263 // the new activity on top of the current task.
3264 addingToTask = true;
3265 sourceRecord = taskTop;
3266 } else if (!taskTop.task.rootWasReset) {
3267 // In this case we are launching in to an existing task
3268 // that has not yet been started from its front door.
3269 // The current task has been brought to the front.
3270 // Ideally, we'd probably like to place this new task
3271 // at the bottom of its stack, but that's a little hard
3272 // to do with the current organization of the code so
3273 // for now we'll just drop it.
3274 taskTop.task.setIntent(r.intent, r.info);
3275 }
3276 if (!addingToTask) {
3277 // We didn't do anything... but it was needed (a.k.a., client
3278 // don't use that intent!) And for paranoia, make
3279 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003280 if (doResume) {
3281 resumeTopActivityLocked(null);
3282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 return START_TASK_TO_FRONT;
3284 }
3285 }
3286 }
3287 }
3288
3289 //String uri = r.intent.toURI();
3290 //Intent intent2 = new Intent(uri);
3291 //Log.i(TAG, "Given intent: " + r.intent);
3292 //Log.i(TAG, "URI is: " + uri);
3293 //Log.i(TAG, "To intent: " + intent2);
3294
3295 if (r.packageName != null) {
3296 // If the activity being launched is the same as the one currently
3297 // at the top, then we need to check if it should only be launched
3298 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003299 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3300 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 if (top.realActivity.equals(r.realActivity)) {
3302 if (top.app != null && top.app.thread != null) {
3303 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3304 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3305 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3306 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3307 // For paranoia, make sure we have correctly
3308 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003309 if (doResume) {
3310 resumeTopActivityLocked(null);
3311 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003312 if (onlyIfNeeded) {
3313 // We don't need to start a new activity, and
3314 // the client said not to do anything if that
3315 // is the case, so this is it!
3316 return START_RETURN_INTENT_TO_CALLER;
3317 }
3318 deliverNewIntentLocked(top, r.intent);
3319 return START_DELIVERED_TO_TOP;
3320 }
3321 }
3322 }
3323 }
3324
3325 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003326 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003328 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 Activity.RESULT_CANCELED, null);
3330 }
3331 return START_CLASS_NOT_FOUND;
3332 }
3333
3334 boolean newTask = false;
3335
3336 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003337 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3339 // todo: should do better management of integers.
3340 mCurTask++;
3341 if (mCurTask <= 0) {
3342 mCurTask = 1;
3343 }
3344 r.task = new TaskRecord(mCurTask, r.info, intent,
3345 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3346 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3347 + " in new task " + r.task);
3348 newTask = true;
3349 addRecentTask(r.task);
3350
3351 } else if (sourceRecord != null) {
3352 if (!addingToTask &&
3353 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3354 // In this case, we are adding the activity to an existing
3355 // task, but the caller has asked to clear that task if the
3356 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003357 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003358 sourceRecord.task.taskId, r, true);
3359 if (top != null) {
3360 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3361 deliverNewIntentLocked(top, r.intent);
3362 // For paranoia, make sure we have correctly
3363 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003364 if (doResume) {
3365 resumeTopActivityLocked(null);
3366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003367 return START_DELIVERED_TO_TOP;
3368 }
3369 } else if (!addingToTask &&
3370 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3371 // In this case, we are launching an activity in our own task
3372 // that may already be running somewhere in the history, and
3373 // we want to shuffle it to the front of the stack if so.
3374 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3375 if (where >= 0) {
3376 HistoryRecord top = moveActivityToFrontLocked(where);
3377 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3378 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003379 if (doResume) {
3380 resumeTopActivityLocked(null);
3381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382 return START_DELIVERED_TO_TOP;
3383 }
3384 }
3385 // An existing activity is starting this new activity, so we want
3386 // to keep the new one in the same task as the one that is starting
3387 // it.
3388 r.task = sourceRecord.task;
3389 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3390 + " in existing task " + r.task);
3391
3392 } else {
3393 // This not being started from an existing activity, and not part
3394 // of a new task... just put it in the top task, though these days
3395 // this case should never happen.
3396 final int N = mHistory.size();
3397 HistoryRecord prev =
3398 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3399 r.task = prev != null
3400 ? prev.task
3401 : new TaskRecord(mCurTask, r.info, intent,
3402 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3403 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3404 + " in new guessed " + r.task);
3405 }
3406 if (newTask) {
3407 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3408 }
3409 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003410 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 return START_SUCCESS;
3412 }
3413
3414 public final int startActivity(IApplicationThread caller,
3415 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3416 int grantedMode, IBinder resultTo,
3417 String resultWho, int requestCode, boolean onlyIfNeeded,
3418 boolean debug) {
3419 // Refuse possible leaked file descriptors
3420 if (intent != null && intent.hasFileDescriptors()) {
3421 throw new IllegalArgumentException("File descriptors passed in Intent");
3422 }
3423
The Android Open Source Project4df24232009-03-05 14:34:35 -08003424 final boolean componentSpecified = intent.getComponent() != null;
3425
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003426 // Don't modify the client's object!
3427 intent = new Intent(intent);
3428
3429 // Collect information about the target of the Intent.
3430 // Must do this before locking, because resolving the intent
3431 // may require launching a process to run its content provider.
3432 ActivityInfo aInfo;
3433 try {
3434 ResolveInfo rInfo =
3435 ActivityThread.getPackageManager().resolveIntent(
3436 intent, resolvedType,
3437 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003438 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003439 aInfo = rInfo != null ? rInfo.activityInfo : null;
3440 } catch (RemoteException e) {
3441 aInfo = null;
3442 }
3443
3444 if (aInfo != null) {
3445 // Store the found target back into the intent, because now that
3446 // we have it we never want to do this again. For example, if the
3447 // user navigates back to this point in the history, we should
3448 // always restart the exact same activity.
3449 intent.setComponent(new ComponentName(
3450 aInfo.applicationInfo.packageName, aInfo.name));
3451
3452 // Don't debug things in the system process
3453 if (debug) {
3454 if (!aInfo.processName.equals("system")) {
3455 setDebugApp(aInfo.processName, true, false);
3456 }
3457 }
3458 }
3459
3460 synchronized(this) {
3461 final long origId = Binder.clearCallingIdentity();
3462 int res = startActivityLocked(caller, intent, resolvedType,
3463 grantedUriPermissions, grantedMode, aInfo,
3464 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003465 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 Binder.restoreCallingIdentity(origId);
3467 return res;
3468 }
3469 }
3470
3471 public boolean startNextMatchingActivity(IBinder callingActivity,
3472 Intent intent) {
3473 // Refuse possible leaked file descriptors
3474 if (intent != null && intent.hasFileDescriptors() == true) {
3475 throw new IllegalArgumentException("File descriptors passed in Intent");
3476 }
3477
3478 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003479 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003480 if (index < 0) {
3481 return false;
3482 }
3483 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3484 if (r.app == null || r.app.thread == null) {
3485 // The caller is not running... d'oh!
3486 return false;
3487 }
3488 intent = new Intent(intent);
3489 // The caller is not allowed to change the data.
3490 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3491 // And we are resetting to find the next component...
3492 intent.setComponent(null);
3493
3494 ActivityInfo aInfo = null;
3495 try {
3496 List<ResolveInfo> resolves =
3497 ActivityThread.getPackageManager().queryIntentActivities(
3498 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003499 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500
3501 // Look for the original activity in the list...
3502 final int N = resolves != null ? resolves.size() : 0;
3503 for (int i=0; i<N; i++) {
3504 ResolveInfo rInfo = resolves.get(i);
3505 if (rInfo.activityInfo.packageName.equals(r.packageName)
3506 && rInfo.activityInfo.name.equals(r.info.name)) {
3507 // We found the current one... the next matching is
3508 // after it.
3509 i++;
3510 if (i<N) {
3511 aInfo = resolves.get(i).activityInfo;
3512 }
3513 break;
3514 }
3515 }
3516 } catch (RemoteException e) {
3517 }
3518
3519 if (aInfo == null) {
3520 // Nobody who is next!
3521 return false;
3522 }
3523
3524 intent.setComponent(new ComponentName(
3525 aInfo.applicationInfo.packageName, aInfo.name));
3526 intent.setFlags(intent.getFlags()&~(
3527 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3528 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3529 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3530 Intent.FLAG_ACTIVITY_NEW_TASK));
3531
3532 // Okay now we need to start the new activity, replacing the
3533 // currently running activity. This is a little tricky because
3534 // we want to start the new one as if the current one is finished,
3535 // but not finish the current one first so that there is no flicker.
3536 // And thus...
3537 final boolean wasFinishing = r.finishing;
3538 r.finishing = true;
3539
3540 // Propagate reply information over to the new activity.
3541 final HistoryRecord resultTo = r.resultTo;
3542 final String resultWho = r.resultWho;
3543 final int requestCode = r.requestCode;
3544 r.resultTo = null;
3545 if (resultTo != null) {
3546 resultTo.removeResultsLocked(r, resultWho, requestCode);
3547 }
3548
3549 final long origId = Binder.clearCallingIdentity();
3550 // XXX we are not dealing with propagating grantedUriPermissions...
3551 // those are not yet exposed to user code, so there is no need.
3552 int res = startActivityLocked(r.app.thread, intent,
3553 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003554 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 Binder.restoreCallingIdentity(origId);
3556
3557 r.finishing = wasFinishing;
3558 if (res != START_SUCCESS) {
3559 return false;
3560 }
3561 return true;
3562 }
3563 }
3564
3565 final int startActivityInPackage(int uid,
3566 Intent intent, String resolvedType, IBinder resultTo,
3567 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003568 final boolean componentSpecified = intent.getComponent() != null;
3569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003570 // Don't modify the client's object!
3571 intent = new Intent(intent);
3572
3573 // Collect information about the target of the Intent.
3574 // Must do this before locking, because resolving the intent
3575 // may require launching a process to run its content provider.
3576 ActivityInfo aInfo;
3577 try {
3578 ResolveInfo rInfo =
3579 ActivityThread.getPackageManager().resolveIntent(
3580 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003581 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 aInfo = rInfo != null ? rInfo.activityInfo : null;
3583 } catch (RemoteException e) {
3584 aInfo = null;
3585 }
3586
3587 if (aInfo != null) {
3588 // Store the found target back into the intent, because now that
3589 // we have it we never want to do this again. For example, if the
3590 // user navigates back to this point in the history, we should
3591 // always restart the exact same activity.
3592 intent.setComponent(new ComponentName(
3593 aInfo.applicationInfo.packageName, aInfo.name));
3594 }
3595
3596 synchronized(this) {
3597 return startActivityLocked(null, intent, resolvedType,
3598 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003599 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 }
3601 }
3602
3603 private final void addRecentTask(TaskRecord task) {
3604 // Remove any existing entries that are the same kind of task.
3605 int N = mRecentTasks.size();
3606 for (int i=0; i<N; i++) {
3607 TaskRecord tr = mRecentTasks.get(i);
3608 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3609 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3610 mRecentTasks.remove(i);
3611 i--;
3612 N--;
3613 if (task.intent == null) {
3614 // If the new recent task we are adding is not fully
3615 // specified, then replace it with the existing recent task.
3616 task = tr;
3617 }
3618 }
3619 }
3620 if (N >= MAX_RECENT_TASKS) {
3621 mRecentTasks.remove(N-1);
3622 }
3623 mRecentTasks.add(0, task);
3624 }
3625
3626 public void setRequestedOrientation(IBinder token,
3627 int requestedOrientation) {
3628 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003629 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003630 if (index < 0) {
3631 return;
3632 }
3633 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3634 final long origId = Binder.clearCallingIdentity();
3635 mWindowManager.setAppOrientation(r, requestedOrientation);
3636 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003637 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003638 r.mayFreezeScreenLocked(r.app) ? r : null);
3639 if (config != null) {
3640 r.frozenBeforeDestroy = true;
3641 if (!updateConfigurationLocked(config, r)) {
3642 resumeTopActivityLocked(null);
3643 }
3644 }
3645 Binder.restoreCallingIdentity(origId);
3646 }
3647 }
3648
3649 public int getRequestedOrientation(IBinder token) {
3650 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003651 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003652 if (index < 0) {
3653 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3654 }
3655 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3656 return mWindowManager.getAppOrientation(r);
3657 }
3658 }
3659
3660 private final void stopActivityLocked(HistoryRecord r) {
3661 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3662 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3663 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3664 if (!r.finishing) {
3665 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3666 "no-history");
3667 }
3668 } else if (r.app != null && r.app.thread != null) {
3669 if (mFocusedActivity == r) {
3670 setFocusedActivityLocked(topRunningActivityLocked(null));
3671 }
3672 r.resumeKeyDispatchingLocked();
3673 try {
3674 r.stopped = false;
3675 r.state = ActivityState.STOPPING;
3676 if (DEBUG_VISBILITY) Log.v(
3677 TAG, "Stopping visible=" + r.visible + " for " + r);
3678 if (!r.visible) {
3679 mWindowManager.setAppVisibility(r, false);
3680 }
3681 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3682 } catch (Exception e) {
3683 // Maybe just ignore exceptions here... if the process
3684 // has crashed, our death notification will clean things
3685 // up.
3686 Log.w(TAG, "Exception thrown during pause", e);
3687 // Just in case, assume it to be stopped.
3688 r.stopped = true;
3689 r.state = ActivityState.STOPPED;
3690 if (r.configDestroy) {
3691 destroyActivityLocked(r, true);
3692 }
3693 }
3694 }
3695 }
3696
3697 /**
3698 * @return Returns true if the activity is being finished, false if for
3699 * some reason it is being left as-is.
3700 */
3701 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3702 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003703 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003704 TAG, "Finishing activity: token=" + token
3705 + ", result=" + resultCode + ", data=" + resultData);
3706
Dianne Hackborn75b03852009-06-12 15:43:26 -07003707 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003708 if (index < 0) {
3709 return false;
3710 }
3711 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3712
3713 // Is this the last activity left?
3714 boolean lastActivity = true;
3715 for (int i=mHistory.size()-1; i>=0; i--) {
3716 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3717 if (!p.finishing && p != r) {
3718 lastActivity = false;
3719 break;
3720 }
3721 }
3722
3723 // If this is the last activity, but it is the home activity, then
3724 // just don't finish it.
3725 if (lastActivity) {
3726 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3727 return false;
3728 }
3729 }
3730
3731 finishActivityLocked(r, index, resultCode, resultData, reason);
3732 return true;
3733 }
3734
3735 /**
3736 * @return Returns true if this activity has been removed from the history
3737 * list, or false if it is still in the list and will be removed later.
3738 */
3739 private final boolean finishActivityLocked(HistoryRecord r, int index,
3740 int resultCode, Intent resultData, String reason) {
3741 if (r.finishing) {
3742 Log.w(TAG, "Duplicate finish request for " + r);
3743 return false;
3744 }
3745
3746 r.finishing = true;
3747 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3748 System.identityHashCode(r),
3749 r.task.taskId, r.shortComponentName, reason);
3750 r.task.numActivities--;
3751 if (r.frontOfTask && index < (mHistory.size()-1)) {
3752 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3753 if (next.task == r.task) {
3754 next.frontOfTask = true;
3755 }
3756 }
3757
3758 r.pauseKeyDispatchingLocked();
3759 if (mFocusedActivity == r) {
3760 setFocusedActivityLocked(topRunningActivityLocked(null));
3761 }
3762
3763 // send the result
3764 HistoryRecord resultTo = r.resultTo;
3765 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003766 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3767 + " who=" + r.resultWho + " req=" + r.requestCode
3768 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003769 if (r.info.applicationInfo.uid > 0) {
3770 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3771 r.packageName, resultData, r);
3772 }
3773 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3774 resultData);
3775 r.resultTo = null;
3776 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003777 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003778
3779 // Make sure this HistoryRecord is not holding on to other resources,
3780 // because clients have remote IPC references to this object so we
3781 // can't assume that will go away and want to avoid circular IPC refs.
3782 r.results = null;
3783 r.pendingResults = null;
3784 r.newIntents = null;
3785 r.icicle = null;
3786
3787 if (mPendingThumbnails.size() > 0) {
3788 // There are clients waiting to receive thumbnails so, in case
3789 // this is an activity that someone is waiting for, add it
3790 // to the pending list so we can correctly update the clients.
3791 mCancelledThumbnails.add(r);
3792 }
3793
3794 if (mResumedActivity == r) {
3795 boolean endTask = index <= 0
3796 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3797 if (DEBUG_TRANSITION) Log.v(TAG,
3798 "Prepare close transition: finishing " + r);
3799 mWindowManager.prepareAppTransition(endTask
3800 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3801 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3802
3803 // Tell window manager to prepare for this one to be removed.
3804 mWindowManager.setAppVisibility(r, false);
3805
3806 if (mPausingActivity == null) {
3807 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3808 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3809 startPausingLocked(false, false);
3810 }
3811
3812 } else if (r.state != ActivityState.PAUSING) {
3813 // If the activity is PAUSING, we will complete the finish once
3814 // it is done pausing; else we can just directly finish it here.
3815 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3816 return finishCurrentActivityLocked(r, index,
3817 FINISH_AFTER_PAUSE) == null;
3818 } else {
3819 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3820 }
3821
3822 return false;
3823 }
3824
3825 private static final int FINISH_IMMEDIATELY = 0;
3826 private static final int FINISH_AFTER_PAUSE = 1;
3827 private static final int FINISH_AFTER_VISIBLE = 2;
3828
3829 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3830 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003831 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003832 if (index < 0) {
3833 return null;
3834 }
3835
3836 return finishCurrentActivityLocked(r, index, mode);
3837 }
3838
3839 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3840 int index, int mode) {
3841 // First things first: if this activity is currently visible,
3842 // and the resumed activity is not yet visible, then hold off on
3843 // finishing until the resumed one becomes visible.
3844 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3845 if (!mStoppingActivities.contains(r)) {
3846 mStoppingActivities.add(r);
3847 if (mStoppingActivities.size() > 3) {
3848 // If we already have a few activities waiting to stop,
3849 // then give up on things going idle and start clearing
3850 // them out.
3851 Message msg = Message.obtain();
3852 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3853 mHandler.sendMessage(msg);
3854 }
3855 }
3856 r.state = ActivityState.STOPPING;
3857 updateOomAdjLocked();
3858 return r;
3859 }
3860
3861 // make sure the record is cleaned out of other places.
3862 mStoppingActivities.remove(r);
3863 mWaitingVisibleActivities.remove(r);
3864 if (mResumedActivity == r) {
3865 mResumedActivity = null;
3866 }
3867 final ActivityState prevState = r.state;
3868 r.state = ActivityState.FINISHING;
3869
3870 if (mode == FINISH_IMMEDIATELY
3871 || prevState == ActivityState.STOPPED
3872 || prevState == ActivityState.INITIALIZING) {
3873 // If this activity is already stopped, we can just finish
3874 // it right now.
3875 return destroyActivityLocked(r, true) ? null : r;
3876 } else {
3877 // Need to go through the full pause cycle to get this
3878 // activity into the stopped state and then finish it.
3879 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3880 mFinishingActivities.add(r);
3881 resumeTopActivityLocked(null);
3882 }
3883 return r;
3884 }
3885
3886 /**
3887 * This is the internal entry point for handling Activity.finish().
3888 *
3889 * @param token The Binder token referencing the Activity we want to finish.
3890 * @param resultCode Result code, if any, from this Activity.
3891 * @param resultData Result data (Intent), if any, from this Activity.
3892 *
3893 * @result Returns true if the activity successfully finished, or false if it is still running.
3894 */
3895 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3896 // Refuse possible leaked file descriptors
3897 if (resultData != null && resultData.hasFileDescriptors() == true) {
3898 throw new IllegalArgumentException("File descriptors passed in Intent");
3899 }
3900
3901 synchronized(this) {
3902 if (mWatcher != null) {
3903 // Find the first activity that is not finishing.
3904 HistoryRecord next = topRunningActivityLocked(token, 0);
3905 if (next != null) {
3906 // ask watcher if this is allowed
3907 boolean resumeOK = true;
3908 try {
3909 resumeOK = mWatcher.activityResuming(next.packageName);
3910 } catch (RemoteException e) {
3911 mWatcher = null;
3912 }
3913
3914 if (!resumeOK) {
3915 return false;
3916 }
3917 }
3918 }
3919 final long origId = Binder.clearCallingIdentity();
3920 boolean res = requestFinishActivityLocked(token, resultCode,
3921 resultData, "app-request");
3922 Binder.restoreCallingIdentity(origId);
3923 return res;
3924 }
3925 }
3926
3927 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3928 String resultWho, int requestCode, int resultCode, Intent data) {
3929
3930 if (callingUid > 0) {
3931 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3932 data, r);
3933 }
3934
The Android Open Source Project10592532009-03-18 17:39:46 -07003935 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3936 + " : who=" + resultWho + " req=" + requestCode
3937 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003938 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3939 try {
3940 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3941 list.add(new ResultInfo(resultWho, requestCode,
3942 resultCode, data));
3943 r.app.thread.scheduleSendResult(r, list);
3944 return;
3945 } catch (Exception e) {
3946 Log.w(TAG, "Exception thrown sending result to " + r, e);
3947 }
3948 }
3949
3950 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3951 }
3952
3953 public final void finishSubActivity(IBinder token, String resultWho,
3954 int requestCode) {
3955 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003956 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003957 if (index < 0) {
3958 return;
3959 }
3960 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3961
3962 final long origId = Binder.clearCallingIdentity();
3963
3964 int i;
3965 for (i=mHistory.size()-1; i>=0; i--) {
3966 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3967 if (r.resultTo == self && r.requestCode == requestCode) {
3968 if ((r.resultWho == null && resultWho == null) ||
3969 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3970 finishActivityLocked(r, i,
3971 Activity.RESULT_CANCELED, null, "request-sub");
3972 }
3973 }
3974 }
3975
3976 Binder.restoreCallingIdentity(origId);
3977 }
3978 }
3979
3980 /**
3981 * Perform clean-up of service connections in an activity record.
3982 */
3983 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3984 // Throw away any services that have been bound by this activity.
3985 if (r.connections != null) {
3986 Iterator<ConnectionRecord> it = r.connections.iterator();
3987 while (it.hasNext()) {
3988 ConnectionRecord c = it.next();
3989 removeConnectionLocked(c, null, r);
3990 }
3991 r.connections = null;
3992 }
3993 }
3994
3995 /**
3996 * Perform the common clean-up of an activity record. This is called both
3997 * as part of destroyActivityLocked() (when destroying the client-side
3998 * representation) and cleaning things up as a result of its hosting
3999 * processing going away, in which case there is no remaining client-side
4000 * state to destroy so only the cleanup here is needed.
4001 */
4002 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4003 if (mResumedActivity == r) {
4004 mResumedActivity = null;
4005 }
4006 if (mFocusedActivity == r) {
4007 mFocusedActivity = null;
4008 }
4009
4010 r.configDestroy = false;
4011 r.frozenBeforeDestroy = false;
4012
4013 // Make sure this record is no longer in the pending finishes list.
4014 // This could happen, for example, if we are trimming activities
4015 // down to the max limit while they are still waiting to finish.
4016 mFinishingActivities.remove(r);
4017 mWaitingVisibleActivities.remove(r);
4018
4019 // Remove any pending results.
4020 if (r.finishing && r.pendingResults != null) {
4021 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4022 PendingIntentRecord rec = apr.get();
4023 if (rec != null) {
4024 cancelIntentSenderLocked(rec, false);
4025 }
4026 }
4027 r.pendingResults = null;
4028 }
4029
4030 if (cleanServices) {
4031 cleanUpActivityServicesLocked(r);
4032 }
4033
4034 if (mPendingThumbnails.size() > 0) {
4035 // There are clients waiting to receive thumbnails so, in case
4036 // this is an activity that someone is waiting for, add it
4037 // to the pending list so we can correctly update the clients.
4038 mCancelledThumbnails.add(r);
4039 }
4040
4041 // Get rid of any pending idle timeouts.
4042 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4043 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4044 }
4045
4046 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4047 if (r.state != ActivityState.DESTROYED) {
4048 mHistory.remove(r);
4049 r.inHistory = false;
4050 r.state = ActivityState.DESTROYED;
4051 mWindowManager.removeAppToken(r);
4052 if (VALIDATE_TOKENS) {
4053 mWindowManager.validateAppTokens(mHistory);
4054 }
4055 cleanUpActivityServicesLocked(r);
4056 removeActivityUriPermissionsLocked(r);
4057 }
4058 }
4059
4060 /**
4061 * Destroy the current CLIENT SIDE instance of an activity. This may be
4062 * called both when actually finishing an activity, or when performing
4063 * a configuration switch where we destroy the current client-side object
4064 * but then create a new client-side object for this same HistoryRecord.
4065 */
4066 private final boolean destroyActivityLocked(HistoryRecord r,
4067 boolean removeFromApp) {
4068 if (DEBUG_SWITCH) Log.v(
4069 TAG, "Removing activity: token=" + r
4070 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4071 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4072 System.identityHashCode(r),
4073 r.task.taskId, r.shortComponentName);
4074
4075 boolean removedFromHistory = false;
4076
4077 cleanUpActivityLocked(r, false);
4078
4079 if (r.app != null) {
4080 if (removeFromApp) {
4081 int idx = r.app.activities.indexOf(r);
4082 if (idx >= 0) {
4083 r.app.activities.remove(idx);
4084 }
4085 if (r.persistent) {
4086 decPersistentCountLocked(r.app);
4087 }
4088 }
4089
4090 boolean skipDestroy = false;
4091
4092 try {
4093 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4094 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4095 r.configChangeFlags);
4096 } catch (Exception e) {
4097 // We can just ignore exceptions here... if the process
4098 // has crashed, our death notification will clean things
4099 // up.
4100 //Log.w(TAG, "Exception thrown during finish", e);
4101 if (r.finishing) {
4102 removeActivityFromHistoryLocked(r);
4103 removedFromHistory = true;
4104 skipDestroy = true;
4105 }
4106 }
4107
4108 r.app = null;
4109 r.nowVisible = false;
4110
4111 if (r.finishing && !skipDestroy) {
4112 r.state = ActivityState.DESTROYING;
4113 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4114 msg.obj = r;
4115 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4116 } else {
4117 r.state = ActivityState.DESTROYED;
4118 }
4119 } else {
4120 // remove this record from the history.
4121 if (r.finishing) {
4122 removeActivityFromHistoryLocked(r);
4123 removedFromHistory = true;
4124 } else {
4125 r.state = ActivityState.DESTROYED;
4126 }
4127 }
4128
4129 r.configChangeFlags = 0;
4130
4131 if (!mLRUActivities.remove(r)) {
4132 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4133 }
4134
4135 return removedFromHistory;
4136 }
4137
4138 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4139 ProcessRecord app)
4140 {
4141 int i = list.size();
4142 if (localLOGV) Log.v(
4143 TAG, "Removing app " + app + " from list " + list
4144 + " with " + i + " entries");
4145 while (i > 0) {
4146 i--;
4147 HistoryRecord r = (HistoryRecord)list.get(i);
4148 if (localLOGV) Log.v(
4149 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4150 if (r.app == app) {
4151 if (localLOGV) Log.v(TAG, "Removing this entry!");
4152 list.remove(i);
4153 }
4154 }
4155 }
4156
4157 /**
4158 * Main function for removing an existing process from the activity manager
4159 * as a result of that process going away. Clears out all connections
4160 * to the process.
4161 */
4162 private final void handleAppDiedLocked(ProcessRecord app,
4163 boolean restarting) {
4164 cleanUpApplicationRecordLocked(app, restarting, -1);
4165 if (!restarting) {
4166 mLRUProcesses.remove(app);
4167 }
4168
4169 // Just in case...
4170 if (mPausingActivity != null && mPausingActivity.app == app) {
4171 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4172 mPausingActivity = null;
4173 }
4174 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4175 mLastPausedActivity = null;
4176 }
4177
4178 // Remove this application's activities from active lists.
4179 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4180 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4181 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4182 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4183
4184 boolean atTop = true;
4185 boolean hasVisibleActivities = false;
4186
4187 // Clean out the history list.
4188 int i = mHistory.size();
4189 if (localLOGV) Log.v(
4190 TAG, "Removing app " + app + " from history with " + i + " entries");
4191 while (i > 0) {
4192 i--;
4193 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4194 if (localLOGV) Log.v(
4195 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4196 if (r.app == app) {
4197 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4198 if (localLOGV) Log.v(
4199 TAG, "Removing this entry! frozen=" + r.haveState
4200 + " finishing=" + r.finishing);
4201 mHistory.remove(i);
4202
4203 r.inHistory = false;
4204 mWindowManager.removeAppToken(r);
4205 if (VALIDATE_TOKENS) {
4206 mWindowManager.validateAppTokens(mHistory);
4207 }
4208 removeActivityUriPermissionsLocked(r);
4209
4210 } else {
4211 // We have the current state for this activity, so
4212 // it can be restarted later when needed.
4213 if (localLOGV) Log.v(
4214 TAG, "Keeping entry, setting app to null");
4215 if (r.visible) {
4216 hasVisibleActivities = true;
4217 }
4218 r.app = null;
4219 r.nowVisible = false;
4220 if (!r.haveState) {
4221 r.icicle = null;
4222 }
4223 }
4224
4225 cleanUpActivityLocked(r, true);
4226 r.state = ActivityState.STOPPED;
4227 }
4228 atTop = false;
4229 }
4230
4231 app.activities.clear();
4232
4233 if (app.instrumentationClass != null) {
4234 Log.w(TAG, "Crash of app " + app.processName
4235 + " running instrumentation " + app.instrumentationClass);
4236 Bundle info = new Bundle();
4237 info.putString("shortMsg", "Process crashed.");
4238 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4239 }
4240
4241 if (!restarting) {
4242 if (!resumeTopActivityLocked(null)) {
4243 // If there was nothing to resume, and we are not already
4244 // restarting this process, but there is a visible activity that
4245 // is hosted by the process... then make sure all visible
4246 // activities are running, taking care of restarting this
4247 // process.
4248 if (hasVisibleActivities) {
4249 ensureActivitiesVisibleLocked(null, 0);
4250 }
4251 }
4252 }
4253 }
4254
4255 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4256 IBinder threadBinder = thread.asBinder();
4257
4258 // Find the application record.
4259 int count = mLRUProcesses.size();
4260 int i;
4261 for (i=0; i<count; i++) {
4262 ProcessRecord rec = mLRUProcesses.get(i);
4263 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4264 return i;
4265 }
4266 }
4267 return -1;
4268 }
4269
4270 private final ProcessRecord getRecordForAppLocked(
4271 IApplicationThread thread) {
4272 if (thread == null) {
4273 return null;
4274 }
4275
4276 int appIndex = getLRURecordIndexForAppLocked(thread);
4277 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4278 }
4279
4280 private final void appDiedLocked(ProcessRecord app, int pid,
4281 IApplicationThread thread) {
4282
4283 mProcDeaths[0]++;
4284
4285 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4286 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4287 + ") has died.");
4288 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4289 if (localLOGV) Log.v(
4290 TAG, "Dying app: " + app + ", pid: " + pid
4291 + ", thread: " + thread.asBinder());
4292 boolean doLowMem = app.instrumentationClass == null;
4293 handleAppDiedLocked(app, false);
4294
4295 if (doLowMem) {
4296 // If there are no longer any background processes running,
4297 // and the app that died was not running instrumentation,
4298 // then tell everyone we are now low on memory.
4299 boolean haveBg = false;
4300 int count = mLRUProcesses.size();
4301 int i;
4302 for (i=0; i<count; i++) {
4303 ProcessRecord rec = mLRUProcesses.get(i);
4304 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4305 haveBg = true;
4306 break;
4307 }
4308 }
4309
4310 if (!haveBg) {
4311 Log.i(TAG, "Low Memory: No more background processes.");
4312 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4313 for (i=0; i<count; i++) {
4314 ProcessRecord rec = mLRUProcesses.get(i);
4315 if (rec.thread != null) {
4316 rec.lastRequestedGc = SystemClock.uptimeMillis();
4317 try {
4318 rec.thread.scheduleLowMemory();
4319 } catch (RemoteException e) {
4320 // Don't care if the process is gone.
4321 }
4322 }
4323 }
4324 }
4325 }
4326 } else if (Config.LOGD) {
4327 Log.d(TAG, "Received spurious death notification for thread "
4328 + thread.asBinder());
4329 }
4330 }
4331
4332 final String readFile(String filename) {
4333 try {
4334 FileInputStream fs = new FileInputStream(filename);
4335 byte[] inp = new byte[8192];
4336 int size = fs.read(inp);
4337 fs.close();
4338 return new String(inp, 0, 0, size);
4339 } catch (java.io.IOException e) {
4340 }
4341 return "";
4342 }
4343
4344 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4345 final String annotation) {
4346 if (app.notResponding || app.crashing) {
4347 return;
4348 }
4349
4350 // Log the ANR to the event log.
4351 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4352
4353 // If we are on a secure build and the application is not interesting to the user (it is
4354 // not visible or in the background), just kill it instead of displaying a dialog.
4355 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4356 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4357 Process.killProcess(app.pid);
4358 return;
4359 }
4360
4361 // DeviceMonitor.start();
4362
4363 String processInfo = null;
4364 if (MONITOR_CPU_USAGE) {
4365 updateCpuStatsNow();
4366 synchronized (mProcessStatsThread) {
4367 processInfo = mProcessStats.printCurrentState();
4368 }
4369 }
4370
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004371 StringBuilder info = mStringBuilder;
4372 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004373 info.append("ANR (application not responding) in process: ");
4374 info.append(app.processName);
4375 if (annotation != null) {
4376 info.append("\nAnnotation: ");
4377 info.append(annotation);
4378 }
4379 if (MONITOR_CPU_USAGE) {
4380 info.append("\nCPU usage:\n");
4381 info.append(processInfo);
4382 }
4383 Log.i(TAG, info.toString());
4384
4385 // The application is not responding. Dump as many thread traces as we can.
4386 boolean fileDump = prepareTraceFile(true);
4387 if (!fileDump) {
4388 // Dumping traces to the log, just dump the process that isn't responding so
4389 // we don't overflow the log
4390 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4391 } else {
4392 // Dumping traces to a file so dump all active processes we know about
4393 synchronized (this) {
4394 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4395 ProcessRecord r = mLRUProcesses.get(i);
4396 if (r.thread != null) {
4397 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4398 }
4399 }
4400 }
4401 }
4402
4403 if (mWatcher != null) {
4404 try {
4405 int res = mWatcher.appNotResponding(app.processName,
4406 app.pid, info.toString());
4407 if (res != 0) {
4408 if (res < 0) {
4409 // wait until the SIGQUIT has had a chance to process before killing the
4410 // process.
4411 try {
4412 wait(2000);
4413 } catch (InterruptedException e) {
4414 }
4415
4416 Process.killProcess(app.pid);
4417 return;
4418 }
4419 }
4420 } catch (RemoteException e) {
4421 mWatcher = null;
4422 }
4423 }
4424
4425 makeAppNotRespondingLocked(app,
4426 activity != null ? activity.shortComponentName : null,
4427 annotation != null ? "ANR " + annotation : "ANR",
4428 info.toString(), null);
4429 Message msg = Message.obtain();
4430 HashMap map = new HashMap();
4431 msg.what = SHOW_NOT_RESPONDING_MSG;
4432 msg.obj = map;
4433 map.put("app", app);
4434 if (activity != null) {
4435 map.put("activity", activity);
4436 }
4437
4438 mHandler.sendMessage(msg);
4439 return;
4440 }
4441
4442 /**
4443 * If a stack trace file has been configured, prepare the filesystem
4444 * by creating the directory if it doesn't exist and optionally
4445 * removing the old trace file.
4446 *
4447 * @param removeExisting If set, the existing trace file will be removed.
4448 * @return Returns true if the trace file preparations succeeded
4449 */
4450 public static boolean prepareTraceFile(boolean removeExisting) {
4451 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4452 boolean fileReady = false;
4453 if (!TextUtils.isEmpty(tracesPath)) {
4454 File f = new File(tracesPath);
4455 if (!f.exists()) {
4456 // Ensure the enclosing directory exists
4457 File dir = f.getParentFile();
4458 if (!dir.exists()) {
4459 fileReady = dir.mkdirs();
4460 FileUtils.setPermissions(dir.getAbsolutePath(),
4461 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4462 } else if (dir.isDirectory()) {
4463 fileReady = true;
4464 }
4465 } else if (removeExisting) {
4466 // Remove the previous traces file, so we don't fill the disk.
4467 // The VM will recreate it
4468 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4469 fileReady = f.delete();
4470 }
4471 }
4472
4473 return fileReady;
4474 }
4475
4476
4477 private final void decPersistentCountLocked(ProcessRecord app)
4478 {
4479 app.persistentActivities--;
4480 if (app.persistentActivities > 0) {
4481 // Still more of 'em...
4482 return;
4483 }
4484 if (app.persistent) {
4485 // Ah, but the application itself is persistent. Whatever!
4486 return;
4487 }
4488
4489 // App is no longer persistent... make sure it and the ones
4490 // following it in the LRU list have the correc oom_adj.
4491 updateOomAdjLocked();
4492 }
4493
4494 public void setPersistent(IBinder token, boolean isPersistent) {
4495 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4496 != PackageManager.PERMISSION_GRANTED) {
4497 String msg = "Permission Denial: setPersistent() from pid="
4498 + Binder.getCallingPid()
4499 + ", uid=" + Binder.getCallingUid()
4500 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4501 Log.w(TAG, msg);
4502 throw new SecurityException(msg);
4503 }
4504
4505 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004506 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004507 if (index < 0) {
4508 return;
4509 }
4510 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4511 ProcessRecord app = r.app;
4512
4513 if (localLOGV) Log.v(
4514 TAG, "Setting persistence " + isPersistent + ": " + r);
4515
4516 if (isPersistent) {
4517 if (r.persistent) {
4518 // Okay okay, I heard you already!
4519 if (localLOGV) Log.v(TAG, "Already persistent!");
4520 return;
4521 }
4522 r.persistent = true;
4523 app.persistentActivities++;
4524 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4525 if (app.persistentActivities > 1) {
4526 // We aren't the first...
4527 if (localLOGV) Log.v(TAG, "Not the first!");
4528 return;
4529 }
4530 if (app.persistent) {
4531 // This would be redundant.
4532 if (localLOGV) Log.v(TAG, "App is persistent!");
4533 return;
4534 }
4535
4536 // App is now persistent... make sure it and the ones
4537 // following it now have the correct oom_adj.
4538 final long origId = Binder.clearCallingIdentity();
4539 updateOomAdjLocked();
4540 Binder.restoreCallingIdentity(origId);
4541
4542 } else {
4543 if (!r.persistent) {
4544 // Okay okay, I heard you already!
4545 return;
4546 }
4547 r.persistent = false;
4548 final long origId = Binder.clearCallingIdentity();
4549 decPersistentCountLocked(app);
4550 Binder.restoreCallingIdentity(origId);
4551
4552 }
4553 }
4554 }
4555
4556 public boolean clearApplicationUserData(final String packageName,
4557 final IPackageDataObserver observer) {
4558 int uid = Binder.getCallingUid();
4559 int pid = Binder.getCallingPid();
4560 long callingId = Binder.clearCallingIdentity();
4561 try {
4562 IPackageManager pm = ActivityThread.getPackageManager();
4563 int pkgUid = -1;
4564 synchronized(this) {
4565 try {
4566 pkgUid = pm.getPackageUid(packageName);
4567 } catch (RemoteException e) {
4568 }
4569 if (pkgUid == -1) {
4570 Log.w(TAG, "Invalid packageName:" + packageName);
4571 return false;
4572 }
4573 if (uid == pkgUid || checkComponentPermission(
4574 android.Manifest.permission.CLEAR_APP_USER_DATA,
4575 pid, uid, -1)
4576 == PackageManager.PERMISSION_GRANTED) {
4577 restartPackageLocked(packageName, pkgUid);
4578 } else {
4579 throw new SecurityException(pid+" does not have permission:"+
4580 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4581 "for process:"+packageName);
4582 }
4583 }
4584
4585 try {
4586 //clear application user data
4587 pm.clearApplicationUserData(packageName, observer);
4588 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4589 Uri.fromParts("package", packageName, null));
4590 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4591 broadcastIntentLocked(null, null, intent,
4592 null, null, 0, null, null, null,
4593 false, false, MY_PID, Process.SYSTEM_UID);
4594 } catch (RemoteException e) {
4595 }
4596 } finally {
4597 Binder.restoreCallingIdentity(callingId);
4598 }
4599 return true;
4600 }
4601
4602 public void restartPackage(final String packageName) {
4603 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4604 != PackageManager.PERMISSION_GRANTED) {
4605 String msg = "Permission Denial: restartPackage() from pid="
4606 + Binder.getCallingPid()
4607 + ", uid=" + Binder.getCallingUid()
4608 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4609 Log.w(TAG, msg);
4610 throw new SecurityException(msg);
4611 }
4612
4613 long callingId = Binder.clearCallingIdentity();
4614 try {
4615 IPackageManager pm = ActivityThread.getPackageManager();
4616 int pkgUid = -1;
4617 synchronized(this) {
4618 try {
4619 pkgUid = pm.getPackageUid(packageName);
4620 } catch (RemoteException e) {
4621 }
4622 if (pkgUid == -1) {
4623 Log.w(TAG, "Invalid packageName: " + packageName);
4624 return;
4625 }
4626 restartPackageLocked(packageName, pkgUid);
4627 }
4628 } finally {
4629 Binder.restoreCallingIdentity(callingId);
4630 }
4631 }
4632
4633 private void restartPackageLocked(final String packageName, int uid) {
4634 uninstallPackageLocked(packageName, uid, false);
4635 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4636 Uri.fromParts("package", packageName, null));
4637 intent.putExtra(Intent.EXTRA_UID, uid);
4638 broadcastIntentLocked(null, null, intent,
4639 null, null, 0, null, null, null,
4640 false, false, MY_PID, Process.SYSTEM_UID);
4641 }
4642
4643 private final void uninstallPackageLocked(String name, int uid,
4644 boolean callerWillRestart) {
4645 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4646
4647 int i, N;
4648
4649 final String procNamePrefix = name + ":";
4650 if (uid < 0) {
4651 try {
4652 uid = ActivityThread.getPackageManager().getPackageUid(name);
4653 } catch (RemoteException e) {
4654 }
4655 }
4656
4657 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4658 while (badApps.hasNext()) {
4659 SparseArray<Long> ba = badApps.next();
4660 if (ba.get(uid) != null) {
4661 badApps.remove();
4662 }
4663 }
4664
4665 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4666
4667 // Remove all processes this package may have touched: all with the
4668 // same UID (except for the system or root user), and all whose name
4669 // matches the package name.
4670 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4671 final int NA = apps.size();
4672 for (int ia=0; ia<NA; ia++) {
4673 ProcessRecord app = apps.valueAt(ia);
4674 if (app.removed) {
4675 procs.add(app);
4676 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4677 || app.processName.equals(name)
4678 || app.processName.startsWith(procNamePrefix)) {
4679 app.removed = true;
4680 procs.add(app);
4681 }
4682 }
4683 }
4684
4685 N = procs.size();
4686 for (i=0; i<N; i++) {
4687 removeProcessLocked(procs.get(i), callerWillRestart);
4688 }
4689
4690 for (i=mHistory.size()-1; i>=0; i--) {
4691 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4692 if (r.packageName.equals(name)) {
4693 if (Config.LOGD) Log.d(
4694 TAG, " Force finishing activity "
4695 + r.intent.getComponent().flattenToShortString());
4696 if (r.app != null) {
4697 r.app.removed = true;
4698 }
4699 r.app = null;
4700 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4701 }
4702 }
4703
4704 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4705 for (ServiceRecord service : mServices.values()) {
4706 if (service.packageName.equals(name)) {
4707 if (service.app != null) {
4708 service.app.removed = true;
4709 }
4710 service.app = null;
4711 services.add(service);
4712 }
4713 }
4714
4715 N = services.size();
4716 for (i=0; i<N; i++) {
4717 bringDownServiceLocked(services.get(i), true);
4718 }
4719
4720 resumeTopActivityLocked(null);
4721 }
4722
4723 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4724 final String name = app.processName;
4725 final int uid = app.info.uid;
4726 if (Config.LOGD) Log.d(
4727 TAG, "Force removing process " + app + " (" + name
4728 + "/" + uid + ")");
4729
4730 mProcessNames.remove(name, uid);
4731 boolean needRestart = false;
4732 if (app.pid > 0 && app.pid != MY_PID) {
4733 int pid = app.pid;
4734 synchronized (mPidsSelfLocked) {
4735 mPidsSelfLocked.remove(pid);
4736 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4737 }
4738 handleAppDiedLocked(app, true);
4739 mLRUProcesses.remove(app);
4740 Process.killProcess(pid);
4741
4742 if (app.persistent) {
4743 if (!callerWillRestart) {
4744 addAppLocked(app.info);
4745 } else {
4746 needRestart = true;
4747 }
4748 }
4749 } else {
4750 mRemovedProcesses.add(app);
4751 }
4752
4753 return needRestart;
4754 }
4755
4756 private final void processStartTimedOutLocked(ProcessRecord app) {
4757 final int pid = app.pid;
4758 boolean gone = false;
4759 synchronized (mPidsSelfLocked) {
4760 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4761 if (knownApp != null && knownApp.thread == null) {
4762 mPidsSelfLocked.remove(pid);
4763 gone = true;
4764 }
4765 }
4766
4767 if (gone) {
4768 Log.w(TAG, "Process " + app + " failed to attach");
4769 mProcessNames.remove(app.processName, app.info.uid);
4770 Process.killProcess(pid);
4771 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4772 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4773 mPendingBroadcast = null;
4774 scheduleBroadcastsLocked();
4775 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004776 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4777 Log.w(TAG, "Unattached app died before backup, skipping");
4778 try {
4779 IBackupManager bm = IBackupManager.Stub.asInterface(
4780 ServiceManager.getService(Context.BACKUP_SERVICE));
4781 bm.agentDisconnected(app.info.packageName);
4782 } catch (RemoteException e) {
4783 // Can't happen; the backup manager is local
4784 }
4785 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 } else {
4787 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4788 }
4789 }
4790
4791 private final boolean attachApplicationLocked(IApplicationThread thread,
4792 int pid) {
4793
4794 // Find the application record that is being attached... either via
4795 // the pid if we are running in multiple processes, or just pull the
4796 // next app record if we are emulating process with anonymous threads.
4797 ProcessRecord app;
4798 if (pid != MY_PID && pid >= 0) {
4799 synchronized (mPidsSelfLocked) {
4800 app = mPidsSelfLocked.get(pid);
4801 }
4802 } else if (mStartingProcesses.size() > 0) {
4803 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004804 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004805 } else {
4806 app = null;
4807 }
4808
4809 if (app == null) {
4810 Log.w(TAG, "No pending application record for pid " + pid
4811 + " (IApplicationThread " + thread + "); dropping process");
4812 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4813 if (pid > 0 && pid != MY_PID) {
4814 Process.killProcess(pid);
4815 } else {
4816 try {
4817 thread.scheduleExit();
4818 } catch (Exception e) {
4819 // Ignore exceptions.
4820 }
4821 }
4822 return false;
4823 }
4824
4825 // If this application record is still attached to a previous
4826 // process, clean it up now.
4827 if (app.thread != null) {
4828 handleAppDiedLocked(app, true);
4829 }
4830
4831 // Tell the process all about itself.
4832
4833 if (localLOGV) Log.v(
4834 TAG, "Binding process pid " + pid + " to record " + app);
4835
4836 String processName = app.processName;
4837 try {
4838 thread.asBinder().linkToDeath(new AppDeathRecipient(
4839 app, pid, thread), 0);
4840 } catch (RemoteException e) {
4841 app.resetPackageList();
4842 startProcessLocked(app, "link fail", processName);
4843 return false;
4844 }
4845
4846 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4847
4848 app.thread = thread;
4849 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004850 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004851 app.forcingToForeground = null;
4852 app.foregroundServices = false;
4853 app.debugging = false;
4854
4855 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4856
4857 List providers = generateApplicationProvidersLocked(app);
4858
4859 if (localLOGV) Log.v(
4860 TAG, "New app record " + app
4861 + " thread=" + thread.asBinder() + " pid=" + pid);
4862 try {
4863 int testMode = IApplicationThread.DEBUG_OFF;
4864 if (mDebugApp != null && mDebugApp.equals(processName)) {
4865 testMode = mWaitForDebugger
4866 ? IApplicationThread.DEBUG_WAIT
4867 : IApplicationThread.DEBUG_ON;
4868 app.debugging = true;
4869 if (mDebugTransient) {
4870 mDebugApp = mOrigDebugApp;
4871 mWaitForDebugger = mOrigWaitForDebugger;
4872 }
4873 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004874 // If the app is being launched for restore or full backup, set it up specially
4875 boolean isRestrictedBackupMode = false;
4876 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4877 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4878 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4879 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004880 ensurePackageDexOpt(app.instrumentationInfo != null
4881 ? app.instrumentationInfo.packageName
4882 : app.info.packageName);
4883 if (app.instrumentationClass != null) {
4884 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004885 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004886 thread.bindApplication(processName, app.instrumentationInfo != null
4887 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004888 app.instrumentationClass, app.instrumentationProfileFile,
4889 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004890 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004891 updateLRUListLocked(app, false);
4892 app.lastRequestedGc = SystemClock.uptimeMillis();
4893 } catch (Exception e) {
4894 // todo: Yikes! What should we do? For now we will try to
4895 // start another process, but that could easily get us in
4896 // an infinite loop of restarting processes...
4897 Log.w(TAG, "Exception thrown during bind!", e);
4898
4899 app.resetPackageList();
4900 startProcessLocked(app, "bind fail", processName);
4901 return false;
4902 }
4903
4904 // Remove this record from the list of starting applications.
4905 mPersistentStartingProcesses.remove(app);
4906 mProcessesOnHold.remove(app);
4907
4908 boolean badApp = false;
4909 boolean didSomething = false;
4910
4911 // See if the top visible activity is waiting to run in this process...
4912 HistoryRecord hr = topRunningActivityLocked(null);
4913 if (hr != null) {
4914 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4915 && processName.equals(hr.processName)) {
4916 try {
4917 if (realStartActivityLocked(hr, app, true, true)) {
4918 didSomething = true;
4919 }
4920 } catch (Exception e) {
4921 Log.w(TAG, "Exception in new application when starting activity "
4922 + hr.intent.getComponent().flattenToShortString(), e);
4923 badApp = true;
4924 }
4925 } else {
4926 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4927 }
4928 }
4929
4930 // Find any services that should be running in this process...
4931 if (!badApp && mPendingServices.size() > 0) {
4932 ServiceRecord sr = null;
4933 try {
4934 for (int i=0; i<mPendingServices.size(); i++) {
4935 sr = mPendingServices.get(i);
4936 if (app.info.uid != sr.appInfo.uid
4937 || !processName.equals(sr.processName)) {
4938 continue;
4939 }
4940
4941 mPendingServices.remove(i);
4942 i--;
4943 realStartServiceLocked(sr, app);
4944 didSomething = true;
4945 }
4946 } catch (Exception e) {
4947 Log.w(TAG, "Exception in new application when starting service "
4948 + sr.shortName, e);
4949 badApp = true;
4950 }
4951 }
4952
4953 // Check if the next broadcast receiver is in this process...
4954 BroadcastRecord br = mPendingBroadcast;
4955 if (!badApp && br != null && br.curApp == app) {
4956 try {
4957 mPendingBroadcast = null;
4958 processCurBroadcastLocked(br, app);
4959 didSomething = true;
4960 } catch (Exception e) {
4961 Log.w(TAG, "Exception in new application when starting receiver "
4962 + br.curComponent.flattenToShortString(), e);
4963 badApp = true;
4964 logBroadcastReceiverDiscard(br);
4965 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4966 br.resultExtras, br.resultAbort, true);
4967 scheduleBroadcastsLocked();
4968 }
4969 }
4970
Christopher Tate181fafa2009-05-14 11:12:14 -07004971 // Check whether the next backup agent is in this process...
4972 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4973 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004974 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07004975 try {
4976 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4977 } catch (Exception e) {
4978 Log.w(TAG, "Exception scheduling backup agent creation: ");
4979 e.printStackTrace();
4980 }
4981 }
4982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004983 if (badApp) {
4984 // todo: Also need to kill application to deal with all
4985 // kinds of exceptions.
4986 handleAppDiedLocked(app, false);
4987 return false;
4988 }
4989
4990 if (!didSomething) {
4991 updateOomAdjLocked();
4992 }
4993
4994 return true;
4995 }
4996
4997 public final void attachApplication(IApplicationThread thread) {
4998 synchronized (this) {
4999 int callingPid = Binder.getCallingPid();
5000 final long origId = Binder.clearCallingIdentity();
5001 attachApplicationLocked(thread, callingPid);
5002 Binder.restoreCallingIdentity(origId);
5003 }
5004 }
5005
5006 public final void activityIdle(IBinder token) {
5007 final long origId = Binder.clearCallingIdentity();
5008 activityIdleInternal(token, false);
5009 Binder.restoreCallingIdentity(origId);
5010 }
5011
5012 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5013 boolean remove) {
5014 int N = mStoppingActivities.size();
5015 if (N <= 0) return null;
5016
5017 ArrayList<HistoryRecord> stops = null;
5018
5019 final boolean nowVisible = mResumedActivity != null
5020 && mResumedActivity.nowVisible
5021 && !mResumedActivity.waitingVisible;
5022 for (int i=0; i<N; i++) {
5023 HistoryRecord s = mStoppingActivities.get(i);
5024 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5025 + nowVisible + " waitingVisible=" + s.waitingVisible
5026 + " finishing=" + s.finishing);
5027 if (s.waitingVisible && nowVisible) {
5028 mWaitingVisibleActivities.remove(s);
5029 s.waitingVisible = false;
5030 if (s.finishing) {
5031 // If this activity is finishing, it is sitting on top of
5032 // everyone else but we now know it is no longer needed...
5033 // so get rid of it. Otherwise, we need to go through the
5034 // normal flow and hide it once we determine that it is
5035 // hidden by the activities in front of it.
5036 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5037 mWindowManager.setAppVisibility(s, false);
5038 }
5039 }
5040 if (!s.waitingVisible && remove) {
5041 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5042 if (stops == null) {
5043 stops = new ArrayList<HistoryRecord>();
5044 }
5045 stops.add(s);
5046 mStoppingActivities.remove(i);
5047 N--;
5048 i--;
5049 }
5050 }
5051
5052 return stops;
5053 }
5054
5055 void enableScreenAfterBoot() {
5056 mWindowManager.enableScreenAfterBoot();
5057 }
5058
5059 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5060 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5061
5062 ArrayList<HistoryRecord> stops = null;
5063 ArrayList<HistoryRecord> finishes = null;
5064 ArrayList<HistoryRecord> thumbnails = null;
5065 int NS = 0;
5066 int NF = 0;
5067 int NT = 0;
5068 IApplicationThread sendThumbnail = null;
5069 boolean booting = false;
5070 boolean enableScreen = false;
5071
5072 synchronized (this) {
5073 if (token != null) {
5074 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5075 }
5076
5077 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005078 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005079 if (index >= 0) {
5080 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5081
5082 // No longer need to keep the device awake.
5083 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5084 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5085 mLaunchingActivity.release();
5086 }
5087
5088 // We are now idle. If someone is waiting for a thumbnail from
5089 // us, we can now deliver.
5090 r.idle = true;
5091 scheduleAppGcsLocked();
5092 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5093 sendThumbnail = r.app.thread;
5094 r.thumbnailNeeded = false;
5095 }
5096
5097 // If this activity is fullscreen, set up to hide those under it.
5098
5099 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5100 ensureActivitiesVisibleLocked(null, 0);
5101
5102 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5103 if (!mBooted && !fromTimeout) {
5104 mBooted = true;
5105 enableScreen = true;
5106 }
5107 }
5108
5109 // Atomically retrieve all of the other things to do.
5110 stops = processStoppingActivitiesLocked(true);
5111 NS = stops != null ? stops.size() : 0;
5112 if ((NF=mFinishingActivities.size()) > 0) {
5113 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5114 mFinishingActivities.clear();
5115 }
5116 if ((NT=mCancelledThumbnails.size()) > 0) {
5117 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5118 mCancelledThumbnails.clear();
5119 }
5120
5121 booting = mBooting;
5122 mBooting = false;
5123 }
5124
5125 int i;
5126
5127 // Send thumbnail if requested.
5128 if (sendThumbnail != null) {
5129 try {
5130 sendThumbnail.requestThumbnail(token);
5131 } catch (Exception e) {
5132 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5133 sendPendingThumbnail(null, token, null, null, true);
5134 }
5135 }
5136
5137 // Stop any activities that are scheduled to do so but have been
5138 // waiting for the next one to start.
5139 for (i=0; i<NS; i++) {
5140 HistoryRecord r = (HistoryRecord)stops.get(i);
5141 synchronized (this) {
5142 if (r.finishing) {
5143 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5144 } else {
5145 stopActivityLocked(r);
5146 }
5147 }
5148 }
5149
5150 // Finish any activities that are scheduled to do so but have been
5151 // waiting for the next one to start.
5152 for (i=0; i<NF; i++) {
5153 HistoryRecord r = (HistoryRecord)finishes.get(i);
5154 synchronized (this) {
5155 destroyActivityLocked(r, true);
5156 }
5157 }
5158
5159 // Report back to any thumbnail receivers.
5160 for (i=0; i<NT; i++) {
5161 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5162 sendPendingThumbnail(r, null, null, null, true);
5163 }
5164
5165 if (booting) {
5166 // Ensure that any processes we had put on hold are now started
5167 // up.
5168 final int NP = mProcessesOnHold.size();
5169 if (NP > 0) {
5170 ArrayList<ProcessRecord> procs =
5171 new ArrayList<ProcessRecord>(mProcessesOnHold);
5172 for (int ip=0; ip<NP; ip++) {
5173 this.startProcessLocked(procs.get(ip), "on-hold", null);
5174 }
5175 }
5176 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5177 // Tell anyone interested that we are done booting!
5178 synchronized (this) {
5179 broadcastIntentLocked(null, null,
5180 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5181 null, null, 0, null, null,
5182 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5183 false, false, MY_PID, Process.SYSTEM_UID);
5184 }
5185 }
5186 }
5187
5188 trimApplications();
5189 //dump();
5190 //mWindowManager.dump();
5191
5192 if (enableScreen) {
5193 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5194 SystemClock.uptimeMillis());
5195 enableScreenAfterBoot();
5196 }
5197 }
5198
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005199 final void ensureScreenEnabled() {
5200 boolean enableScreen;
5201 synchronized (this) {
5202 enableScreen = !mBooted;
5203 mBooted = true;
5204 }
5205
5206 if (enableScreen) {
5207 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5208 SystemClock.uptimeMillis());
5209 enableScreenAfterBoot();
5210 }
5211 }
5212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005213 public final void activityPaused(IBinder token, Bundle icicle) {
5214 // Refuse possible leaked file descriptors
5215 if (icicle != null && icicle.hasFileDescriptors()) {
5216 throw new IllegalArgumentException("File descriptors passed in Bundle");
5217 }
5218
5219 final long origId = Binder.clearCallingIdentity();
5220 activityPaused(token, icicle, false);
5221 Binder.restoreCallingIdentity(origId);
5222 }
5223
5224 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5225 if (DEBUG_PAUSE) Log.v(
5226 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5227 + ", timeout=" + timeout);
5228
5229 HistoryRecord r = null;
5230
5231 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005232 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 if (index >= 0) {
5234 r = (HistoryRecord)mHistory.get(index);
5235 if (!timeout) {
5236 r.icicle = icicle;
5237 r.haveState = true;
5238 }
5239 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5240 if (mPausingActivity == r) {
5241 r.state = ActivityState.PAUSED;
5242 completePauseLocked();
5243 } else {
5244 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5245 System.identityHashCode(r), r.shortComponentName,
5246 mPausingActivity != null
5247 ? mPausingActivity.shortComponentName : "(none)");
5248 }
5249 }
5250 }
5251 }
5252
5253 public final void activityStopped(IBinder token, Bitmap thumbnail,
5254 CharSequence description) {
5255 if (localLOGV) Log.v(
5256 TAG, "Activity stopped: token=" + token);
5257
5258 HistoryRecord r = null;
5259
5260 final long origId = Binder.clearCallingIdentity();
5261
5262 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005263 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005264 if (index >= 0) {
5265 r = (HistoryRecord)mHistory.get(index);
5266 r.thumbnail = thumbnail;
5267 r.description = description;
5268 r.stopped = true;
5269 r.state = ActivityState.STOPPED;
5270 if (!r.finishing) {
5271 if (r.configDestroy) {
5272 destroyActivityLocked(r, true);
5273 resumeTopActivityLocked(null);
5274 }
5275 }
5276 }
5277 }
5278
5279 if (r != null) {
5280 sendPendingThumbnail(r, null, null, null, false);
5281 }
5282
5283 trimApplications();
5284
5285 Binder.restoreCallingIdentity(origId);
5286 }
5287
5288 public final void activityDestroyed(IBinder token) {
5289 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5290 synchronized (this) {
5291 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5292
Dianne Hackborn75b03852009-06-12 15:43:26 -07005293 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005294 if (index >= 0) {
5295 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5296 if (r.state == ActivityState.DESTROYING) {
5297 final long origId = Binder.clearCallingIdentity();
5298 removeActivityFromHistoryLocked(r);
5299 Binder.restoreCallingIdentity(origId);
5300 }
5301 }
5302 }
5303 }
5304
5305 public String getCallingPackage(IBinder token) {
5306 synchronized (this) {
5307 HistoryRecord r = getCallingRecordLocked(token);
5308 return r != null && r.app != null ? r.app.processName : null;
5309 }
5310 }
5311
5312 public ComponentName getCallingActivity(IBinder token) {
5313 synchronized (this) {
5314 HistoryRecord r = getCallingRecordLocked(token);
5315 return r != null ? r.intent.getComponent() : null;
5316 }
5317 }
5318
5319 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005320 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005321 if (index >= 0) {
5322 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5323 if (r != null) {
5324 return r.resultTo;
5325 }
5326 }
5327 return null;
5328 }
5329
5330 public ComponentName getActivityClassForToken(IBinder token) {
5331 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005332 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005333 if (index >= 0) {
5334 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5335 return r.intent.getComponent();
5336 }
5337 return null;
5338 }
5339 }
5340
5341 public String getPackageForToken(IBinder token) {
5342 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005343 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005344 if (index >= 0) {
5345 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5346 return r.packageName;
5347 }
5348 return null;
5349 }
5350 }
5351
5352 public IIntentSender getIntentSender(int type,
5353 String packageName, IBinder token, String resultWho,
5354 int requestCode, Intent intent, String resolvedType, int flags) {
5355 // Refuse possible leaked file descriptors
5356 if (intent != null && intent.hasFileDescriptors() == true) {
5357 throw new IllegalArgumentException("File descriptors passed in Intent");
5358 }
5359
5360 synchronized(this) {
5361 int callingUid = Binder.getCallingUid();
5362 try {
5363 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5364 Process.supportsProcesses()) {
5365 int uid = ActivityThread.getPackageManager()
5366 .getPackageUid(packageName);
5367 if (uid != Binder.getCallingUid()) {
5368 String msg = "Permission Denial: getIntentSender() from pid="
5369 + Binder.getCallingPid()
5370 + ", uid=" + Binder.getCallingUid()
5371 + ", (need uid=" + uid + ")"
5372 + " is not allowed to send as package " + packageName;
5373 Log.w(TAG, msg);
5374 throw new SecurityException(msg);
5375 }
5376 }
5377 } catch (RemoteException e) {
5378 throw new SecurityException(e);
5379 }
5380 HistoryRecord activity = null;
5381 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005382 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005383 if (index < 0) {
5384 return null;
5385 }
5386 activity = (HistoryRecord)mHistory.get(index);
5387 if (activity.finishing) {
5388 return null;
5389 }
5390 }
5391
5392 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5393 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5394 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5395 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5396 |PendingIntent.FLAG_UPDATE_CURRENT);
5397
5398 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5399 type, packageName, activity, resultWho,
5400 requestCode, intent, resolvedType, flags);
5401 WeakReference<PendingIntentRecord> ref;
5402 ref = mIntentSenderRecords.get(key);
5403 PendingIntentRecord rec = ref != null ? ref.get() : null;
5404 if (rec != null) {
5405 if (!cancelCurrent) {
5406 if (updateCurrent) {
5407 rec.key.requestIntent.replaceExtras(intent);
5408 }
5409 return rec;
5410 }
5411 rec.canceled = true;
5412 mIntentSenderRecords.remove(key);
5413 }
5414 if (noCreate) {
5415 return rec;
5416 }
5417 rec = new PendingIntentRecord(this, key, callingUid);
5418 mIntentSenderRecords.put(key, rec.ref);
5419 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5420 if (activity.pendingResults == null) {
5421 activity.pendingResults
5422 = new HashSet<WeakReference<PendingIntentRecord>>();
5423 }
5424 activity.pendingResults.add(rec.ref);
5425 }
5426 return rec;
5427 }
5428 }
5429
5430 public void cancelIntentSender(IIntentSender sender) {
5431 if (!(sender instanceof PendingIntentRecord)) {
5432 return;
5433 }
5434 synchronized(this) {
5435 PendingIntentRecord rec = (PendingIntentRecord)sender;
5436 try {
5437 int uid = ActivityThread.getPackageManager()
5438 .getPackageUid(rec.key.packageName);
5439 if (uid != Binder.getCallingUid()) {
5440 String msg = "Permission Denial: cancelIntentSender() from pid="
5441 + Binder.getCallingPid()
5442 + ", uid=" + Binder.getCallingUid()
5443 + " is not allowed to cancel packges "
5444 + rec.key.packageName;
5445 Log.w(TAG, msg);
5446 throw new SecurityException(msg);
5447 }
5448 } catch (RemoteException e) {
5449 throw new SecurityException(e);
5450 }
5451 cancelIntentSenderLocked(rec, true);
5452 }
5453 }
5454
5455 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5456 rec.canceled = true;
5457 mIntentSenderRecords.remove(rec.key);
5458 if (cleanActivity && rec.key.activity != null) {
5459 rec.key.activity.pendingResults.remove(rec.ref);
5460 }
5461 }
5462
5463 public String getPackageForIntentSender(IIntentSender pendingResult) {
5464 if (!(pendingResult instanceof PendingIntentRecord)) {
5465 return null;
5466 }
5467 synchronized(this) {
5468 try {
5469 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5470 return res.key.packageName;
5471 } catch (ClassCastException e) {
5472 }
5473 }
5474 return null;
5475 }
5476
5477 public void setProcessLimit(int max) {
5478 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5479 "setProcessLimit()");
5480 mProcessLimit = max;
5481 }
5482
5483 public int getProcessLimit() {
5484 return mProcessLimit;
5485 }
5486
5487 void foregroundTokenDied(ForegroundToken token) {
5488 synchronized (ActivityManagerService.this) {
5489 synchronized (mPidsSelfLocked) {
5490 ForegroundToken cur
5491 = mForegroundProcesses.get(token.pid);
5492 if (cur != token) {
5493 return;
5494 }
5495 mForegroundProcesses.remove(token.pid);
5496 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5497 if (pr == null) {
5498 return;
5499 }
5500 pr.forcingToForeground = null;
5501 pr.foregroundServices = false;
5502 }
5503 updateOomAdjLocked();
5504 }
5505 }
5506
5507 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5508 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5509 "setProcessForeground()");
5510 synchronized(this) {
5511 boolean changed = false;
5512
5513 synchronized (mPidsSelfLocked) {
5514 ProcessRecord pr = mPidsSelfLocked.get(pid);
5515 if (pr == null) {
5516 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5517 return;
5518 }
5519 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5520 if (oldToken != null) {
5521 oldToken.token.unlinkToDeath(oldToken, 0);
5522 mForegroundProcesses.remove(pid);
5523 pr.forcingToForeground = null;
5524 changed = true;
5525 }
5526 if (isForeground && token != null) {
5527 ForegroundToken newToken = new ForegroundToken() {
5528 public void binderDied() {
5529 foregroundTokenDied(this);
5530 }
5531 };
5532 newToken.pid = pid;
5533 newToken.token = token;
5534 try {
5535 token.linkToDeath(newToken, 0);
5536 mForegroundProcesses.put(pid, newToken);
5537 pr.forcingToForeground = token;
5538 changed = true;
5539 } catch (RemoteException e) {
5540 // If the process died while doing this, we will later
5541 // do the cleanup with the process death link.
5542 }
5543 }
5544 }
5545
5546 if (changed) {
5547 updateOomAdjLocked();
5548 }
5549 }
5550 }
5551
5552 // =========================================================
5553 // PERMISSIONS
5554 // =========================================================
5555
5556 static class PermissionController extends IPermissionController.Stub {
5557 ActivityManagerService mActivityManagerService;
5558 PermissionController(ActivityManagerService activityManagerService) {
5559 mActivityManagerService = activityManagerService;
5560 }
5561
5562 public boolean checkPermission(String permission, int pid, int uid) {
5563 return mActivityManagerService.checkPermission(permission, pid,
5564 uid) == PackageManager.PERMISSION_GRANTED;
5565 }
5566 }
5567
5568 /**
5569 * This can be called with or without the global lock held.
5570 */
5571 int checkComponentPermission(String permission, int pid, int uid,
5572 int reqUid) {
5573 // We might be performing an operation on behalf of an indirect binder
5574 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5575 // client identity accordingly before proceeding.
5576 Identity tlsIdentity = sCallerIdentity.get();
5577 if (tlsIdentity != null) {
5578 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5579 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5580 uid = tlsIdentity.uid;
5581 pid = tlsIdentity.pid;
5582 }
5583
5584 // Root, system server and our own process get to do everything.
5585 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5586 !Process.supportsProcesses()) {
5587 return PackageManager.PERMISSION_GRANTED;
5588 }
5589 // If the target requires a specific UID, always fail for others.
5590 if (reqUid >= 0 && uid != reqUid) {
5591 return PackageManager.PERMISSION_DENIED;
5592 }
5593 if (permission == null) {
5594 return PackageManager.PERMISSION_GRANTED;
5595 }
5596 try {
5597 return ActivityThread.getPackageManager()
5598 .checkUidPermission(permission, uid);
5599 } catch (RemoteException e) {
5600 // Should never happen, but if it does... deny!
5601 Log.e(TAG, "PackageManager is dead?!?", e);
5602 }
5603 return PackageManager.PERMISSION_DENIED;
5604 }
5605
5606 /**
5607 * As the only public entry point for permissions checking, this method
5608 * can enforce the semantic that requesting a check on a null global
5609 * permission is automatically denied. (Internally a null permission
5610 * string is used when calling {@link #checkComponentPermission} in cases
5611 * when only uid-based security is needed.)
5612 *
5613 * This can be called with or without the global lock held.
5614 */
5615 public int checkPermission(String permission, int pid, int uid) {
5616 if (permission == null) {
5617 return PackageManager.PERMISSION_DENIED;
5618 }
5619 return checkComponentPermission(permission, pid, uid, -1);
5620 }
5621
5622 /**
5623 * Binder IPC calls go through the public entry point.
5624 * This can be called with or without the global lock held.
5625 */
5626 int checkCallingPermission(String permission) {
5627 return checkPermission(permission,
5628 Binder.getCallingPid(),
5629 Binder.getCallingUid());
5630 }
5631
5632 /**
5633 * This can be called with or without the global lock held.
5634 */
5635 void enforceCallingPermission(String permission, String func) {
5636 if (checkCallingPermission(permission)
5637 == PackageManager.PERMISSION_GRANTED) {
5638 return;
5639 }
5640
5641 String msg = "Permission Denial: " + func + " from pid="
5642 + Binder.getCallingPid()
5643 + ", uid=" + Binder.getCallingUid()
5644 + " requires " + permission;
5645 Log.w(TAG, msg);
5646 throw new SecurityException(msg);
5647 }
5648
5649 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5650 ProviderInfo pi, int uid, int modeFlags) {
5651 try {
5652 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5653 if ((pi.readPermission != null) &&
5654 (pm.checkUidPermission(pi.readPermission, uid)
5655 != PackageManager.PERMISSION_GRANTED)) {
5656 return false;
5657 }
5658 }
5659 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5660 if ((pi.writePermission != null) &&
5661 (pm.checkUidPermission(pi.writePermission, uid)
5662 != PackageManager.PERMISSION_GRANTED)) {
5663 return false;
5664 }
5665 }
5666 return true;
5667 } catch (RemoteException e) {
5668 return false;
5669 }
5670 }
5671
5672 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5673 int modeFlags) {
5674 // Root gets to do everything.
5675 if (uid == 0 || !Process.supportsProcesses()) {
5676 return true;
5677 }
5678 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5679 if (perms == null) return false;
5680 UriPermission perm = perms.get(uri);
5681 if (perm == null) return false;
5682 return (modeFlags&perm.modeFlags) == modeFlags;
5683 }
5684
5685 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5686 // Another redirected-binder-call permissions check as in
5687 // {@link checkComponentPermission}.
5688 Identity tlsIdentity = sCallerIdentity.get();
5689 if (tlsIdentity != null) {
5690 uid = tlsIdentity.uid;
5691 pid = tlsIdentity.pid;
5692 }
5693
5694 // Our own process gets to do everything.
5695 if (pid == MY_PID) {
5696 return PackageManager.PERMISSION_GRANTED;
5697 }
5698 synchronized(this) {
5699 return checkUriPermissionLocked(uri, uid, modeFlags)
5700 ? PackageManager.PERMISSION_GRANTED
5701 : PackageManager.PERMISSION_DENIED;
5702 }
5703 }
5704
5705 private void grantUriPermissionLocked(int callingUid,
5706 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5707 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5708 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5709 if (modeFlags == 0) {
5710 return;
5711 }
5712
5713 final IPackageManager pm = ActivityThread.getPackageManager();
5714
5715 // If this is not a content: uri, we can't do anything with it.
5716 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5717 return;
5718 }
5719
5720 String name = uri.getAuthority();
5721 ProviderInfo pi = null;
5722 ContentProviderRecord cpr
5723 = (ContentProviderRecord)mProvidersByName.get(name);
5724 if (cpr != null) {
5725 pi = cpr.info;
5726 } else {
5727 try {
5728 pi = pm.resolveContentProvider(name,
5729 PackageManager.GET_URI_PERMISSION_PATTERNS);
5730 } catch (RemoteException ex) {
5731 }
5732 }
5733 if (pi == null) {
5734 Log.w(TAG, "No content provider found for: " + name);
5735 return;
5736 }
5737
5738 int targetUid;
5739 try {
5740 targetUid = pm.getPackageUid(targetPkg);
5741 if (targetUid < 0) {
5742 return;
5743 }
5744 } catch (RemoteException ex) {
5745 return;
5746 }
5747
5748 // First... does the target actually need this permission?
5749 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5750 // No need to grant the target this permission.
5751 return;
5752 }
5753
5754 // Second... maybe someone else has already granted the
5755 // permission?
5756 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5757 // No need to grant the target this permission.
5758 return;
5759 }
5760
5761 // Third... is the provider allowing granting of URI permissions?
5762 if (!pi.grantUriPermissions) {
5763 throw new SecurityException("Provider " + pi.packageName
5764 + "/" + pi.name
5765 + " does not allow granting of Uri permissions (uri "
5766 + uri + ")");
5767 }
5768 if (pi.uriPermissionPatterns != null) {
5769 final int N = pi.uriPermissionPatterns.length;
5770 boolean allowed = false;
5771 for (int i=0; i<N; i++) {
5772 if (pi.uriPermissionPatterns[i] != null
5773 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5774 allowed = true;
5775 break;
5776 }
5777 }
5778 if (!allowed) {
5779 throw new SecurityException("Provider " + pi.packageName
5780 + "/" + pi.name
5781 + " does not allow granting of permission to path of Uri "
5782 + uri);
5783 }
5784 }
5785
5786 // Fourth... does the caller itself have permission to access
5787 // this uri?
5788 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5789 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5790 throw new SecurityException("Uid " + callingUid
5791 + " does not have permission to uri " + uri);
5792 }
5793 }
5794
5795 // Okay! So here we are: the caller has the assumed permission
5796 // to the uri, and the target doesn't. Let's now give this to
5797 // the target.
5798
5799 HashMap<Uri, UriPermission> targetUris
5800 = mGrantedUriPermissions.get(targetUid);
5801 if (targetUris == null) {
5802 targetUris = new HashMap<Uri, UriPermission>();
5803 mGrantedUriPermissions.put(targetUid, targetUris);
5804 }
5805
5806 UriPermission perm = targetUris.get(uri);
5807 if (perm == null) {
5808 perm = new UriPermission(targetUid, uri);
5809 targetUris.put(uri, perm);
5810
5811 }
5812 perm.modeFlags |= modeFlags;
5813 if (activity == null) {
5814 perm.globalModeFlags |= modeFlags;
5815 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5816 perm.readActivities.add(activity);
5817 if (activity.readUriPermissions == null) {
5818 activity.readUriPermissions = new HashSet<UriPermission>();
5819 }
5820 activity.readUriPermissions.add(perm);
5821 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5822 perm.writeActivities.add(activity);
5823 if (activity.writeUriPermissions == null) {
5824 activity.writeUriPermissions = new HashSet<UriPermission>();
5825 }
5826 activity.writeUriPermissions.add(perm);
5827 }
5828 }
5829
5830 private void grantUriPermissionFromIntentLocked(int callingUid,
5831 String targetPkg, Intent intent, HistoryRecord activity) {
5832 if (intent == null) {
5833 return;
5834 }
5835 Uri data = intent.getData();
5836 if (data == null) {
5837 return;
5838 }
5839 grantUriPermissionLocked(callingUid, targetPkg, data,
5840 intent.getFlags(), activity);
5841 }
5842
5843 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5844 Uri uri, int modeFlags) {
5845 synchronized(this) {
5846 final ProcessRecord r = getRecordForAppLocked(caller);
5847 if (r == null) {
5848 throw new SecurityException("Unable to find app for caller "
5849 + caller
5850 + " when granting permission to uri " + uri);
5851 }
5852 if (targetPkg == null) {
5853 Log.w(TAG, "grantUriPermission: null target");
5854 return;
5855 }
5856 if (uri == null) {
5857 Log.w(TAG, "grantUriPermission: null uri");
5858 return;
5859 }
5860
5861 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5862 null);
5863 }
5864 }
5865
5866 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5867 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5868 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5869 HashMap<Uri, UriPermission> perms
5870 = mGrantedUriPermissions.get(perm.uid);
5871 if (perms != null) {
5872 perms.remove(perm.uri);
5873 if (perms.size() == 0) {
5874 mGrantedUriPermissions.remove(perm.uid);
5875 }
5876 }
5877 }
5878 }
5879
5880 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5881 if (activity.readUriPermissions != null) {
5882 for (UriPermission perm : activity.readUriPermissions) {
5883 perm.readActivities.remove(activity);
5884 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5885 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5886 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5887 removeUriPermissionIfNeededLocked(perm);
5888 }
5889 }
5890 }
5891 if (activity.writeUriPermissions != null) {
5892 for (UriPermission perm : activity.writeUriPermissions) {
5893 perm.writeActivities.remove(activity);
5894 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5895 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5896 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5897 removeUriPermissionIfNeededLocked(perm);
5898 }
5899 }
5900 }
5901 }
5902
5903 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5904 int modeFlags) {
5905 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5906 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5907 if (modeFlags == 0) {
5908 return;
5909 }
5910
5911 final IPackageManager pm = ActivityThread.getPackageManager();
5912
5913 final String authority = uri.getAuthority();
5914 ProviderInfo pi = null;
5915 ContentProviderRecord cpr
5916 = (ContentProviderRecord)mProvidersByName.get(authority);
5917 if (cpr != null) {
5918 pi = cpr.info;
5919 } else {
5920 try {
5921 pi = pm.resolveContentProvider(authority,
5922 PackageManager.GET_URI_PERMISSION_PATTERNS);
5923 } catch (RemoteException ex) {
5924 }
5925 }
5926 if (pi == null) {
5927 Log.w(TAG, "No content provider found for: " + authority);
5928 return;
5929 }
5930
5931 // Does the caller have this permission on the URI?
5932 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5933 // Right now, if you are not the original owner of the permission,
5934 // you are not allowed to revoke it.
5935 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5936 throw new SecurityException("Uid " + callingUid
5937 + " does not have permission to uri " + uri);
5938 //}
5939 }
5940
5941 // Go through all of the permissions and remove any that match.
5942 final List<String> SEGMENTS = uri.getPathSegments();
5943 if (SEGMENTS != null) {
5944 final int NS = SEGMENTS.size();
5945 int N = mGrantedUriPermissions.size();
5946 for (int i=0; i<N; i++) {
5947 HashMap<Uri, UriPermission> perms
5948 = mGrantedUriPermissions.valueAt(i);
5949 Iterator<UriPermission> it = perms.values().iterator();
5950 toploop:
5951 while (it.hasNext()) {
5952 UriPermission perm = it.next();
5953 Uri targetUri = perm.uri;
5954 if (!authority.equals(targetUri.getAuthority())) {
5955 continue;
5956 }
5957 List<String> targetSegments = targetUri.getPathSegments();
5958 if (targetSegments == null) {
5959 continue;
5960 }
5961 if (targetSegments.size() < NS) {
5962 continue;
5963 }
5964 for (int j=0; j<NS; j++) {
5965 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5966 continue toploop;
5967 }
5968 }
5969 perm.clearModes(modeFlags);
5970 if (perm.modeFlags == 0) {
5971 it.remove();
5972 }
5973 }
5974 if (perms.size() == 0) {
5975 mGrantedUriPermissions.remove(
5976 mGrantedUriPermissions.keyAt(i));
5977 N--;
5978 i--;
5979 }
5980 }
5981 }
5982 }
5983
5984 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5985 int modeFlags) {
5986 synchronized(this) {
5987 final ProcessRecord r = getRecordForAppLocked(caller);
5988 if (r == null) {
5989 throw new SecurityException("Unable to find app for caller "
5990 + caller
5991 + " when revoking permission to uri " + uri);
5992 }
5993 if (uri == null) {
5994 Log.w(TAG, "revokeUriPermission: null uri");
5995 return;
5996 }
5997
5998 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5999 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6000 if (modeFlags == 0) {
6001 return;
6002 }
6003
6004 final IPackageManager pm = ActivityThread.getPackageManager();
6005
6006 final String authority = uri.getAuthority();
6007 ProviderInfo pi = null;
6008 ContentProviderRecord cpr
6009 = (ContentProviderRecord)mProvidersByName.get(authority);
6010 if (cpr != null) {
6011 pi = cpr.info;
6012 } else {
6013 try {
6014 pi = pm.resolveContentProvider(authority,
6015 PackageManager.GET_URI_PERMISSION_PATTERNS);
6016 } catch (RemoteException ex) {
6017 }
6018 }
6019 if (pi == null) {
6020 Log.w(TAG, "No content provider found for: " + authority);
6021 return;
6022 }
6023
6024 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6025 }
6026 }
6027
6028 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6029 synchronized (this) {
6030 ProcessRecord app =
6031 who != null ? getRecordForAppLocked(who) : null;
6032 if (app == null) return;
6033
6034 Message msg = Message.obtain();
6035 msg.what = WAIT_FOR_DEBUGGER_MSG;
6036 msg.obj = app;
6037 msg.arg1 = waiting ? 1 : 0;
6038 mHandler.sendMessage(msg);
6039 }
6040 }
6041
6042 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6043 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006044 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006045 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006046 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006047 }
6048
6049 // =========================================================
6050 // TASK MANAGEMENT
6051 // =========================================================
6052
6053 public List getTasks(int maxNum, int flags,
6054 IThumbnailReceiver receiver) {
6055 ArrayList list = new ArrayList();
6056
6057 PendingThumbnailsRecord pending = null;
6058 IApplicationThread topThumbnail = null;
6059 HistoryRecord topRecord = null;
6060
6061 synchronized(this) {
6062 if (localLOGV) Log.v(
6063 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6064 + ", receiver=" + receiver);
6065
6066 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6067 != PackageManager.PERMISSION_GRANTED) {
6068 if (receiver != null) {
6069 // If the caller wants to wait for pending thumbnails,
6070 // it ain't gonna get them.
6071 try {
6072 receiver.finished();
6073 } catch (RemoteException ex) {
6074 }
6075 }
6076 String msg = "Permission Denial: getTasks() from pid="
6077 + Binder.getCallingPid()
6078 + ", uid=" + Binder.getCallingUid()
6079 + " requires " + android.Manifest.permission.GET_TASKS;
6080 Log.w(TAG, msg);
6081 throw new SecurityException(msg);
6082 }
6083
6084 int pos = mHistory.size()-1;
6085 HistoryRecord next =
6086 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6087 HistoryRecord top = null;
6088 CharSequence topDescription = null;
6089 TaskRecord curTask = null;
6090 int numActivities = 0;
6091 int numRunning = 0;
6092 while (pos >= 0 && maxNum > 0) {
6093 final HistoryRecord r = next;
6094 pos--;
6095 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6096
6097 // Initialize state for next task if needed.
6098 if (top == null ||
6099 (top.state == ActivityState.INITIALIZING
6100 && top.task == r.task)) {
6101 top = r;
6102 topDescription = r.description;
6103 curTask = r.task;
6104 numActivities = numRunning = 0;
6105 }
6106
6107 // Add 'r' into the current task.
6108 numActivities++;
6109 if (r.app != null && r.app.thread != null) {
6110 numRunning++;
6111 }
6112 if (topDescription == null) {
6113 topDescription = r.description;
6114 }
6115
6116 if (localLOGV) Log.v(
6117 TAG, r.intent.getComponent().flattenToShortString()
6118 + ": task=" + r.task);
6119
6120 // If the next one is a different task, generate a new
6121 // TaskInfo entry for what we have.
6122 if (next == null || next.task != curTask) {
6123 ActivityManager.RunningTaskInfo ci
6124 = new ActivityManager.RunningTaskInfo();
6125 ci.id = curTask.taskId;
6126 ci.baseActivity = r.intent.getComponent();
6127 ci.topActivity = top.intent.getComponent();
6128 ci.thumbnail = top.thumbnail;
6129 ci.description = topDescription;
6130 ci.numActivities = numActivities;
6131 ci.numRunning = numRunning;
6132 //System.out.println(
6133 // "#" + maxNum + ": " + " descr=" + ci.description);
6134 if (ci.thumbnail == null && receiver != null) {
6135 if (localLOGV) Log.v(
6136 TAG, "State=" + top.state + "Idle=" + top.idle
6137 + " app=" + top.app
6138 + " thr=" + (top.app != null ? top.app.thread : null));
6139 if (top.state == ActivityState.RESUMED
6140 || top.state == ActivityState.PAUSING) {
6141 if (top.idle && top.app != null
6142 && top.app.thread != null) {
6143 topRecord = top;
6144 topThumbnail = top.app.thread;
6145 } else {
6146 top.thumbnailNeeded = true;
6147 }
6148 }
6149 if (pending == null) {
6150 pending = new PendingThumbnailsRecord(receiver);
6151 }
6152 pending.pendingRecords.add(top);
6153 }
6154 list.add(ci);
6155 maxNum--;
6156 top = null;
6157 }
6158 }
6159
6160 if (pending != null) {
6161 mPendingThumbnails.add(pending);
6162 }
6163 }
6164
6165 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6166
6167 if (topThumbnail != null) {
6168 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6169 try {
6170 topThumbnail.requestThumbnail(topRecord);
6171 } catch (Exception e) {
6172 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6173 sendPendingThumbnail(null, topRecord, null, null, true);
6174 }
6175 }
6176
6177 if (pending == null && receiver != null) {
6178 // In this case all thumbnails were available and the client
6179 // is being asked to be told when the remaining ones come in...
6180 // which is unusually, since the top-most currently running
6181 // activity should never have a canned thumbnail! Oh well.
6182 try {
6183 receiver.finished();
6184 } catch (RemoteException ex) {
6185 }
6186 }
6187
6188 return list;
6189 }
6190
6191 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6192 int flags) {
6193 synchronized (this) {
6194 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6195 "getRecentTasks()");
6196
6197 final int N = mRecentTasks.size();
6198 ArrayList<ActivityManager.RecentTaskInfo> res
6199 = new ArrayList<ActivityManager.RecentTaskInfo>(
6200 maxNum < N ? maxNum : N);
6201 for (int i=0; i<N && maxNum > 0; i++) {
6202 TaskRecord tr = mRecentTasks.get(i);
6203 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6204 || (tr.intent == null)
6205 || ((tr.intent.getFlags()
6206 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6207 ActivityManager.RecentTaskInfo rti
6208 = new ActivityManager.RecentTaskInfo();
6209 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6210 rti.baseIntent = new Intent(
6211 tr.intent != null ? tr.intent : tr.affinityIntent);
6212 rti.origActivity = tr.origActivity;
6213 res.add(rti);
6214 maxNum--;
6215 }
6216 }
6217 return res;
6218 }
6219 }
6220
6221 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6222 int j;
6223 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6224 TaskRecord jt = startTask;
6225
6226 // First look backwards
6227 for (j=startIndex-1; j>=0; j--) {
6228 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6229 if (r.task != jt) {
6230 jt = r.task;
6231 if (affinity.equals(jt.affinity)) {
6232 return j;
6233 }
6234 }
6235 }
6236
6237 // Now look forwards
6238 final int N = mHistory.size();
6239 jt = startTask;
6240 for (j=startIndex+1; j<N; j++) {
6241 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6242 if (r.task != jt) {
6243 if (affinity.equals(jt.affinity)) {
6244 return j;
6245 }
6246 jt = r.task;
6247 }
6248 }
6249
6250 // Might it be at the top?
6251 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6252 return N-1;
6253 }
6254
6255 return -1;
6256 }
6257
6258 /**
6259 * Perform a reset of the given task, if needed as part of launching it.
6260 * Returns the new HistoryRecord at the top of the task.
6261 */
6262 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6263 HistoryRecord newActivity) {
6264 boolean forceReset = (newActivity.info.flags
6265 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6266 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6267 if ((newActivity.info.flags
6268 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6269 forceReset = true;
6270 }
6271 }
6272
6273 final TaskRecord task = taskTop.task;
6274
6275 // We are going to move through the history list so that we can look
6276 // at each activity 'target' with 'below' either the interesting
6277 // activity immediately below it in the stack or null.
6278 HistoryRecord target = null;
6279 int targetI = 0;
6280 int taskTopI = -1;
6281 int replyChainEnd = -1;
6282 int lastReparentPos = -1;
6283 for (int i=mHistory.size()-1; i>=-1; i--) {
6284 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6285
6286 if (below != null && below.finishing) {
6287 continue;
6288 }
6289 if (target == null) {
6290 target = below;
6291 targetI = i;
6292 // If we were in the middle of a reply chain before this
6293 // task, it doesn't appear like the root of the chain wants
6294 // anything interesting, so drop it.
6295 replyChainEnd = -1;
6296 continue;
6297 }
6298
6299 final int flags = target.info.flags;
6300
6301 final boolean finishOnTaskLaunch =
6302 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6303 final boolean allowTaskReparenting =
6304 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6305
6306 if (target.task == task) {
6307 // We are inside of the task being reset... we'll either
6308 // finish this activity, push it out for another task,
6309 // or leave it as-is. We only do this
6310 // for activities that are not the root of the task (since
6311 // if we finish the root, we may no longer have the task!).
6312 if (taskTopI < 0) {
6313 taskTopI = targetI;
6314 }
6315 if (below != null && below.task == task) {
6316 final boolean clearWhenTaskReset =
6317 (target.intent.getFlags()
6318 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006319 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006320 // If this activity is sending a reply to a previous
6321 // activity, we can't do anything with it now until
6322 // we reach the start of the reply chain.
6323 // XXX note that we are assuming the result is always
6324 // to the previous activity, which is almost always
6325 // the case but we really shouldn't count on.
6326 if (replyChainEnd < 0) {
6327 replyChainEnd = targetI;
6328 }
Ed Heyl73798232009-03-24 21:32:21 -07006329 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006330 && target.taskAffinity != null
6331 && !target.taskAffinity.equals(task.affinity)) {
6332 // If this activity has an affinity for another
6333 // task, then we need to move it out of here. We will
6334 // move it as far out of the way as possible, to the
6335 // bottom of the activity stack. This also keeps it
6336 // correctly ordered with any activities we previously
6337 // moved.
6338 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6339 if (target.taskAffinity != null
6340 && target.taskAffinity.equals(p.task.affinity)) {
6341 // If the activity currently at the bottom has the
6342 // same task affinity as the one we are moving,
6343 // then merge it into the same task.
6344 target.task = p.task;
6345 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6346 + " out to bottom task " + p.task);
6347 } else {
6348 mCurTask++;
6349 if (mCurTask <= 0) {
6350 mCurTask = 1;
6351 }
6352 target.task = new TaskRecord(mCurTask, target.info, null,
6353 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6354 target.task.affinityIntent = target.intent;
6355 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6356 + " out to new task " + target.task);
6357 }
6358 mWindowManager.setAppGroupId(target, task.taskId);
6359 if (replyChainEnd < 0) {
6360 replyChainEnd = targetI;
6361 }
6362 int dstPos = 0;
6363 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6364 p = (HistoryRecord)mHistory.get(srcPos);
6365 if (p.finishing) {
6366 continue;
6367 }
6368 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6369 + " out to target's task " + target.task);
6370 task.numActivities--;
6371 p.task = target.task;
6372 target.task.numActivities++;
6373 mHistory.remove(srcPos);
6374 mHistory.add(dstPos, p);
6375 mWindowManager.moveAppToken(dstPos, p);
6376 mWindowManager.setAppGroupId(p, p.task.taskId);
6377 dstPos++;
6378 if (VALIDATE_TOKENS) {
6379 mWindowManager.validateAppTokens(mHistory);
6380 }
6381 i++;
6382 }
6383 if (taskTop == p) {
6384 taskTop = below;
6385 }
6386 if (taskTopI == replyChainEnd) {
6387 taskTopI = -1;
6388 }
6389 replyChainEnd = -1;
6390 addRecentTask(target.task);
6391 } else if (forceReset || finishOnTaskLaunch
6392 || clearWhenTaskReset) {
6393 // If the activity should just be removed -- either
6394 // because it asks for it, or the task should be
6395 // cleared -- then finish it and anything that is
6396 // part of its reply chain.
6397 if (clearWhenTaskReset) {
6398 // In this case, we want to finish this activity
6399 // and everything above it, so be sneaky and pretend
6400 // like these are all in the reply chain.
6401 replyChainEnd = targetI+1;
6402 while (replyChainEnd < mHistory.size() &&
6403 ((HistoryRecord)mHistory.get(
6404 replyChainEnd)).task == task) {
6405 replyChainEnd++;
6406 }
6407 replyChainEnd--;
6408 } else if (replyChainEnd < 0) {
6409 replyChainEnd = targetI;
6410 }
6411 HistoryRecord p = null;
6412 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6413 p = (HistoryRecord)mHistory.get(srcPos);
6414 if (p.finishing) {
6415 continue;
6416 }
6417 if (finishActivityLocked(p, srcPos,
6418 Activity.RESULT_CANCELED, null, "reset")) {
6419 replyChainEnd--;
6420 srcPos--;
6421 }
6422 }
6423 if (taskTop == p) {
6424 taskTop = below;
6425 }
6426 if (taskTopI == replyChainEnd) {
6427 taskTopI = -1;
6428 }
6429 replyChainEnd = -1;
6430 } else {
6431 // If we were in the middle of a chain, well the
6432 // activity that started it all doesn't want anything
6433 // special, so leave it all as-is.
6434 replyChainEnd = -1;
6435 }
6436 } else {
6437 // Reached the bottom of the task -- any reply chain
6438 // should be left as-is.
6439 replyChainEnd = -1;
6440 }
6441
6442 } else if (target.resultTo != null) {
6443 // If this activity is sending a reply to a previous
6444 // activity, we can't do anything with it now until
6445 // we reach the start of the reply chain.
6446 // XXX note that we are assuming the result is always
6447 // to the previous activity, which is almost always
6448 // the case but we really shouldn't count on.
6449 if (replyChainEnd < 0) {
6450 replyChainEnd = targetI;
6451 }
6452
6453 } else if (taskTopI >= 0 && allowTaskReparenting
6454 && task.affinity != null
6455 && task.affinity.equals(target.taskAffinity)) {
6456 // We are inside of another task... if this activity has
6457 // an affinity for our task, then either remove it if we are
6458 // clearing or move it over to our task. Note that
6459 // we currently punt on the case where we are resetting a
6460 // task that is not at the top but who has activities above
6461 // with an affinity to it... this is really not a normal
6462 // case, and we will need to later pull that task to the front
6463 // and usually at that point we will do the reset and pick
6464 // up those remaining activities. (This only happens if
6465 // someone starts an activity in a new task from an activity
6466 // in a task that is not currently on top.)
6467 if (forceReset || finishOnTaskLaunch) {
6468 if (replyChainEnd < 0) {
6469 replyChainEnd = targetI;
6470 }
6471 HistoryRecord p = null;
6472 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6473 p = (HistoryRecord)mHistory.get(srcPos);
6474 if (p.finishing) {
6475 continue;
6476 }
6477 if (finishActivityLocked(p, srcPos,
6478 Activity.RESULT_CANCELED, null, "reset")) {
6479 taskTopI--;
6480 lastReparentPos--;
6481 replyChainEnd--;
6482 srcPos--;
6483 }
6484 }
6485 replyChainEnd = -1;
6486 } else {
6487 if (replyChainEnd < 0) {
6488 replyChainEnd = targetI;
6489 }
6490 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6491 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6492 if (p.finishing) {
6493 continue;
6494 }
6495 if (lastReparentPos < 0) {
6496 lastReparentPos = taskTopI;
6497 taskTop = p;
6498 } else {
6499 lastReparentPos--;
6500 }
6501 mHistory.remove(srcPos);
6502 p.task.numActivities--;
6503 p.task = task;
6504 mHistory.add(lastReparentPos, p);
6505 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6506 + " in to resetting task " + task);
6507 task.numActivities++;
6508 mWindowManager.moveAppToken(lastReparentPos, p);
6509 mWindowManager.setAppGroupId(p, p.task.taskId);
6510 if (VALIDATE_TOKENS) {
6511 mWindowManager.validateAppTokens(mHistory);
6512 }
6513 }
6514 replyChainEnd = -1;
6515
6516 // Now we've moved it in to place... but what if this is
6517 // a singleTop activity and we have put it on top of another
6518 // instance of the same activity? Then we drop the instance
6519 // below so it remains singleTop.
6520 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6521 for (int j=lastReparentPos-1; j>=0; j--) {
6522 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6523 if (p.finishing) {
6524 continue;
6525 }
6526 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6527 if (finishActivityLocked(p, j,
6528 Activity.RESULT_CANCELED, null, "replace")) {
6529 taskTopI--;
6530 lastReparentPos--;
6531 }
6532 }
6533 }
6534 }
6535 }
6536 }
6537
6538 target = below;
6539 targetI = i;
6540 }
6541
6542 return taskTop;
6543 }
6544
6545 /**
6546 * TODO: Add mWatcher hook
6547 */
6548 public void moveTaskToFront(int task) {
6549 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6550 "moveTaskToFront()");
6551
6552 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006553 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6554 Binder.getCallingUid(), "Task to front")) {
6555 return;
6556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006557 final long origId = Binder.clearCallingIdentity();
6558 try {
6559 int N = mRecentTasks.size();
6560 for (int i=0; i<N; i++) {
6561 TaskRecord tr = mRecentTasks.get(i);
6562 if (tr.taskId == task) {
6563 moveTaskToFrontLocked(tr);
6564 return;
6565 }
6566 }
6567 for (int i=mHistory.size()-1; i>=0; i--) {
6568 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6569 if (hr.task.taskId == task) {
6570 moveTaskToFrontLocked(hr.task);
6571 return;
6572 }
6573 }
6574 } finally {
6575 Binder.restoreCallingIdentity(origId);
6576 }
6577 }
6578 }
6579
6580 private final void moveTaskToFrontLocked(TaskRecord tr) {
6581 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6582
6583 final int task = tr.taskId;
6584 int top = mHistory.size()-1;
6585
6586 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6587 // nothing to do!
6588 return;
6589 }
6590
6591 if (DEBUG_TRANSITION) Log.v(TAG,
6592 "Prepare to front transition: task=" + tr);
6593 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6594
6595 ArrayList moved = new ArrayList();
6596
6597 // Applying the affinities may have removed entries from the history,
6598 // so get the size again.
6599 top = mHistory.size()-1;
6600 int pos = top;
6601
6602 // Shift all activities with this task up to the top
6603 // of the stack, keeping them in the same internal order.
6604 while (pos >= 0) {
6605 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6606 if (localLOGV) Log.v(
6607 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6608 boolean first = true;
6609 if (r.task.taskId == task) {
6610 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6611 mHistory.remove(pos);
6612 mHistory.add(top, r);
6613 moved.add(0, r);
6614 top--;
6615 if (first) {
6616 addRecentTask(r.task);
6617 first = false;
6618 }
6619 }
6620 pos--;
6621 }
6622
6623 mWindowManager.moveAppTokensToTop(moved);
6624 if (VALIDATE_TOKENS) {
6625 mWindowManager.validateAppTokens(mHistory);
6626 }
6627
6628 finishTaskMove(task);
6629 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6630 }
6631
6632 private final void finishTaskMove(int task) {
6633 resumeTopActivityLocked(null);
6634 }
6635
6636 public void moveTaskToBack(int task) {
6637 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6638 "moveTaskToBack()");
6639
6640 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006641 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6642 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6643 Binder.getCallingUid(), "Task to back")) {
6644 return;
6645 }
6646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006647 final long origId = Binder.clearCallingIdentity();
6648 moveTaskToBackLocked(task);
6649 Binder.restoreCallingIdentity(origId);
6650 }
6651 }
6652
6653 /**
6654 * Moves an activity, and all of the other activities within the same task, to the bottom
6655 * of the history stack. The activity's order within the task is unchanged.
6656 *
6657 * @param token A reference to the activity we wish to move
6658 * @param nonRoot If false then this only works if the activity is the root
6659 * of a task; if true it will work for any activity in a task.
6660 * @return Returns true if the move completed, false if not.
6661 */
6662 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6663 synchronized(this) {
6664 final long origId = Binder.clearCallingIdentity();
6665 int taskId = getTaskForActivityLocked(token, !nonRoot);
6666 if (taskId >= 0) {
6667 return moveTaskToBackLocked(taskId);
6668 }
6669 Binder.restoreCallingIdentity(origId);
6670 }
6671 return false;
6672 }
6673
6674 /**
6675 * Worker method for rearranging history stack. Implements the function of moving all
6676 * activities for a specific task (gathering them if disjoint) into a single group at the
6677 * bottom of the stack.
6678 *
6679 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6680 * to premeptively cancel the move.
6681 *
6682 * @param task The taskId to collect and move to the bottom.
6683 * @return Returns true if the move completed, false if not.
6684 */
6685 private final boolean moveTaskToBackLocked(int task) {
6686 Log.i(TAG, "moveTaskToBack: " + task);
6687
6688 // If we have a watcher, preflight the move before committing to it. First check
6689 // for *other* available tasks, but if none are available, then try again allowing the
6690 // current task to be selected.
6691 if (mWatcher != null) {
6692 HistoryRecord next = topRunningActivityLocked(null, task);
6693 if (next == null) {
6694 next = topRunningActivityLocked(null, 0);
6695 }
6696 if (next != null) {
6697 // ask watcher if this is allowed
6698 boolean moveOK = true;
6699 try {
6700 moveOK = mWatcher.activityResuming(next.packageName);
6701 } catch (RemoteException e) {
6702 mWatcher = null;
6703 }
6704 if (!moveOK) {
6705 return false;
6706 }
6707 }
6708 }
6709
6710 ArrayList moved = new ArrayList();
6711
6712 if (DEBUG_TRANSITION) Log.v(TAG,
6713 "Prepare to back transition: task=" + task);
6714 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6715
6716 final int N = mHistory.size();
6717 int bottom = 0;
6718 int pos = 0;
6719
6720 // Shift all activities with this task down to the bottom
6721 // of the stack, keeping them in the same internal order.
6722 while (pos < N) {
6723 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6724 if (localLOGV) Log.v(
6725 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6726 if (r.task.taskId == task) {
6727 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6728 mHistory.remove(pos);
6729 mHistory.add(bottom, r);
6730 moved.add(r);
6731 bottom++;
6732 }
6733 pos++;
6734 }
6735
6736 mWindowManager.moveAppTokensToBottom(moved);
6737 if (VALIDATE_TOKENS) {
6738 mWindowManager.validateAppTokens(mHistory);
6739 }
6740
6741 finishTaskMove(task);
6742 return true;
6743 }
6744
6745 public void moveTaskBackwards(int task) {
6746 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6747 "moveTaskBackwards()");
6748
6749 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006750 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6751 Binder.getCallingUid(), "Task backwards")) {
6752 return;
6753 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006754 final long origId = Binder.clearCallingIdentity();
6755 moveTaskBackwardsLocked(task);
6756 Binder.restoreCallingIdentity(origId);
6757 }
6758 }
6759
6760 private final void moveTaskBackwardsLocked(int task) {
6761 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6762 }
6763
6764 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6765 synchronized(this) {
6766 return getTaskForActivityLocked(token, onlyRoot);
6767 }
6768 }
6769
6770 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6771 final int N = mHistory.size();
6772 TaskRecord lastTask = null;
6773 for (int i=0; i<N; i++) {
6774 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6775 if (r == token) {
6776 if (!onlyRoot || lastTask != r.task) {
6777 return r.task.taskId;
6778 }
6779 return -1;
6780 }
6781 lastTask = r.task;
6782 }
6783
6784 return -1;
6785 }
6786
6787 /**
6788 * Returns the top activity in any existing task matching the given
6789 * Intent. Returns null if no such task is found.
6790 */
6791 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6792 ComponentName cls = intent.getComponent();
6793 if (info.targetActivity != null) {
6794 cls = new ComponentName(info.packageName, info.targetActivity);
6795 }
6796
6797 TaskRecord cp = null;
6798
6799 final int N = mHistory.size();
6800 for (int i=(N-1); i>=0; i--) {
6801 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6802 if (!r.finishing && r.task != cp
6803 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6804 cp = r.task;
6805 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6806 // + "/aff=" + r.task.affinity + " to new cls="
6807 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6808 if (r.task.affinity != null) {
6809 if (r.task.affinity.equals(info.taskAffinity)) {
6810 //Log.i(TAG, "Found matching affinity!");
6811 return r;
6812 }
6813 } else if (r.task.intent != null
6814 && r.task.intent.getComponent().equals(cls)) {
6815 //Log.i(TAG, "Found matching class!");
6816 //dump();
6817 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6818 return r;
6819 } else if (r.task.affinityIntent != null
6820 && r.task.affinityIntent.getComponent().equals(cls)) {
6821 //Log.i(TAG, "Found matching class!");
6822 //dump();
6823 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6824 return r;
6825 }
6826 }
6827 }
6828
6829 return null;
6830 }
6831
6832 /**
6833 * Returns the first activity (starting from the top of the stack) that
6834 * is the same as the given activity. Returns null if no such activity
6835 * is found.
6836 */
6837 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6838 ComponentName cls = intent.getComponent();
6839 if (info.targetActivity != null) {
6840 cls = new ComponentName(info.packageName, info.targetActivity);
6841 }
6842
6843 final int N = mHistory.size();
6844 for (int i=(N-1); i>=0; i--) {
6845 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6846 if (!r.finishing) {
6847 if (r.intent.getComponent().equals(cls)) {
6848 //Log.i(TAG, "Found matching class!");
6849 //dump();
6850 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6851 return r;
6852 }
6853 }
6854 }
6855
6856 return null;
6857 }
6858
6859 public void finishOtherInstances(IBinder token, ComponentName className) {
6860 synchronized(this) {
6861 final long origId = Binder.clearCallingIdentity();
6862
6863 int N = mHistory.size();
6864 TaskRecord lastTask = null;
6865 for (int i=0; i<N; i++) {
6866 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6867 if (r.realActivity.equals(className)
6868 && r != token && lastTask != r.task) {
6869 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6870 null, "others")) {
6871 i--;
6872 N--;
6873 }
6874 }
6875 lastTask = r.task;
6876 }
6877
6878 Binder.restoreCallingIdentity(origId);
6879 }
6880 }
6881
6882 // =========================================================
6883 // THUMBNAILS
6884 // =========================================================
6885
6886 public void reportThumbnail(IBinder token,
6887 Bitmap thumbnail, CharSequence description) {
6888 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6889 final long origId = Binder.clearCallingIdentity();
6890 sendPendingThumbnail(null, token, thumbnail, description, true);
6891 Binder.restoreCallingIdentity(origId);
6892 }
6893
6894 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6895 Bitmap thumbnail, CharSequence description, boolean always) {
6896 TaskRecord task = null;
6897 ArrayList receivers = null;
6898
6899 //System.out.println("Send pending thumbnail: " + r);
6900
6901 synchronized(this) {
6902 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006903 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006904 if (index < 0) {
6905 return;
6906 }
6907 r = (HistoryRecord)mHistory.get(index);
6908 }
6909 if (thumbnail == null) {
6910 thumbnail = r.thumbnail;
6911 description = r.description;
6912 }
6913 if (thumbnail == null && !always) {
6914 // If there is no thumbnail, and this entry is not actually
6915 // going away, then abort for now and pick up the next
6916 // thumbnail we get.
6917 return;
6918 }
6919 task = r.task;
6920
6921 int N = mPendingThumbnails.size();
6922 int i=0;
6923 while (i<N) {
6924 PendingThumbnailsRecord pr =
6925 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6926 //System.out.println("Looking in " + pr.pendingRecords);
6927 if (pr.pendingRecords.remove(r)) {
6928 if (receivers == null) {
6929 receivers = new ArrayList();
6930 }
6931 receivers.add(pr);
6932 if (pr.pendingRecords.size() == 0) {
6933 pr.finished = true;
6934 mPendingThumbnails.remove(i);
6935 N--;
6936 continue;
6937 }
6938 }
6939 i++;
6940 }
6941 }
6942
6943 if (receivers != null) {
6944 final int N = receivers.size();
6945 for (int i=0; i<N; i++) {
6946 try {
6947 PendingThumbnailsRecord pr =
6948 (PendingThumbnailsRecord)receivers.get(i);
6949 pr.receiver.newThumbnail(
6950 task != null ? task.taskId : -1, thumbnail, description);
6951 if (pr.finished) {
6952 pr.receiver.finished();
6953 }
6954 } catch (Exception e) {
6955 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6956 }
6957 }
6958 }
6959 }
6960
6961 // =========================================================
6962 // CONTENT PROVIDERS
6963 // =========================================================
6964
6965 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6966 List providers = null;
6967 try {
6968 providers = ActivityThread.getPackageManager().
6969 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006970 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006971 } catch (RemoteException ex) {
6972 }
6973 if (providers != null) {
6974 final int N = providers.size();
6975 for (int i=0; i<N; i++) {
6976 ProviderInfo cpi =
6977 (ProviderInfo)providers.get(i);
6978 ContentProviderRecord cpr =
6979 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6980 if (cpr == null) {
6981 cpr = new ContentProviderRecord(cpi, app.info);
6982 mProvidersByClass.put(cpi.name, cpr);
6983 }
6984 app.pubProviders.put(cpi.name, cpr);
6985 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07006986 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006987 }
6988 }
6989 return providers;
6990 }
6991
6992 private final String checkContentProviderPermissionLocked(
6993 ProviderInfo cpi, ProcessRecord r, int mode) {
6994 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6995 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6996 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6997 cpi.exported ? -1 : cpi.applicationInfo.uid)
6998 == PackageManager.PERMISSION_GRANTED
6999 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7000 return null;
7001 }
7002 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7003 cpi.exported ? -1 : cpi.applicationInfo.uid)
7004 == PackageManager.PERMISSION_GRANTED) {
7005 return null;
7006 }
7007 String msg = "Permission Denial: opening provider " + cpi.name
7008 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7009 + ", uid=" + callingUid + ") requires "
7010 + cpi.readPermission + " or " + cpi.writePermission;
7011 Log.w(TAG, msg);
7012 return msg;
7013 }
7014
7015 private final ContentProviderHolder getContentProviderImpl(
7016 IApplicationThread caller, String name) {
7017 ContentProviderRecord cpr;
7018 ProviderInfo cpi = null;
7019
7020 synchronized(this) {
7021 ProcessRecord r = null;
7022 if (caller != null) {
7023 r = getRecordForAppLocked(caller);
7024 if (r == null) {
7025 throw new SecurityException(
7026 "Unable to find app for caller " + caller
7027 + " (pid=" + Binder.getCallingPid()
7028 + ") when getting content provider " + name);
7029 }
7030 }
7031
7032 // First check if this content provider has been published...
7033 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7034 if (cpr != null) {
7035 cpi = cpr.info;
7036 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7037 return new ContentProviderHolder(cpi,
7038 cpi.readPermission != null
7039 ? cpi.readPermission : cpi.writePermission);
7040 }
7041
7042 if (r != null && cpr.canRunHere(r)) {
7043 // This provider has been published or is in the process
7044 // of being published... but it is also allowed to run
7045 // in the caller's process, so don't make a connection
7046 // and just let the caller instantiate its own instance.
7047 if (cpr.provider != null) {
7048 // don't give caller the provider object, it needs
7049 // to make its own.
7050 cpr = new ContentProviderRecord(cpr);
7051 }
7052 return cpr;
7053 }
7054
7055 final long origId = Binder.clearCallingIdentity();
7056
7057 // In this case the provider is a single instance, so we can
7058 // return it right away.
7059 if (r != null) {
7060 r.conProviders.add(cpr);
7061 cpr.clients.add(r);
7062 } else {
7063 cpr.externals++;
7064 }
7065
7066 if (cpr.app != null) {
7067 updateOomAdjLocked(cpr.app);
7068 }
7069
7070 Binder.restoreCallingIdentity(origId);
7071
7072 } else {
7073 try {
7074 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007075 resolveContentProvider(name,
7076 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007077 } catch (RemoteException ex) {
7078 }
7079 if (cpi == null) {
7080 return null;
7081 }
7082
7083 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7084 return new ContentProviderHolder(cpi,
7085 cpi.readPermission != null
7086 ? cpi.readPermission : cpi.writePermission);
7087 }
7088
7089 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7090 final boolean firstClass = cpr == null;
7091 if (firstClass) {
7092 try {
7093 ApplicationInfo ai =
7094 ActivityThread.getPackageManager().
7095 getApplicationInfo(
7096 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007097 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007098 if (ai == null) {
7099 Log.w(TAG, "No package info for content provider "
7100 + cpi.name);
7101 return null;
7102 }
7103 cpr = new ContentProviderRecord(cpi, ai);
7104 } catch (RemoteException ex) {
7105 // pm is in same process, this will never happen.
7106 }
7107 }
7108
7109 if (r != null && cpr.canRunHere(r)) {
7110 // If this is a multiprocess provider, then just return its
7111 // info and allow the caller to instantiate it. Only do
7112 // this if the provider is the same user as the caller's
7113 // process, or can run as root (so can be in any process).
7114 return cpr;
7115 }
7116
7117 if (false) {
7118 RuntimeException e = new RuntimeException("foo");
7119 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7120 // + " pruid " + ai.uid + "): " + cpi.className, e);
7121 }
7122
7123 // This is single process, and our app is now connecting to it.
7124 // See if we are already in the process of launching this
7125 // provider.
7126 final int N = mLaunchingProviders.size();
7127 int i;
7128 for (i=0; i<N; i++) {
7129 if (mLaunchingProviders.get(i) == cpr) {
7130 break;
7131 }
7132 if (false) {
7133 final ContentProviderRecord rec =
7134 (ContentProviderRecord)mLaunchingProviders.get(i);
7135 if (rec.info.name.equals(cpr.info.name)) {
7136 cpr = rec;
7137 break;
7138 }
7139 }
7140 }
7141
7142 // If the provider is not already being launched, then get it
7143 // started.
7144 if (i >= N) {
7145 final long origId = Binder.clearCallingIdentity();
7146 ProcessRecord proc = startProcessLocked(cpi.processName,
7147 cpr.appInfo, false, 0, "content provider",
7148 new ComponentName(cpi.applicationInfo.packageName,
7149 cpi.name));
7150 if (proc == null) {
7151 Log.w(TAG, "Unable to launch app "
7152 + cpi.applicationInfo.packageName + "/"
7153 + cpi.applicationInfo.uid + " for provider "
7154 + name + ": process is bad");
7155 return null;
7156 }
7157 cpr.launchingApp = proc;
7158 mLaunchingProviders.add(cpr);
7159 Binder.restoreCallingIdentity(origId);
7160 }
7161
7162 // Make sure the provider is published (the same provider class
7163 // may be published under multiple names).
7164 if (firstClass) {
7165 mProvidersByClass.put(cpi.name, cpr);
7166 }
7167 mProvidersByName.put(name, cpr);
7168
7169 if (r != null) {
7170 r.conProviders.add(cpr);
7171 cpr.clients.add(r);
7172 } else {
7173 cpr.externals++;
7174 }
7175 }
7176 }
7177
7178 // Wait for the provider to be published...
7179 synchronized (cpr) {
7180 while (cpr.provider == null) {
7181 if (cpr.launchingApp == null) {
7182 Log.w(TAG, "Unable to launch app "
7183 + cpi.applicationInfo.packageName + "/"
7184 + cpi.applicationInfo.uid + " for provider "
7185 + name + ": launching app became null");
7186 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7187 cpi.applicationInfo.packageName,
7188 cpi.applicationInfo.uid, name);
7189 return null;
7190 }
7191 try {
7192 cpr.wait();
7193 } catch (InterruptedException ex) {
7194 }
7195 }
7196 }
7197 return cpr;
7198 }
7199
7200 public final ContentProviderHolder getContentProvider(
7201 IApplicationThread caller, String name) {
7202 if (caller == null) {
7203 String msg = "null IApplicationThread when getting content provider "
7204 + name;
7205 Log.w(TAG, msg);
7206 throw new SecurityException(msg);
7207 }
7208
7209 return getContentProviderImpl(caller, name);
7210 }
7211
7212 private ContentProviderHolder getContentProviderExternal(String name) {
7213 return getContentProviderImpl(null, name);
7214 }
7215
7216 /**
7217 * Drop a content provider from a ProcessRecord's bookkeeping
7218 * @param cpr
7219 */
7220 public void removeContentProvider(IApplicationThread caller, String name) {
7221 synchronized (this) {
7222 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7223 if(cpr == null) {
7224 //remove from mProvidersByClass
7225 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7226 return;
7227 }
7228 final ProcessRecord r = getRecordForAppLocked(caller);
7229 if (r == null) {
7230 throw new SecurityException(
7231 "Unable to find app for caller " + caller +
7232 " when removing content provider " + name);
7233 }
7234 //update content provider record entry info
7235 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7236 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7237 r.info.processName+" from process "+localCpr.appInfo.processName);
7238 if(localCpr.appInfo.processName == r.info.processName) {
7239 //should not happen. taken care of as a local provider
7240 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7241 return;
7242 } else {
7243 localCpr.clients.remove(r);
7244 r.conProviders.remove(localCpr);
7245 }
7246 updateOomAdjLocked();
7247 }
7248 }
7249
7250 private void removeContentProviderExternal(String name) {
7251 synchronized (this) {
7252 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7253 if(cpr == null) {
7254 //remove from mProvidersByClass
7255 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7256 return;
7257 }
7258
7259 //update content provider record entry info
7260 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7261 localCpr.externals--;
7262 if (localCpr.externals < 0) {
7263 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7264 }
7265 updateOomAdjLocked();
7266 }
7267 }
7268
7269 public final void publishContentProviders(IApplicationThread caller,
7270 List<ContentProviderHolder> providers) {
7271 if (providers == null) {
7272 return;
7273 }
7274
7275 synchronized(this) {
7276 final ProcessRecord r = getRecordForAppLocked(caller);
7277 if (r == null) {
7278 throw new SecurityException(
7279 "Unable to find app for caller " + caller
7280 + " (pid=" + Binder.getCallingPid()
7281 + ") when publishing content providers");
7282 }
7283
7284 final long origId = Binder.clearCallingIdentity();
7285
7286 final int N = providers.size();
7287 for (int i=0; i<N; i++) {
7288 ContentProviderHolder src = providers.get(i);
7289 if (src == null || src.info == null || src.provider == null) {
7290 continue;
7291 }
7292 ContentProviderRecord dst =
7293 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7294 if (dst != null) {
7295 mProvidersByClass.put(dst.info.name, dst);
7296 String names[] = dst.info.authority.split(";");
7297 for (int j = 0; j < names.length; j++) {
7298 mProvidersByName.put(names[j], dst);
7299 }
7300
7301 int NL = mLaunchingProviders.size();
7302 int j;
7303 for (j=0; j<NL; j++) {
7304 if (mLaunchingProviders.get(j) == dst) {
7305 mLaunchingProviders.remove(j);
7306 j--;
7307 NL--;
7308 }
7309 }
7310 synchronized (dst) {
7311 dst.provider = src.provider;
7312 dst.app = r;
7313 dst.notifyAll();
7314 }
7315 updateOomAdjLocked(r);
7316 }
7317 }
7318
7319 Binder.restoreCallingIdentity(origId);
7320 }
7321 }
7322
7323 public static final void installSystemProviders() {
7324 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7325 List providers = mSelf.generateApplicationProvidersLocked(app);
7326 mSystemThread.installSystemProviders(providers);
7327 }
7328
7329 // =========================================================
7330 // GLOBAL MANAGEMENT
7331 // =========================================================
7332
7333 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7334 ApplicationInfo info, String customProcess) {
7335 String proc = customProcess != null ? customProcess : info.processName;
7336 BatteryStatsImpl.Uid.Proc ps = null;
7337 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7338 synchronized (stats) {
7339 ps = stats.getProcessStatsLocked(info.uid, proc);
7340 }
7341 return new ProcessRecord(ps, thread, info, proc);
7342 }
7343
7344 final ProcessRecord addAppLocked(ApplicationInfo info) {
7345 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7346
7347 if (app == null) {
7348 app = newProcessRecordLocked(null, info, null);
7349 mProcessNames.put(info.processName, info.uid, app);
7350 updateLRUListLocked(app, true);
7351 }
7352
7353 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7354 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7355 app.persistent = true;
7356 app.maxAdj = CORE_SERVER_ADJ;
7357 }
7358 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7359 mPersistentStartingProcesses.add(app);
7360 startProcessLocked(app, "added application", app.processName);
7361 }
7362
7363 return app;
7364 }
7365
7366 public void unhandledBack() {
7367 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7368 "unhandledBack()");
7369
7370 synchronized(this) {
7371 int count = mHistory.size();
7372 if (Config.LOGD) Log.d(
7373 TAG, "Performing unhandledBack(): stack size = " + count);
7374 if (count > 1) {
7375 final long origId = Binder.clearCallingIdentity();
7376 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7377 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7378 Binder.restoreCallingIdentity(origId);
7379 }
7380 }
7381 }
7382
7383 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7384 String name = uri.getAuthority();
7385 ContentProviderHolder cph = getContentProviderExternal(name);
7386 ParcelFileDescriptor pfd = null;
7387 if (cph != null) {
7388 // We record the binder invoker's uid in thread-local storage before
7389 // going to the content provider to open the file. Later, in the code
7390 // that handles all permissions checks, we look for this uid and use
7391 // that rather than the Activity Manager's own uid. The effect is that
7392 // we do the check against the caller's permissions even though it looks
7393 // to the content provider like the Activity Manager itself is making
7394 // the request.
7395 sCallerIdentity.set(new Identity(
7396 Binder.getCallingPid(), Binder.getCallingUid()));
7397 try {
7398 pfd = cph.provider.openFile(uri, "r");
7399 } catch (FileNotFoundException e) {
7400 // do nothing; pfd will be returned null
7401 } finally {
7402 // Ensure that whatever happens, we clean up the identity state
7403 sCallerIdentity.remove();
7404 }
7405
7406 // We've got the fd now, so we're done with the provider.
7407 removeContentProviderExternal(name);
7408 } else {
7409 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7410 }
7411 return pfd;
7412 }
7413
7414 public void goingToSleep() {
7415 synchronized(this) {
7416 mSleeping = true;
7417 mWindowManager.setEventDispatching(false);
7418
7419 if (mResumedActivity != null) {
7420 pauseIfSleepingLocked();
7421 } else {
7422 Log.w(TAG, "goingToSleep with no resumed activity!");
7423 }
7424 }
7425 }
7426
Dianne Hackborn55280a92009-05-07 15:53:46 -07007427 public boolean shutdown(int timeout) {
7428 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7429 != PackageManager.PERMISSION_GRANTED) {
7430 throw new SecurityException("Requires permission "
7431 + android.Manifest.permission.SHUTDOWN);
7432 }
7433
7434 boolean timedout = false;
7435
7436 synchronized(this) {
7437 mShuttingDown = true;
7438 mWindowManager.setEventDispatching(false);
7439
7440 if (mResumedActivity != null) {
7441 pauseIfSleepingLocked();
7442 final long endTime = System.currentTimeMillis() + timeout;
7443 while (mResumedActivity != null || mPausingActivity != null) {
7444 long delay = endTime - System.currentTimeMillis();
7445 if (delay <= 0) {
7446 Log.w(TAG, "Activity manager shutdown timed out");
7447 timedout = true;
7448 break;
7449 }
7450 try {
7451 this.wait();
7452 } catch (InterruptedException e) {
7453 }
7454 }
7455 }
7456 }
7457
7458 mUsageStatsService.shutdown();
7459 mBatteryStatsService.shutdown();
7460
7461 return timedout;
7462 }
7463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007464 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007465 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007466 if (!mGoingToSleep.isHeld()) {
7467 mGoingToSleep.acquire();
7468 if (mLaunchingActivity.isHeld()) {
7469 mLaunchingActivity.release();
7470 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7471 }
7472 }
7473
7474 // If we are not currently pausing an activity, get the current
7475 // one to pause. If we are pausing one, we will just let that stuff
7476 // run and release the wake lock when all done.
7477 if (mPausingActivity == null) {
7478 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7479 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7480 startPausingLocked(false, true);
7481 }
7482 }
7483 }
7484
7485 public void wakingUp() {
7486 synchronized(this) {
7487 if (mGoingToSleep.isHeld()) {
7488 mGoingToSleep.release();
7489 }
7490 mWindowManager.setEventDispatching(true);
7491 mSleeping = false;
7492 resumeTopActivityLocked(null);
7493 }
7494 }
7495
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007496 public void stopAppSwitches() {
7497 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7498 != PackageManager.PERMISSION_GRANTED) {
7499 throw new SecurityException("Requires permission "
7500 + android.Manifest.permission.STOP_APP_SWITCHES);
7501 }
7502
7503 synchronized(this) {
7504 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7505 + APP_SWITCH_DELAY_TIME;
7506 mDidAppSwitch = false;
7507 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7508 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7509 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7510 }
7511 }
7512
7513 public void resumeAppSwitches() {
7514 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7515 != PackageManager.PERMISSION_GRANTED) {
7516 throw new SecurityException("Requires permission "
7517 + android.Manifest.permission.STOP_APP_SWITCHES);
7518 }
7519
7520 synchronized(this) {
7521 // Note that we don't execute any pending app switches... we will
7522 // let those wait until either the timeout, or the next start
7523 // activity request.
7524 mAppSwitchesAllowedTime = 0;
7525 }
7526 }
7527
7528 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7529 String name) {
7530 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7531 return true;
7532 }
7533
7534 final int perm = checkComponentPermission(
7535 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7536 callingUid, -1);
7537 if (perm == PackageManager.PERMISSION_GRANTED) {
7538 return true;
7539 }
7540
7541 Log.w(TAG, name + " request from " + callingUid + " stopped");
7542 return false;
7543 }
7544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007545 public void setDebugApp(String packageName, boolean waitForDebugger,
7546 boolean persistent) {
7547 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7548 "setDebugApp()");
7549
7550 // Note that this is not really thread safe if there are multiple
7551 // callers into it at the same time, but that's not a situation we
7552 // care about.
7553 if (persistent) {
7554 final ContentResolver resolver = mContext.getContentResolver();
7555 Settings.System.putString(
7556 resolver, Settings.System.DEBUG_APP,
7557 packageName);
7558 Settings.System.putInt(
7559 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7560 waitForDebugger ? 1 : 0);
7561 }
7562
7563 synchronized (this) {
7564 if (!persistent) {
7565 mOrigDebugApp = mDebugApp;
7566 mOrigWaitForDebugger = mWaitForDebugger;
7567 }
7568 mDebugApp = packageName;
7569 mWaitForDebugger = waitForDebugger;
7570 mDebugTransient = !persistent;
7571 if (packageName != null) {
7572 final long origId = Binder.clearCallingIdentity();
7573 uninstallPackageLocked(packageName, -1, false);
7574 Binder.restoreCallingIdentity(origId);
7575 }
7576 }
7577 }
7578
7579 public void setAlwaysFinish(boolean enabled) {
7580 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7581 "setAlwaysFinish()");
7582
7583 Settings.System.putInt(
7584 mContext.getContentResolver(),
7585 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7586
7587 synchronized (this) {
7588 mAlwaysFinishActivities = enabled;
7589 }
7590 }
7591
7592 public void setActivityWatcher(IActivityWatcher watcher) {
7593 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7594 "setActivityWatcher()");
7595 synchronized (this) {
7596 mWatcher = watcher;
7597 }
7598 }
7599
7600 public final void enterSafeMode() {
7601 synchronized(this) {
7602 // It only makes sense to do this before the system is ready
7603 // and started launching other packages.
7604 if (!mSystemReady) {
7605 try {
7606 ActivityThread.getPackageManager().enterSafeMode();
7607 } catch (RemoteException e) {
7608 }
7609
7610 View v = LayoutInflater.from(mContext).inflate(
7611 com.android.internal.R.layout.safe_mode, null);
7612 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7613 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7614 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7615 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7616 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7617 lp.format = v.getBackground().getOpacity();
7618 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7619 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7620 ((WindowManager)mContext.getSystemService(
7621 Context.WINDOW_SERVICE)).addView(v, lp);
7622 }
7623 }
7624 }
7625
7626 public void noteWakeupAlarm(IIntentSender sender) {
7627 if (!(sender instanceof PendingIntentRecord)) {
7628 return;
7629 }
7630 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7631 synchronized (stats) {
7632 if (mBatteryStatsService.isOnBattery()) {
7633 mBatteryStatsService.enforceCallingPermission();
7634 PendingIntentRecord rec = (PendingIntentRecord)sender;
7635 int MY_UID = Binder.getCallingUid();
7636 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7637 BatteryStatsImpl.Uid.Pkg pkg =
7638 stats.getPackageStatsLocked(uid, rec.key.packageName);
7639 pkg.incWakeupsLocked();
7640 }
7641 }
7642 }
7643
7644 public boolean killPidsForMemory(int[] pids) {
7645 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7646 throw new SecurityException("killPidsForMemory only available to the system");
7647 }
7648
7649 // XXX Note: don't acquire main activity lock here, because the window
7650 // manager calls in with its locks held.
7651
7652 boolean killed = false;
7653 synchronized (mPidsSelfLocked) {
7654 int[] types = new int[pids.length];
7655 int worstType = 0;
7656 for (int i=0; i<pids.length; i++) {
7657 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7658 if (proc != null) {
7659 int type = proc.setAdj;
7660 types[i] = type;
7661 if (type > worstType) {
7662 worstType = type;
7663 }
7664 }
7665 }
7666
7667 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7668 // then constrain it so we will kill all hidden procs.
7669 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7670 worstType = HIDDEN_APP_MIN_ADJ;
7671 }
7672 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7673 for (int i=0; i<pids.length; i++) {
7674 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7675 if (proc == null) {
7676 continue;
7677 }
7678 int adj = proc.setAdj;
7679 if (adj >= worstType) {
7680 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7681 + adj + ")");
7682 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7683 proc.processName, adj);
7684 killed = true;
7685 Process.killProcess(pids[i]);
7686 }
7687 }
7688 }
7689 return killed;
7690 }
7691
7692 public void reportPss(IApplicationThread caller, int pss) {
7693 Watchdog.PssRequestor req;
7694 String name;
7695 ProcessRecord callerApp;
7696 synchronized (this) {
7697 if (caller == null) {
7698 return;
7699 }
7700 callerApp = getRecordForAppLocked(caller);
7701 if (callerApp == null) {
7702 return;
7703 }
7704 callerApp.lastPss = pss;
7705 req = callerApp;
7706 name = callerApp.processName;
7707 }
7708 Watchdog.getInstance().reportPss(req, name, pss);
7709 if (!callerApp.persistent) {
7710 removeRequestedPss(callerApp);
7711 }
7712 }
7713
7714 public void requestPss(Runnable completeCallback) {
7715 ArrayList<ProcessRecord> procs;
7716 synchronized (this) {
7717 mRequestPssCallback = completeCallback;
7718 mRequestPssList.clear();
7719 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7720 ProcessRecord proc = mLRUProcesses.get(i);
7721 if (!proc.persistent) {
7722 mRequestPssList.add(proc);
7723 }
7724 }
7725 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7726 }
7727
7728 int oldPri = Process.getThreadPriority(Process.myTid());
7729 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7730 for (int i=procs.size()-1; i>=0; i--) {
7731 ProcessRecord proc = procs.get(i);
7732 proc.lastPss = 0;
7733 proc.requestPss();
7734 }
7735 Process.setThreadPriority(oldPri);
7736 }
7737
7738 void removeRequestedPss(ProcessRecord proc) {
7739 Runnable callback = null;
7740 synchronized (this) {
7741 if (mRequestPssList.remove(proc)) {
7742 if (mRequestPssList.size() == 0) {
7743 callback = mRequestPssCallback;
7744 mRequestPssCallback = null;
7745 }
7746 }
7747 }
7748
7749 if (callback != null) {
7750 callback.run();
7751 }
7752 }
7753
7754 public void collectPss(Watchdog.PssStats stats) {
7755 stats.mEmptyPss = 0;
7756 stats.mEmptyCount = 0;
7757 stats.mBackgroundPss = 0;
7758 stats.mBackgroundCount = 0;
7759 stats.mServicePss = 0;
7760 stats.mServiceCount = 0;
7761 stats.mVisiblePss = 0;
7762 stats.mVisibleCount = 0;
7763 stats.mForegroundPss = 0;
7764 stats.mForegroundCount = 0;
7765 stats.mNoPssCount = 0;
7766 synchronized (this) {
7767 int i;
7768 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7769 ? mProcDeaths.length : stats.mProcDeaths.length;
7770 int aggr = 0;
7771 for (i=0; i<NPD; i++) {
7772 aggr += mProcDeaths[i];
7773 stats.mProcDeaths[i] = aggr;
7774 }
7775 while (i<stats.mProcDeaths.length) {
7776 stats.mProcDeaths[i] = 0;
7777 i++;
7778 }
7779
7780 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7781 ProcessRecord proc = mLRUProcesses.get(i);
7782 if (proc.persistent) {
7783 continue;
7784 }
7785 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7786 if (proc.lastPss == 0) {
7787 stats.mNoPssCount++;
7788 continue;
7789 }
7790 if (proc.setAdj == EMPTY_APP_ADJ) {
7791 stats.mEmptyPss += proc.lastPss;
7792 stats.mEmptyCount++;
7793 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7794 stats.mEmptyPss += proc.lastPss;
7795 stats.mEmptyCount++;
7796 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7797 stats.mBackgroundPss += proc.lastPss;
7798 stats.mBackgroundCount++;
7799 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7800 stats.mVisiblePss += proc.lastPss;
7801 stats.mVisibleCount++;
7802 } else {
7803 stats.mForegroundPss += proc.lastPss;
7804 stats.mForegroundCount++;
7805 }
7806 }
7807 }
7808 }
7809
7810 public final void startRunning(String pkg, String cls, String action,
7811 String data) {
7812 synchronized(this) {
7813 if (mStartRunning) {
7814 return;
7815 }
7816 mStartRunning = true;
7817 mTopComponent = pkg != null && cls != null
7818 ? new ComponentName(pkg, cls) : null;
7819 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7820 mTopData = data;
7821 if (!mSystemReady) {
7822 return;
7823 }
7824 }
7825
7826 systemReady();
7827 }
7828
7829 private void retrieveSettings() {
7830 final ContentResolver resolver = mContext.getContentResolver();
7831 String debugApp = Settings.System.getString(
7832 resolver, Settings.System.DEBUG_APP);
7833 boolean waitForDebugger = Settings.System.getInt(
7834 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7835 boolean alwaysFinishActivities = Settings.System.getInt(
7836 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7837
7838 Configuration configuration = new Configuration();
7839 Settings.System.getConfiguration(resolver, configuration);
7840
7841 synchronized (this) {
7842 mDebugApp = mOrigDebugApp = debugApp;
7843 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7844 mAlwaysFinishActivities = alwaysFinishActivities;
7845 // This happens before any activities are started, so we can
7846 // change mConfiguration in-place.
7847 mConfiguration.updateFrom(configuration);
7848 }
7849 }
7850
7851 public boolean testIsSystemReady() {
7852 // no need to synchronize(this) just to read & return the value
7853 return mSystemReady;
7854 }
7855
7856 public void systemReady() {
7857 // In the simulator, startRunning will never have been called, which
7858 // normally sets a few crucial variables. Do it here instead.
7859 if (!Process.supportsProcesses()) {
7860 mStartRunning = true;
7861 mTopAction = Intent.ACTION_MAIN;
7862 }
7863
7864 synchronized(this) {
7865 if (mSystemReady) {
7866 return;
7867 }
7868 mSystemReady = true;
7869 if (!mStartRunning) {
7870 return;
7871 }
7872 }
7873
7874 if (Config.LOGD) Log.d(TAG, "Start running!");
7875 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7876 SystemClock.uptimeMillis());
7877
7878 synchronized(this) {
7879 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7880 ResolveInfo ri = mContext.getPackageManager()
7881 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007882 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007883 CharSequence errorMsg = null;
7884 if (ri != null) {
7885 ActivityInfo ai = ri.activityInfo;
7886 ApplicationInfo app = ai.applicationInfo;
7887 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7888 mTopAction = Intent.ACTION_FACTORY_TEST;
7889 mTopData = null;
7890 mTopComponent = new ComponentName(app.packageName,
7891 ai.name);
7892 } else {
7893 errorMsg = mContext.getResources().getText(
7894 com.android.internal.R.string.factorytest_not_system);
7895 }
7896 } else {
7897 errorMsg = mContext.getResources().getText(
7898 com.android.internal.R.string.factorytest_no_action);
7899 }
7900 if (errorMsg != null) {
7901 mTopAction = null;
7902 mTopData = null;
7903 mTopComponent = null;
7904 Message msg = Message.obtain();
7905 msg.what = SHOW_FACTORY_ERROR_MSG;
7906 msg.getData().putCharSequence("msg", errorMsg);
7907 mHandler.sendMessage(msg);
7908 }
7909 }
7910 }
7911
7912 retrieveSettings();
7913
7914 synchronized (this) {
7915 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7916 try {
7917 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007918 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007919 if (apps != null) {
7920 int N = apps.size();
7921 int i;
7922 for (i=0; i<N; i++) {
7923 ApplicationInfo info
7924 = (ApplicationInfo)apps.get(i);
7925 if (info != null &&
7926 !info.packageName.equals("android")) {
7927 addAppLocked(info);
7928 }
7929 }
7930 }
7931 } catch (RemoteException ex) {
7932 // pm is in same process, this will never happen.
7933 }
7934 }
7935
7936 try {
7937 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7938 Message msg = Message.obtain();
7939 msg.what = SHOW_UID_ERROR_MSG;
7940 mHandler.sendMessage(msg);
7941 }
7942 } catch (RemoteException e) {
7943 }
7944
7945 // Start up initial activity.
7946 mBooting = true;
7947 resumeTopActivityLocked(null);
7948 }
7949 }
7950
7951 boolean makeAppCrashingLocked(ProcessRecord app,
7952 String tag, String shortMsg, String longMsg, byte[] crashData) {
7953 app.crashing = true;
7954 app.crashingReport = generateProcessError(app,
7955 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7956 startAppProblemLocked(app);
7957 app.stopFreezingAllLocked();
7958 return handleAppCrashLocked(app);
7959 }
7960
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007961 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7962 IPackageManager pm = ActivityThread.getPackageManager();
7963 try {
7964 // was an installer package name specified when this app was
7965 // installed?
7966 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7967 if (installerPackageName == null) {
7968 return null;
7969 }
7970
7971 // is there an Activity in this package that handles ACTION_APP_ERROR?
7972 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07007973 intent.setPackage(installerPackageName);
7974 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007975 if (info == null || info.activityInfo == null) {
7976 return null;
7977 }
7978
7979 return new ComponentName(installerPackageName, info.activityInfo.name);
7980 } catch (RemoteException e) {
7981 // will return null and no error report will be delivered
7982 }
7983 return null;
7984 }
7985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007986 void makeAppNotRespondingLocked(ProcessRecord app,
7987 String tag, String shortMsg, String longMsg, byte[] crashData) {
7988 app.notResponding = true;
7989 app.notRespondingReport = generateProcessError(app,
7990 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7991 crashData);
7992 startAppProblemLocked(app);
7993 app.stopFreezingAllLocked();
7994 }
7995
7996 /**
7997 * Generate a process error record, suitable for attachment to a ProcessRecord.
7998 *
7999 * @param app The ProcessRecord in which the error occurred.
8000 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8001 * ActivityManager.AppErrorStateInfo
8002 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8003 * @param shortMsg Short message describing the crash.
8004 * @param longMsg Long message describing the crash.
8005 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8006 *
8007 * @return Returns a fully-formed AppErrorStateInfo record.
8008 */
8009 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8010 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8011 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8012
8013 report.condition = condition;
8014 report.processName = app.processName;
8015 report.pid = app.pid;
8016 report.uid = app.info.uid;
8017 report.tag = tag;
8018 report.shortMsg = shortMsg;
8019 report.longMsg = longMsg;
8020 report.crashData = crashData;
8021
8022 return report;
8023 }
8024
8025 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8026 boolean crashed) {
8027 synchronized (this) {
8028 app.crashing = false;
8029 app.crashingReport = null;
8030 app.notResponding = false;
8031 app.notRespondingReport = null;
8032 if (app.anrDialog == fromDialog) {
8033 app.anrDialog = null;
8034 }
8035 if (app.waitDialog == fromDialog) {
8036 app.waitDialog = null;
8037 }
8038 if (app.pid > 0 && app.pid != MY_PID) {
8039 if (crashed) {
8040 handleAppCrashLocked(app);
8041 }
8042 Log.i(ActivityManagerService.TAG, "Killing process "
8043 + app.processName
8044 + " (pid=" + app.pid + ") at user's request");
8045 Process.killProcess(app.pid);
8046 }
8047
8048 }
8049 }
8050
8051 boolean handleAppCrashLocked(ProcessRecord app) {
8052 long now = SystemClock.uptimeMillis();
8053
8054 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8055 app.info.uid);
8056 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8057 // This process loses!
8058 Log.w(TAG, "Process " + app.info.processName
8059 + " has crashed too many times: killing!");
8060 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8061 app.info.processName, app.info.uid);
8062 killServicesLocked(app, false);
8063 for (int i=mHistory.size()-1; i>=0; i--) {
8064 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8065 if (r.app == app) {
8066 if (Config.LOGD) Log.d(
8067 TAG, " Force finishing activity "
8068 + r.intent.getComponent().flattenToShortString());
8069 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8070 }
8071 }
8072 if (!app.persistent) {
8073 // We don't want to start this process again until the user
8074 // explicitly does so... but for persistent process, we really
8075 // need to keep it running. If a persistent process is actually
8076 // repeatedly crashing, then badness for everyone.
8077 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8078 app.info.processName);
8079 mBadProcesses.put(app.info.processName, app.info.uid, now);
8080 app.bad = true;
8081 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8082 app.removed = true;
8083 removeProcessLocked(app, false);
8084 return false;
8085 }
8086 }
8087
8088 // Bump up the crash count of any services currently running in the proc.
8089 if (app.services.size() != 0) {
8090 // Any services running in the application need to be placed
8091 // back in the pending list.
8092 Iterator it = app.services.iterator();
8093 while (it.hasNext()) {
8094 ServiceRecord sr = (ServiceRecord)it.next();
8095 sr.crashCount++;
8096 }
8097 }
8098
8099 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8100 return true;
8101 }
8102
8103 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008104 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008105 skipCurrentReceiverLocked(app);
8106 }
8107
8108 void skipCurrentReceiverLocked(ProcessRecord app) {
8109 boolean reschedule = false;
8110 BroadcastRecord r = app.curReceiver;
8111 if (r != null) {
8112 // The current broadcast is waiting for this app's receiver
8113 // to be finished. Looks like that's not going to happen, so
8114 // let the broadcast continue.
8115 logBroadcastReceiverDiscard(r);
8116 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8117 r.resultExtras, r.resultAbort, true);
8118 reschedule = true;
8119 }
8120 r = mPendingBroadcast;
8121 if (r != null && r.curApp == app) {
8122 if (DEBUG_BROADCAST) Log.v(TAG,
8123 "skip & discard pending app " + r);
8124 logBroadcastReceiverDiscard(r);
8125 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8126 r.resultExtras, r.resultAbort, true);
8127 reschedule = true;
8128 }
8129 if (reschedule) {
8130 scheduleBroadcastsLocked();
8131 }
8132 }
8133
8134 public int handleApplicationError(IBinder app, int flags,
8135 String tag, String shortMsg, String longMsg, byte[] crashData) {
8136 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008137 ProcessRecord r = null;
8138 synchronized (this) {
8139 if (app != null) {
8140 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8141 final int NA = apps.size();
8142 for (int ia=0; ia<NA; ia++) {
8143 ProcessRecord p = apps.valueAt(ia);
8144 if (p.thread != null && p.thread.asBinder() == app) {
8145 r = p;
8146 break;
8147 }
8148 }
8149 }
8150 }
8151
8152 if (r != null) {
8153 // The application has crashed. Send the SIGQUIT to the process so
8154 // that it can dump its state.
8155 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8156 //Log.i(TAG, "Current system threads:");
8157 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8158 }
8159
8160 if (mWatcher != null) {
8161 try {
8162 String name = r != null ? r.processName : null;
8163 int pid = r != null ? r.pid : Binder.getCallingPid();
8164 if (!mWatcher.appCrashed(name, pid,
8165 shortMsg, longMsg, crashData)) {
8166 Log.w(TAG, "Force-killing crashed app " + name
8167 + " at watcher's request");
8168 Process.killProcess(pid);
8169 return 0;
8170 }
8171 } catch (RemoteException e) {
8172 mWatcher = null;
8173 }
8174 }
8175
8176 final long origId = Binder.clearCallingIdentity();
8177
8178 // If this process is running instrumentation, finish it.
8179 if (r != null && r.instrumentationClass != null) {
8180 Log.w(TAG, "Error in app " + r.processName
8181 + " running instrumentation " + r.instrumentationClass + ":");
8182 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8183 if (longMsg != null) Log.w(TAG, " " + longMsg);
8184 Bundle info = new Bundle();
8185 info.putString("shortMsg", shortMsg);
8186 info.putString("longMsg", longMsg);
8187 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8188 Binder.restoreCallingIdentity(origId);
8189 return 0;
8190 }
8191
8192 if (r != null) {
8193 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8194 return 0;
8195 }
8196 } else {
8197 Log.w(TAG, "Some application object " + app + " tag " + tag
8198 + " has crashed, but I don't know who it is.");
8199 Log.w(TAG, "ShortMsg:" + shortMsg);
8200 Log.w(TAG, "LongMsg:" + longMsg);
8201 Binder.restoreCallingIdentity(origId);
8202 return 0;
8203 }
8204
8205 Message msg = Message.obtain();
8206 msg.what = SHOW_ERROR_MSG;
8207 HashMap data = new HashMap();
8208 data.put("result", result);
8209 data.put("app", r);
8210 data.put("flags", flags);
8211 data.put("shortMsg", shortMsg);
8212 data.put("longMsg", longMsg);
8213 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8214 // For system processes, submit crash data to the server.
8215 data.put("crashData", crashData);
8216 }
8217 msg.obj = data;
8218 mHandler.sendMessage(msg);
8219
8220 Binder.restoreCallingIdentity(origId);
8221 }
8222
8223 int res = result.get();
8224
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008225 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008226 synchronized (this) {
8227 if (r != null) {
8228 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8229 SystemClock.uptimeMillis());
8230 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008231 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8232 appErrorIntent = createAppErrorIntentLocked(r);
8233 res = AppErrorDialog.FORCE_QUIT;
8234 }
8235 }
8236
8237 if (appErrorIntent != null) {
8238 try {
8239 mContext.startActivity(appErrorIntent);
8240 } catch (ActivityNotFoundException e) {
8241 Log.w(TAG, "bug report receiver dissappeared", e);
8242 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008243 }
8244
8245 return res;
8246 }
8247
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008248 Intent createAppErrorIntentLocked(ProcessRecord r) {
8249 ApplicationErrorReport report = createAppErrorReportLocked(r);
8250 if (report == null) {
8251 return null;
8252 }
8253 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8254 result.setComponent(r.errorReportReceiver);
8255 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8256 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8257 return result;
8258 }
8259
8260 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8261 if (r.errorReportReceiver == null) {
8262 return null;
8263 }
8264
8265 if (!r.crashing && !r.notResponding) {
8266 return null;
8267 }
8268
8269 try {
8270 ApplicationErrorReport report = new ApplicationErrorReport();
8271 report.packageName = r.info.packageName;
8272 report.installerPackageName = r.errorReportReceiver.getPackageName();
8273 report.processName = r.processName;
8274
8275 if (r.crashing) {
8276 report.type = ApplicationErrorReport.TYPE_CRASH;
8277 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8278
8279 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8280 r.crashingReport.crashData);
8281 DataInputStream dataStream = new DataInputStream(byteStream);
8282 CrashData crashData = new CrashData(dataStream);
8283 ThrowableData throwData = crashData.getThrowableData();
8284
8285 report.time = crashData.getTime();
8286 report.crashInfo.stackTrace = throwData.toString();
8287
Jacek Surazskif829a782009-06-11 22:47:02 +02008288 // Extract the source of the exception, useful for report
8289 // clustering. Also extract the "deepest" non-null exception
8290 // message.
8291 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008292 while (throwData.getCause() != null) {
8293 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008294 String msg = throwData.getMessage();
8295 if (msg != null && msg.length() > 0) {
8296 exceptionMessage = msg;
8297 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008298 }
8299 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008300 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008301 report.crashInfo.exceptionClassName = throwData.getType();
8302 report.crashInfo.throwFileName = trace.getFileName();
8303 report.crashInfo.throwClassName = trace.getClassName();
8304 report.crashInfo.throwMethodName = trace.getMethodName();
8305 } else if (r.notResponding) {
8306 report.type = ApplicationErrorReport.TYPE_ANR;
8307 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8308
8309 report.anrInfo.activity = r.notRespondingReport.tag;
8310 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8311 report.anrInfo.info = r.notRespondingReport.longMsg;
8312 }
8313
8314 return report;
8315 } catch (IOException e) {
8316 // we don't send it
8317 }
8318
8319 return null;
8320 }
8321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008322 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8323 // assume our apps are happy - lazy create the list
8324 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8325
8326 synchronized (this) {
8327
8328 // iterate across all processes
8329 final int N = mLRUProcesses.size();
8330 for (int i = 0; i < N; i++) {
8331 ProcessRecord app = mLRUProcesses.get(i);
8332 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8333 // This one's in trouble, so we'll generate a report for it
8334 // crashes are higher priority (in case there's a crash *and* an anr)
8335 ActivityManager.ProcessErrorStateInfo report = null;
8336 if (app.crashing) {
8337 report = app.crashingReport;
8338 } else if (app.notResponding) {
8339 report = app.notRespondingReport;
8340 }
8341
8342 if (report != null) {
8343 if (errList == null) {
8344 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8345 }
8346 errList.add(report);
8347 } else {
8348 Log.w(TAG, "Missing app error report, app = " + app.processName +
8349 " crashing = " + app.crashing +
8350 " notResponding = " + app.notResponding);
8351 }
8352 }
8353 }
8354 }
8355
8356 return errList;
8357 }
8358
8359 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8360 // Lazy instantiation of list
8361 List<ActivityManager.RunningAppProcessInfo> runList = null;
8362 synchronized (this) {
8363 // Iterate across all processes
8364 final int N = mLRUProcesses.size();
8365 for (int i = 0; i < N; i++) {
8366 ProcessRecord app = mLRUProcesses.get(i);
8367 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8368 // Generate process state info for running application
8369 ActivityManager.RunningAppProcessInfo currApp =
8370 new ActivityManager.RunningAppProcessInfo(app.processName,
8371 app.pid, app.getPackageList());
8372 int adj = app.curAdj;
8373 if (adj >= CONTENT_PROVIDER_ADJ) {
8374 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8375 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8376 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008377 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8378 } else if (adj >= HOME_APP_ADJ) {
8379 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8380 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008381 } else if (adj >= SECONDARY_SERVER_ADJ) {
8382 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8383 } else if (adj >= VISIBLE_APP_ADJ) {
8384 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8385 } else {
8386 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8387 }
8388 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8389 // + " lru=" + currApp.lru);
8390 if (runList == null) {
8391 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8392 }
8393 runList.add(currApp);
8394 }
8395 }
8396 }
8397 return runList;
8398 }
8399
8400 @Override
8401 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8402 synchronized (this) {
8403 if (checkCallingPermission(android.Manifest.permission.DUMP)
8404 != PackageManager.PERMISSION_GRANTED) {
8405 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8406 + Binder.getCallingPid()
8407 + ", uid=" + Binder.getCallingUid()
8408 + " without permission "
8409 + android.Manifest.permission.DUMP);
8410 return;
8411 }
8412 if (args.length != 0 && "service".equals(args[0])) {
8413 dumpService(fd, pw, args);
8414 return;
8415 }
8416 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008417 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008418 pw.println(" ");
8419 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008420 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008421 if (mWaitingVisibleActivities.size() > 0) {
8422 pw.println(" ");
8423 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008424 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008425 }
8426 if (mStoppingActivities.size() > 0) {
8427 pw.println(" ");
8428 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008429 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008430 }
8431 if (mFinishingActivities.size() > 0) {
8432 pw.println(" ");
8433 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008434 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008435 }
8436
8437 pw.println(" ");
8438 pw.println(" mPausingActivity: " + mPausingActivity);
8439 pw.println(" mResumedActivity: " + mResumedActivity);
8440 pw.println(" mFocusedActivity: " + mFocusedActivity);
8441 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8442
8443 if (mRecentTasks.size() > 0) {
8444 pw.println(" ");
8445 pw.println("Recent tasks in Current Activity Manager State:");
8446
8447 final int N = mRecentTasks.size();
8448 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008449 TaskRecord tr = mRecentTasks.get(i);
8450 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8451 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008452 mRecentTasks.get(i).dump(pw, " ");
8453 }
8454 }
8455
8456 pw.println(" ");
8457 pw.println(" mCurTask: " + mCurTask);
8458
8459 pw.println(" ");
8460 pw.println("Processes in Current Activity Manager State:");
8461
8462 boolean needSep = false;
8463 int numPers = 0;
8464
8465 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8466 final int NA = procs.size();
8467 for (int ia=0; ia<NA; ia++) {
8468 if (!needSep) {
8469 pw.println(" All known processes:");
8470 needSep = true;
8471 }
8472 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008473 pw.print(r.persistent ? " *PERS*" : " *APP*");
8474 pw.print(" UID "); pw.print(procs.keyAt(ia));
8475 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008476 r.dump(pw, " ");
8477 if (r.persistent) {
8478 numPers++;
8479 }
8480 }
8481 }
8482
8483 if (mLRUProcesses.size() > 0) {
8484 if (needSep) pw.println(" ");
8485 needSep = true;
8486 pw.println(" Running processes (most recent first):");
8487 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008488 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008489 needSep = true;
8490 }
8491
8492 synchronized (mPidsSelfLocked) {
8493 if (mPidsSelfLocked.size() > 0) {
8494 if (needSep) pw.println(" ");
8495 needSep = true;
8496 pw.println(" PID mappings:");
8497 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008498 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8499 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008500 }
8501 }
8502 }
8503
8504 if (mForegroundProcesses.size() > 0) {
8505 if (needSep) pw.println(" ");
8506 needSep = true;
8507 pw.println(" Foreground Processes:");
8508 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008509 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8510 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 }
8512 }
8513
8514 if (mPersistentStartingProcesses.size() > 0) {
8515 if (needSep) pw.println(" ");
8516 needSep = true;
8517 pw.println(" Persisent processes that are starting:");
8518 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008519 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 }
8521
8522 if (mStartingProcesses.size() > 0) {
8523 if (needSep) pw.println(" ");
8524 needSep = true;
8525 pw.println(" Processes that are starting:");
8526 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008527 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008528 }
8529
8530 if (mRemovedProcesses.size() > 0) {
8531 if (needSep) pw.println(" ");
8532 needSep = true;
8533 pw.println(" Processes that are being removed:");
8534 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008535 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008536 }
8537
8538 if (mProcessesOnHold.size() > 0) {
8539 if (needSep) pw.println(" ");
8540 needSep = true;
8541 pw.println(" Processes that are on old until the system is ready:");
8542 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008543 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008544 }
8545
8546 if (mProcessCrashTimes.getMap().size() > 0) {
8547 if (needSep) pw.println(" ");
8548 needSep = true;
8549 pw.println(" Time since processes crashed:");
8550 long now = SystemClock.uptimeMillis();
8551 for (Map.Entry<String, SparseArray<Long>> procs
8552 : mProcessCrashTimes.getMap().entrySet()) {
8553 SparseArray<Long> uids = procs.getValue();
8554 final int N = uids.size();
8555 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008556 pw.print(" Process "); pw.print(procs.getKey());
8557 pw.print(" uid "); pw.print(uids.keyAt(i));
8558 pw.print(": last crashed ");
8559 pw.print((now-uids.valueAt(i)));
8560 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008561 }
8562 }
8563 }
8564
8565 if (mBadProcesses.getMap().size() > 0) {
8566 if (needSep) pw.println(" ");
8567 needSep = true;
8568 pw.println(" Bad processes:");
8569 for (Map.Entry<String, SparseArray<Long>> procs
8570 : mBadProcesses.getMap().entrySet()) {
8571 SparseArray<Long> uids = procs.getValue();
8572 final int N = uids.size();
8573 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008574 pw.print(" Bad process "); pw.print(procs.getKey());
8575 pw.print(" uid "); pw.print(uids.keyAt(i));
8576 pw.print(": crashed at time ");
8577 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008578 }
8579 }
8580 }
8581
8582 pw.println(" ");
8583 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008584 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008585 pw.println(" mConfiguration: " + mConfiguration);
8586 pw.println(" mStartRunning=" + mStartRunning
8587 + " mSystemReady=" + mSystemReady
8588 + " mBooting=" + mBooting
8589 + " mBooted=" + mBooted
8590 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008591 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008592 pw.println(" mGoingToSleep=" + mGoingToSleep);
8593 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8594 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8595 + " mDebugTransient=" + mDebugTransient
8596 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8597 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8598 + " mWatcher=" + mWatcher);
8599 }
8600 }
8601
8602 /**
8603 * There are three ways to call this:
8604 * - no service specified: dump all the services
8605 * - a flattened component name that matched an existing service was specified as the
8606 * first arg: dump that one service
8607 * - the first arg isn't the flattened component name of an existing service:
8608 * dump all services whose component contains the first arg as a substring
8609 */
8610 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8611 String[] newArgs;
8612 String componentNameString;
8613 ServiceRecord r;
8614 if (args.length == 1) {
8615 componentNameString = null;
8616 newArgs = EMPTY_STRING_ARRAY;
8617 r = null;
8618 } else {
8619 componentNameString = args[1];
8620 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8621 r = componentName != null ? mServices.get(componentName) : null;
8622 newArgs = new String[args.length - 2];
8623 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8624 }
8625
8626 if (r != null) {
8627 dumpService(fd, pw, r, newArgs);
8628 } else {
8629 for (ServiceRecord r1 : mServices.values()) {
8630 if (componentNameString == null
8631 || r1.name.flattenToString().contains(componentNameString)) {
8632 dumpService(fd, pw, r1, newArgs);
8633 }
8634 }
8635 }
8636 }
8637
8638 /**
8639 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8640 * there is a thread associated with the service.
8641 */
8642 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8643 pw.println(" Service " + r.name.flattenToString());
8644 if (r.app != null && r.app.thread != null) {
8645 try {
8646 // flush anything that is already in the PrintWriter since the thread is going
8647 // to write to the file descriptor directly
8648 pw.flush();
8649 r.app.thread.dumpService(fd, r, args);
8650 pw.print("\n");
8651 } catch (RemoteException e) {
8652 pw.println("got a RemoteException while dumping the service");
8653 }
8654 }
8655 }
8656
8657 void dumpBroadcasts(PrintWriter pw) {
8658 synchronized (this) {
8659 if (checkCallingPermission(android.Manifest.permission.DUMP)
8660 != PackageManager.PERMISSION_GRANTED) {
8661 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8662 + Binder.getCallingPid()
8663 + ", uid=" + Binder.getCallingUid()
8664 + " without permission "
8665 + android.Manifest.permission.DUMP);
8666 return;
8667 }
8668 pw.println("Broadcasts in Current Activity Manager State:");
8669
8670 if (mRegisteredReceivers.size() > 0) {
8671 pw.println(" ");
8672 pw.println(" Registered Receivers:");
8673 Iterator it = mRegisteredReceivers.values().iterator();
8674 while (it.hasNext()) {
8675 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008676 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008677 r.dump(pw, " ");
8678 }
8679 }
8680
8681 pw.println(" ");
8682 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008683 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008684
8685 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8686 || mPendingBroadcast != null) {
8687 if (mParallelBroadcasts.size() > 0) {
8688 pw.println(" ");
8689 pw.println(" Active broadcasts:");
8690 }
8691 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8692 pw.println(" Broadcast #" + i + ":");
8693 mParallelBroadcasts.get(i).dump(pw, " ");
8694 }
8695 if (mOrderedBroadcasts.size() > 0) {
8696 pw.println(" ");
8697 pw.println(" Active serialized broadcasts:");
8698 }
8699 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8700 pw.println(" Serialized Broadcast #" + i + ":");
8701 mOrderedBroadcasts.get(i).dump(pw, " ");
8702 }
8703 pw.println(" ");
8704 pw.println(" Pending broadcast:");
8705 if (mPendingBroadcast != null) {
8706 mPendingBroadcast.dump(pw, " ");
8707 } else {
8708 pw.println(" (null)");
8709 }
8710 }
8711
8712 pw.println(" ");
8713 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8714 if (mStickyBroadcasts != null) {
8715 pw.println(" ");
8716 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008717 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008718 for (Map.Entry<String, ArrayList<Intent>> ent
8719 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008720 pw.print(" * Sticky action "); pw.print(ent.getKey());
8721 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008722 ArrayList<Intent> intents = ent.getValue();
8723 final int N = intents.size();
8724 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008725 sb.setLength(0);
8726 sb.append(" Intent: ");
8727 intents.get(i).toShortString(sb, true, false);
8728 pw.println(sb.toString());
8729 Bundle bundle = intents.get(i).getExtras();
8730 if (bundle != null) {
8731 pw.print(" ");
8732 pw.println(bundle.toString());
8733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008734 }
8735 }
8736 }
8737
8738 pw.println(" ");
8739 pw.println(" mHandler:");
8740 mHandler.dump(new PrintWriterPrinter(pw), " ");
8741 }
8742 }
8743
8744 void dumpServices(PrintWriter pw) {
8745 synchronized (this) {
8746 if (checkCallingPermission(android.Manifest.permission.DUMP)
8747 != PackageManager.PERMISSION_GRANTED) {
8748 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8749 + Binder.getCallingPid()
8750 + ", uid=" + Binder.getCallingUid()
8751 + " without permission "
8752 + android.Manifest.permission.DUMP);
8753 return;
8754 }
8755 pw.println("Services in Current Activity Manager State:");
8756
8757 boolean needSep = false;
8758
8759 if (mServices.size() > 0) {
8760 pw.println(" Active services:");
8761 Iterator<ServiceRecord> it = mServices.values().iterator();
8762 while (it.hasNext()) {
8763 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008764 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008765 r.dump(pw, " ");
8766 }
8767 needSep = true;
8768 }
8769
8770 if (mPendingServices.size() > 0) {
8771 if (needSep) pw.println(" ");
8772 pw.println(" Pending services:");
8773 for (int i=0; i<mPendingServices.size(); i++) {
8774 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008775 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008776 r.dump(pw, " ");
8777 }
8778 needSep = true;
8779 }
8780
8781 if (mRestartingServices.size() > 0) {
8782 if (needSep) pw.println(" ");
8783 pw.println(" Restarting services:");
8784 for (int i=0; i<mRestartingServices.size(); i++) {
8785 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008786 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008787 r.dump(pw, " ");
8788 }
8789 needSep = true;
8790 }
8791
8792 if (mStoppingServices.size() > 0) {
8793 if (needSep) pw.println(" ");
8794 pw.println(" Stopping services:");
8795 for (int i=0; i<mStoppingServices.size(); i++) {
8796 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008797 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008798 r.dump(pw, " ");
8799 }
8800 needSep = true;
8801 }
8802
8803 if (mServiceConnections.size() > 0) {
8804 if (needSep) pw.println(" ");
8805 pw.println(" Connection bindings to services:");
8806 Iterator<ConnectionRecord> it
8807 = mServiceConnections.values().iterator();
8808 while (it.hasNext()) {
8809 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008810 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008811 r.dump(pw, " ");
8812 }
8813 }
8814 }
8815 }
8816
8817 void dumpProviders(PrintWriter pw) {
8818 synchronized (this) {
8819 if (checkCallingPermission(android.Manifest.permission.DUMP)
8820 != PackageManager.PERMISSION_GRANTED) {
8821 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8822 + Binder.getCallingPid()
8823 + ", uid=" + Binder.getCallingUid()
8824 + " without permission "
8825 + android.Manifest.permission.DUMP);
8826 return;
8827 }
8828
8829 pw.println("Content Providers in Current Activity Manager State:");
8830
8831 boolean needSep = false;
8832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008833 if (mProvidersByClass.size() > 0) {
8834 if (needSep) pw.println(" ");
8835 pw.println(" Published content providers (by class):");
8836 Iterator it = mProvidersByClass.entrySet().iterator();
8837 while (it.hasNext()) {
8838 Map.Entry e = (Map.Entry)it.next();
8839 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008840 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008841 r.dump(pw, " ");
8842 }
8843 needSep = true;
8844 }
8845
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008846 if (mProvidersByName.size() > 0) {
8847 pw.println(" ");
8848 pw.println(" Authority to provider mappings:");
8849 Iterator it = mProvidersByName.entrySet().iterator();
8850 while (it.hasNext()) {
8851 Map.Entry e = (Map.Entry)it.next();
8852 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8853 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8854 pw.println(r);
8855 }
8856 needSep = true;
8857 }
8858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008859 if (mLaunchingProviders.size() > 0) {
8860 if (needSep) pw.println(" ");
8861 pw.println(" Launching content providers:");
8862 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008863 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8864 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008865 }
8866 needSep = true;
8867 }
8868
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008869 if (mGrantedUriPermissions.size() > 0) {
8870 pw.println();
8871 pw.println("Granted Uri Permissions:");
8872 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8873 int uid = mGrantedUriPermissions.keyAt(i);
8874 HashMap<Uri, UriPermission> perms
8875 = mGrantedUriPermissions.valueAt(i);
8876 pw.print(" * UID "); pw.print(uid);
8877 pw.println(" holds:");
8878 for (UriPermission perm : perms.values()) {
8879 pw.print(" "); pw.println(perm);
8880 perm.dump(pw, " ");
8881 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008882 }
8883 }
8884 }
8885 }
8886
8887 void dumpSenders(PrintWriter pw) {
8888 synchronized (this) {
8889 if (checkCallingPermission(android.Manifest.permission.DUMP)
8890 != PackageManager.PERMISSION_GRANTED) {
8891 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8892 + Binder.getCallingPid()
8893 + ", uid=" + Binder.getCallingUid()
8894 + " without permission "
8895 + android.Manifest.permission.DUMP);
8896 return;
8897 }
8898
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008899 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008900
8901 if (this.mIntentSenderRecords.size() > 0) {
8902 Iterator<WeakReference<PendingIntentRecord>> it
8903 = mIntentSenderRecords.values().iterator();
8904 while (it.hasNext()) {
8905 WeakReference<PendingIntentRecord> ref = it.next();
8906 PendingIntentRecord rec = ref != null ? ref.get(): null;
8907 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008908 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008909 rec.dump(pw, " ");
8910 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008911 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008912 }
8913 }
8914 }
8915 }
8916 }
8917
8918 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008919 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008920 TaskRecord lastTask = null;
8921 for (int i=list.size()-1; i>=0; i--) {
8922 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008923 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008924 if (lastTask != r.task) {
8925 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008926 pw.print(prefix);
8927 pw.print(full ? "* " : " ");
8928 pw.println(lastTask);
8929 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008930 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008932 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008933 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8934 pw.print(" #"); pw.print(i); pw.print(": ");
8935 pw.println(r);
8936 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008937 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008939 }
8940 }
8941
8942 private static final int dumpProcessList(PrintWriter pw, List list,
8943 String prefix, String normalLabel, String persistentLabel,
8944 boolean inclOomAdj) {
8945 int numPers = 0;
8946 for (int i=list.size()-1; i>=0; i--) {
8947 ProcessRecord r = (ProcessRecord)list.get(i);
8948 if (false) {
8949 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8950 + " #" + i + ":");
8951 r.dump(pw, prefix + " ");
8952 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008953 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008954 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008955 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008956 } else {
8957 pw.println(String.format("%s%s #%2d: %s",
8958 prefix, (r.persistent ? persistentLabel : normalLabel),
8959 i, r.toString()));
8960 }
8961 if (r.persistent) {
8962 numPers++;
8963 }
8964 }
8965 return numPers;
8966 }
8967
8968 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8969 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008970 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008971 long uptime = SystemClock.uptimeMillis();
8972 long realtime = SystemClock.elapsedRealtime();
8973
8974 if (isCheckinRequest) {
8975 // short checkin version
8976 pw.println(uptime + "," + realtime);
8977 pw.flush();
8978 } else {
8979 pw.println("Applications Memory Usage (kB):");
8980 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8981 }
8982 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8983 ProcessRecord r = (ProcessRecord)list.get(i);
8984 if (r.thread != null) {
8985 if (!isCheckinRequest) {
8986 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8987 pw.flush();
8988 }
8989 try {
8990 r.thread.asBinder().dump(fd, args);
8991 } catch (RemoteException e) {
8992 if (!isCheckinRequest) {
8993 pw.println("Got RemoteException!");
8994 pw.flush();
8995 }
8996 }
8997 }
8998 }
8999 }
9000
9001 /**
9002 * Searches array of arguments for the specified string
9003 * @param args array of argument strings
9004 * @param value value to search for
9005 * @return true if the value is contained in the array
9006 */
9007 private static boolean scanArgs(String[] args, String value) {
9008 if (args != null) {
9009 for (String arg : args) {
9010 if (value.equals(arg)) {
9011 return true;
9012 }
9013 }
9014 }
9015 return false;
9016 }
9017
Dianne Hackborn75b03852009-06-12 15:43:26 -07009018 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009019 int count = mHistory.size();
9020
9021 // convert the token to an entry in the history.
9022 HistoryRecord r = null;
9023 int index = -1;
9024 for (int i=count-1; i>=0; i--) {
9025 Object o = mHistory.get(i);
9026 if (o == token) {
9027 r = (HistoryRecord)o;
9028 index = i;
9029 break;
9030 }
9031 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009032
9033 return index;
9034 }
9035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036 private final void killServicesLocked(ProcessRecord app,
9037 boolean allowRestart) {
9038 // Report disconnected services.
9039 if (false) {
9040 // XXX we are letting the client link to the service for
9041 // death notifications.
9042 if (app.services.size() > 0) {
9043 Iterator it = app.services.iterator();
9044 while (it.hasNext()) {
9045 ServiceRecord r = (ServiceRecord)it.next();
9046 if (r.connections.size() > 0) {
9047 Iterator<ConnectionRecord> jt
9048 = r.connections.values().iterator();
9049 while (jt.hasNext()) {
9050 ConnectionRecord c = jt.next();
9051 if (c.binding.client != app) {
9052 try {
9053 //c.conn.connected(r.className, null);
9054 } catch (Exception e) {
9055 // todo: this should be asynchronous!
9056 Log.w(TAG, "Exception thrown disconnected servce "
9057 + r.shortName
9058 + " from app " + app.processName, e);
9059 }
9060 }
9061 }
9062 }
9063 }
9064 }
9065 }
9066
9067 // Clean up any connections this application has to other services.
9068 if (app.connections.size() > 0) {
9069 Iterator<ConnectionRecord> it = app.connections.iterator();
9070 while (it.hasNext()) {
9071 ConnectionRecord r = it.next();
9072 removeConnectionLocked(r, app, null);
9073 }
9074 }
9075 app.connections.clear();
9076
9077 if (app.services.size() != 0) {
9078 // Any services running in the application need to be placed
9079 // back in the pending list.
9080 Iterator it = app.services.iterator();
9081 while (it.hasNext()) {
9082 ServiceRecord sr = (ServiceRecord)it.next();
9083 synchronized (sr.stats.getBatteryStats()) {
9084 sr.stats.stopLaunchedLocked();
9085 }
9086 sr.app = null;
9087 sr.executeNesting = 0;
9088 mStoppingServices.remove(sr);
9089 if (sr.bindings.size() > 0) {
9090 Iterator<IntentBindRecord> bindings
9091 = sr.bindings.values().iterator();
9092 while (bindings.hasNext()) {
9093 IntentBindRecord b = bindings.next();
9094 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9095 + ": shouldUnbind=" + b.hasBound);
9096 b.binder = null;
9097 b.requested = b.received = b.hasBound = false;
9098 }
9099 }
9100
9101 if (sr.crashCount >= 2) {
9102 Log.w(TAG, "Service crashed " + sr.crashCount
9103 + " times, stopping: " + sr);
9104 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9105 sr.crashCount, sr.shortName, app.pid);
9106 bringDownServiceLocked(sr, true);
9107 } else if (!allowRestart) {
9108 bringDownServiceLocked(sr, true);
9109 } else {
9110 scheduleServiceRestartLocked(sr);
9111 }
9112 }
9113
9114 if (!allowRestart) {
9115 app.services.clear();
9116 }
9117 }
9118
9119 app.executingServices.clear();
9120 }
9121
9122 private final void removeDyingProviderLocked(ProcessRecord proc,
9123 ContentProviderRecord cpr) {
9124 synchronized (cpr) {
9125 cpr.launchingApp = null;
9126 cpr.notifyAll();
9127 }
9128
9129 mProvidersByClass.remove(cpr.info.name);
9130 String names[] = cpr.info.authority.split(";");
9131 for (int j = 0; j < names.length; j++) {
9132 mProvidersByName.remove(names[j]);
9133 }
9134
9135 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9136 while (cit.hasNext()) {
9137 ProcessRecord capp = cit.next();
9138 if (!capp.persistent && capp.thread != null
9139 && capp.pid != 0
9140 && capp.pid != MY_PID) {
9141 Log.i(TAG, "Killing app " + capp.processName
9142 + " (pid " + capp.pid
9143 + ") because provider " + cpr.info.name
9144 + " is in dying process " + proc.processName);
9145 Process.killProcess(capp.pid);
9146 }
9147 }
9148
9149 mLaunchingProviders.remove(cpr);
9150 }
9151
9152 /**
9153 * Main code for cleaning up a process when it has gone away. This is
9154 * called both as a result of the process dying, or directly when stopping
9155 * a process when running in single process mode.
9156 */
9157 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9158 boolean restarting, int index) {
9159 if (index >= 0) {
9160 mLRUProcesses.remove(index);
9161 }
9162
9163 // Dismiss any open dialogs.
9164 if (app.crashDialog != null) {
9165 app.crashDialog.dismiss();
9166 app.crashDialog = null;
9167 }
9168 if (app.anrDialog != null) {
9169 app.anrDialog.dismiss();
9170 app.anrDialog = null;
9171 }
9172 if (app.waitDialog != null) {
9173 app.waitDialog.dismiss();
9174 app.waitDialog = null;
9175 }
9176
9177 app.crashing = false;
9178 app.notResponding = false;
9179
9180 app.resetPackageList();
9181 app.thread = null;
9182 app.forcingToForeground = null;
9183 app.foregroundServices = false;
9184
9185 killServicesLocked(app, true);
9186
9187 boolean restart = false;
9188
9189 int NL = mLaunchingProviders.size();
9190
9191 // Remove published content providers.
9192 if (!app.pubProviders.isEmpty()) {
9193 Iterator it = app.pubProviders.values().iterator();
9194 while (it.hasNext()) {
9195 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9196 cpr.provider = null;
9197 cpr.app = null;
9198
9199 // See if someone is waiting for this provider... in which
9200 // case we don't remove it, but just let it restart.
9201 int i = 0;
9202 if (!app.bad) {
9203 for (; i<NL; i++) {
9204 if (mLaunchingProviders.get(i) == cpr) {
9205 restart = true;
9206 break;
9207 }
9208 }
9209 } else {
9210 i = NL;
9211 }
9212
9213 if (i >= NL) {
9214 removeDyingProviderLocked(app, cpr);
9215 NL = mLaunchingProviders.size();
9216 }
9217 }
9218 app.pubProviders.clear();
9219 }
9220
9221 // Look through the content providers we are waiting to have launched,
9222 // and if any run in this process then either schedule a restart of
9223 // the process or kill the client waiting for it if this process has
9224 // gone bad.
9225 for (int i=0; i<NL; i++) {
9226 ContentProviderRecord cpr = (ContentProviderRecord)
9227 mLaunchingProviders.get(i);
9228 if (cpr.launchingApp == app) {
9229 if (!app.bad) {
9230 restart = true;
9231 } else {
9232 removeDyingProviderLocked(app, cpr);
9233 NL = mLaunchingProviders.size();
9234 }
9235 }
9236 }
9237
9238 // Unregister from connected content providers.
9239 if (!app.conProviders.isEmpty()) {
9240 Iterator it = app.conProviders.iterator();
9241 while (it.hasNext()) {
9242 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9243 cpr.clients.remove(app);
9244 }
9245 app.conProviders.clear();
9246 }
9247
9248 skipCurrentReceiverLocked(app);
9249
9250 // Unregister any receivers.
9251 if (app.receivers.size() > 0) {
9252 Iterator<ReceiverList> it = app.receivers.iterator();
9253 while (it.hasNext()) {
9254 removeReceiverLocked(it.next());
9255 }
9256 app.receivers.clear();
9257 }
9258
Christopher Tate181fafa2009-05-14 11:12:14 -07009259 // If the app is undergoing backup, tell the backup manager about it
9260 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9261 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9262 try {
9263 IBackupManager bm = IBackupManager.Stub.asInterface(
9264 ServiceManager.getService(Context.BACKUP_SERVICE));
9265 bm.agentDisconnected(app.info.packageName);
9266 } catch (RemoteException e) {
9267 // can't happen; backup manager is local
9268 }
9269 }
9270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009271 // If the caller is restarting this app, then leave it in its
9272 // current lists and let the caller take care of it.
9273 if (restarting) {
9274 return;
9275 }
9276
9277 if (!app.persistent) {
9278 if (DEBUG_PROCESSES) Log.v(TAG,
9279 "Removing non-persistent process during cleanup: " + app);
9280 mProcessNames.remove(app.processName, app.info.uid);
9281 } else if (!app.removed) {
9282 // This app is persistent, so we need to keep its record around.
9283 // If it is not already on the pending app list, add it there
9284 // and start a new process for it.
9285 app.thread = null;
9286 app.forcingToForeground = null;
9287 app.foregroundServices = false;
9288 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9289 mPersistentStartingProcesses.add(app);
9290 restart = true;
9291 }
9292 }
9293 mProcessesOnHold.remove(app);
9294
The Android Open Source Project4df24232009-03-05 14:34:35 -08009295 if (app == mHomeProcess) {
9296 mHomeProcess = null;
9297 }
9298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009299 if (restart) {
9300 // We have components that still need to be running in the
9301 // process, so re-launch it.
9302 mProcessNames.put(app.processName, app.info.uid, app);
9303 startProcessLocked(app, "restart", app.processName);
9304 } else if (app.pid > 0 && app.pid != MY_PID) {
9305 // Goodbye!
9306 synchronized (mPidsSelfLocked) {
9307 mPidsSelfLocked.remove(app.pid);
9308 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9309 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009310 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009311 }
9312 }
9313
9314 // =========================================================
9315 // SERVICES
9316 // =========================================================
9317
9318 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9319 ActivityManager.RunningServiceInfo info =
9320 new ActivityManager.RunningServiceInfo();
9321 info.service = r.name;
9322 if (r.app != null) {
9323 info.pid = r.app.pid;
9324 }
9325 info.process = r.processName;
9326 info.foreground = r.isForeground;
9327 info.activeSince = r.createTime;
9328 info.started = r.startRequested;
9329 info.clientCount = r.connections.size();
9330 info.crashCount = r.crashCount;
9331 info.lastActivityTime = r.lastActivity;
9332 return info;
9333 }
9334
9335 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9336 int flags) {
9337 synchronized (this) {
9338 ArrayList<ActivityManager.RunningServiceInfo> res
9339 = new ArrayList<ActivityManager.RunningServiceInfo>();
9340
9341 if (mServices.size() > 0) {
9342 Iterator<ServiceRecord> it = mServices.values().iterator();
9343 while (it.hasNext() && res.size() < maxNum) {
9344 res.add(makeRunningServiceInfoLocked(it.next()));
9345 }
9346 }
9347
9348 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9349 ServiceRecord r = mRestartingServices.get(i);
9350 ActivityManager.RunningServiceInfo info =
9351 makeRunningServiceInfoLocked(r);
9352 info.restarting = r.nextRestartTime;
9353 res.add(info);
9354 }
9355
9356 return res;
9357 }
9358 }
9359
9360 private final ServiceRecord findServiceLocked(ComponentName name,
9361 IBinder token) {
9362 ServiceRecord r = mServices.get(name);
9363 return r == token ? r : null;
9364 }
9365
9366 private final class ServiceLookupResult {
9367 final ServiceRecord record;
9368 final String permission;
9369
9370 ServiceLookupResult(ServiceRecord _record, String _permission) {
9371 record = _record;
9372 permission = _permission;
9373 }
9374 };
9375
9376 private ServiceLookupResult findServiceLocked(Intent service,
9377 String resolvedType) {
9378 ServiceRecord r = null;
9379 if (service.getComponent() != null) {
9380 r = mServices.get(service.getComponent());
9381 }
9382 if (r == null) {
9383 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9384 r = mServicesByIntent.get(filter);
9385 }
9386
9387 if (r == null) {
9388 try {
9389 ResolveInfo rInfo =
9390 ActivityThread.getPackageManager().resolveService(
9391 service, resolvedType, 0);
9392 ServiceInfo sInfo =
9393 rInfo != null ? rInfo.serviceInfo : null;
9394 if (sInfo == null) {
9395 return null;
9396 }
9397
9398 ComponentName name = new ComponentName(
9399 sInfo.applicationInfo.packageName, sInfo.name);
9400 r = mServices.get(name);
9401 } catch (RemoteException ex) {
9402 // pm is in same process, this will never happen.
9403 }
9404 }
9405 if (r != null) {
9406 int callingPid = Binder.getCallingPid();
9407 int callingUid = Binder.getCallingUid();
9408 if (checkComponentPermission(r.permission,
9409 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9410 != PackageManager.PERMISSION_GRANTED) {
9411 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9412 + " from pid=" + callingPid
9413 + ", uid=" + callingUid
9414 + " requires " + r.permission);
9415 return new ServiceLookupResult(null, r.permission);
9416 }
9417 return new ServiceLookupResult(r, null);
9418 }
9419 return null;
9420 }
9421
9422 private class ServiceRestarter implements Runnable {
9423 private ServiceRecord mService;
9424
9425 void setService(ServiceRecord service) {
9426 mService = service;
9427 }
9428
9429 public void run() {
9430 synchronized(ActivityManagerService.this) {
9431 performServiceRestartLocked(mService);
9432 }
9433 }
9434 }
9435
9436 private ServiceLookupResult retrieveServiceLocked(Intent service,
9437 String resolvedType, int callingPid, int callingUid) {
9438 ServiceRecord r = null;
9439 if (service.getComponent() != null) {
9440 r = mServices.get(service.getComponent());
9441 }
9442 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9443 r = mServicesByIntent.get(filter);
9444 if (r == null) {
9445 try {
9446 ResolveInfo rInfo =
9447 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009448 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009449 ServiceInfo sInfo =
9450 rInfo != null ? rInfo.serviceInfo : null;
9451 if (sInfo == null) {
9452 Log.w(TAG, "Unable to start service " + service +
9453 ": not found");
9454 return null;
9455 }
9456
9457 ComponentName name = new ComponentName(
9458 sInfo.applicationInfo.packageName, sInfo.name);
9459 r = mServices.get(name);
9460 if (r == null) {
9461 filter = new Intent.FilterComparison(service.cloneFilter());
9462 ServiceRestarter res = new ServiceRestarter();
9463 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9464 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9465 synchronized (stats) {
9466 ss = stats.getServiceStatsLocked(
9467 sInfo.applicationInfo.uid, sInfo.packageName,
9468 sInfo.name);
9469 }
9470 r = new ServiceRecord(ss, name, filter, sInfo, res);
9471 res.setService(r);
9472 mServices.put(name, r);
9473 mServicesByIntent.put(filter, r);
9474
9475 // Make sure this component isn't in the pending list.
9476 int N = mPendingServices.size();
9477 for (int i=0; i<N; i++) {
9478 ServiceRecord pr = mPendingServices.get(i);
9479 if (pr.name.equals(name)) {
9480 mPendingServices.remove(i);
9481 i--;
9482 N--;
9483 }
9484 }
9485 }
9486 } catch (RemoteException ex) {
9487 // pm is in same process, this will never happen.
9488 }
9489 }
9490 if (r != null) {
9491 if (checkComponentPermission(r.permission,
9492 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9493 != PackageManager.PERMISSION_GRANTED) {
9494 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9495 + " from pid=" + Binder.getCallingPid()
9496 + ", uid=" + Binder.getCallingUid()
9497 + " requires " + r.permission);
9498 return new ServiceLookupResult(null, r.permission);
9499 }
9500 return new ServiceLookupResult(r, null);
9501 }
9502 return null;
9503 }
9504
9505 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9506 long now = SystemClock.uptimeMillis();
9507 if (r.executeNesting == 0 && r.app != null) {
9508 if (r.app.executingServices.size() == 0) {
9509 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9510 msg.obj = r.app;
9511 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9512 }
9513 r.app.executingServices.add(r);
9514 }
9515 r.executeNesting++;
9516 r.executingStart = now;
9517 }
9518
9519 private final void sendServiceArgsLocked(ServiceRecord r,
9520 boolean oomAdjusted) {
9521 final int N = r.startArgs.size();
9522 if (N == 0) {
9523 return;
9524 }
9525
9526 final int BASEID = r.lastStartId - N + 1;
9527 int i = 0;
9528 while (i < N) {
9529 try {
9530 Intent args = r.startArgs.get(i);
9531 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9532 + r.name + " " + r.intent + " args=" + args);
9533 bumpServiceExecutingLocked(r);
9534 if (!oomAdjusted) {
9535 oomAdjusted = true;
9536 updateOomAdjLocked(r.app);
9537 }
9538 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9539 i++;
9540 } catch (Exception e) {
9541 break;
9542 }
9543 }
9544 if (i == N) {
9545 r.startArgs.clear();
9546 } else {
9547 while (i > 0) {
9548 r.startArgs.remove(0);
9549 i--;
9550 }
9551 }
9552 }
9553
9554 private final boolean requestServiceBindingLocked(ServiceRecord r,
9555 IntentBindRecord i, boolean rebind) {
9556 if (r.app == null || r.app.thread == null) {
9557 // If service is not currently running, can't yet bind.
9558 return false;
9559 }
9560 if ((!i.requested || rebind) && i.apps.size() > 0) {
9561 try {
9562 bumpServiceExecutingLocked(r);
9563 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9564 + ": shouldUnbind=" + i.hasBound);
9565 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9566 if (!rebind) {
9567 i.requested = true;
9568 }
9569 i.hasBound = true;
9570 i.doRebind = false;
9571 } catch (RemoteException e) {
9572 return false;
9573 }
9574 }
9575 return true;
9576 }
9577
9578 private final void requestServiceBindingsLocked(ServiceRecord r) {
9579 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9580 while (bindings.hasNext()) {
9581 IntentBindRecord i = bindings.next();
9582 if (!requestServiceBindingLocked(r, i, false)) {
9583 break;
9584 }
9585 }
9586 }
9587
9588 private final void realStartServiceLocked(ServiceRecord r,
9589 ProcessRecord app) throws RemoteException {
9590 if (app.thread == null) {
9591 throw new RemoteException();
9592 }
9593
9594 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009595 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009596
9597 app.services.add(r);
9598 bumpServiceExecutingLocked(r);
9599 updateLRUListLocked(app, true);
9600
9601 boolean created = false;
9602 try {
9603 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9604 + r.name + " " + r.intent);
9605 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9606 System.identityHashCode(r), r.shortName,
9607 r.intent.getIntent().toString(), r.app.pid);
9608 synchronized (r.stats.getBatteryStats()) {
9609 r.stats.startLaunchedLocked();
9610 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009611 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009612 app.thread.scheduleCreateService(r, r.serviceInfo);
9613 created = true;
9614 } finally {
9615 if (!created) {
9616 app.services.remove(r);
9617 scheduleServiceRestartLocked(r);
9618 }
9619 }
9620
9621 requestServiceBindingsLocked(r);
9622 sendServiceArgsLocked(r, true);
9623 }
9624
9625 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9626 r.totalRestartCount++;
9627 if (r.restartDelay == 0) {
9628 r.restartCount++;
9629 r.restartDelay = SERVICE_RESTART_DURATION;
9630 } else {
9631 // If it has been a "reasonably long time" since the service
9632 // was started, then reset our restart duration back to
9633 // the beginning, so we don't infinitely increase the duration
9634 // on a service that just occasionally gets killed (which is
9635 // a normal case, due to process being killed to reclaim memory).
9636 long now = SystemClock.uptimeMillis();
9637 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9638 r.restartCount = 1;
9639 r.restartDelay = SERVICE_RESTART_DURATION;
9640 } else {
9641 r.restartDelay *= 2;
9642 }
9643 }
9644 if (!mRestartingServices.contains(r)) {
9645 mRestartingServices.add(r);
9646 }
9647 mHandler.removeCallbacks(r.restarter);
9648 mHandler.postDelayed(r.restarter, r.restartDelay);
9649 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9650 Log.w(TAG, "Scheduling restart of crashed service "
9651 + r.shortName + " in " + r.restartDelay + "ms");
9652 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9653 r.shortName, r.restartDelay);
9654
9655 Message msg = Message.obtain();
9656 msg.what = SERVICE_ERROR_MSG;
9657 msg.obj = r;
9658 mHandler.sendMessage(msg);
9659 }
9660
9661 final void performServiceRestartLocked(ServiceRecord r) {
9662 if (!mRestartingServices.contains(r)) {
9663 return;
9664 }
9665 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9666 }
9667
9668 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9669 if (r.restartDelay == 0) {
9670 return false;
9671 }
9672 r.resetRestartCounter();
9673 mRestartingServices.remove(r);
9674 mHandler.removeCallbacks(r.restarter);
9675 return true;
9676 }
9677
9678 private final boolean bringUpServiceLocked(ServiceRecord r,
9679 int intentFlags, boolean whileRestarting) {
9680 //Log.i(TAG, "Bring up service:");
9681 //r.dump(" ");
9682
9683 if (r.app != null) {
9684 sendServiceArgsLocked(r, false);
9685 return true;
9686 }
9687
9688 if (!whileRestarting && r.restartDelay > 0) {
9689 // If waiting for a restart, then do nothing.
9690 return true;
9691 }
9692
9693 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9694 + " " + r.intent);
9695
9696 final String appName = r.processName;
9697 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9698 if (app != null && app.thread != null) {
9699 try {
9700 realStartServiceLocked(r, app);
9701 return true;
9702 } catch (RemoteException e) {
9703 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9704 }
9705
9706 // If a dead object exception was thrown -- fall through to
9707 // restart the application.
9708 }
9709
9710 if (!mPendingServices.contains(r)) {
9711 // Not running -- get it started, and enqueue this service record
9712 // to be executed when the app comes up.
9713 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9714 "service", r.name) == null) {
9715 Log.w(TAG, "Unable to launch app "
9716 + r.appInfo.packageName + "/"
9717 + r.appInfo.uid + " for service "
9718 + r.intent.getIntent() + ": process is bad");
9719 bringDownServiceLocked(r, true);
9720 return false;
9721 }
9722 mPendingServices.add(r);
9723 }
9724 return true;
9725 }
9726
9727 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9728 //Log.i(TAG, "Bring down service:");
9729 //r.dump(" ");
9730
9731 // Does it still need to run?
9732 if (!force && r.startRequested) {
9733 return;
9734 }
9735 if (r.connections.size() > 0) {
9736 if (!force) {
9737 // XXX should probably keep a count of the number of auto-create
9738 // connections directly in the service.
9739 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9740 while (it.hasNext()) {
9741 ConnectionRecord cr = it.next();
9742 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9743 return;
9744 }
9745 }
9746 }
9747
9748 // Report to all of the connections that the service is no longer
9749 // available.
9750 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9751 while (it.hasNext()) {
9752 ConnectionRecord c = it.next();
9753 try {
9754 // todo: shouldn't be a synchronous call!
9755 c.conn.connected(r.name, null);
9756 } catch (Exception e) {
9757 Log.w(TAG, "Failure disconnecting service " + r.name +
9758 " to connection " + c.conn.asBinder() +
9759 " (in " + c.binding.client.processName + ")", e);
9760 }
9761 }
9762 }
9763
9764 // Tell the service that it has been unbound.
9765 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9766 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9767 while (it.hasNext()) {
9768 IntentBindRecord ibr = it.next();
9769 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9770 + ": hasBound=" + ibr.hasBound);
9771 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9772 try {
9773 bumpServiceExecutingLocked(r);
9774 updateOomAdjLocked(r.app);
9775 ibr.hasBound = false;
9776 r.app.thread.scheduleUnbindService(r,
9777 ibr.intent.getIntent());
9778 } catch (Exception e) {
9779 Log.w(TAG, "Exception when unbinding service "
9780 + r.shortName, e);
9781 serviceDoneExecutingLocked(r, true);
9782 }
9783 }
9784 }
9785 }
9786
9787 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9788 + " " + r.intent);
9789 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9790 System.identityHashCode(r), r.shortName,
9791 (r.app != null) ? r.app.pid : -1);
9792
9793 mServices.remove(r.name);
9794 mServicesByIntent.remove(r.intent);
9795 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9796 r.totalRestartCount = 0;
9797 unscheduleServiceRestartLocked(r);
9798
9799 // Also make sure it is not on the pending list.
9800 int N = mPendingServices.size();
9801 for (int i=0; i<N; i++) {
9802 if (mPendingServices.get(i) == r) {
9803 mPendingServices.remove(i);
9804 if (DEBUG_SERVICE) Log.v(
9805 TAG, "Removed pending service: " + r.shortName);
9806 i--;
9807 N--;
9808 }
9809 }
9810
9811 if (r.app != null) {
9812 synchronized (r.stats.getBatteryStats()) {
9813 r.stats.stopLaunchedLocked();
9814 }
9815 r.app.services.remove(r);
9816 if (r.app.thread != null) {
9817 updateServiceForegroundLocked(r.app, false);
9818 try {
9819 Log.i(TAG, "Stopping service: " + r.shortName);
9820 bumpServiceExecutingLocked(r);
9821 mStoppingServices.add(r);
9822 updateOomAdjLocked(r.app);
9823 r.app.thread.scheduleStopService(r);
9824 } catch (Exception e) {
9825 Log.w(TAG, "Exception when stopping service "
9826 + r.shortName, e);
9827 serviceDoneExecutingLocked(r, true);
9828 }
9829 } else {
9830 if (DEBUG_SERVICE) Log.v(
9831 TAG, "Removed service that has no process: " + r.shortName);
9832 }
9833 } else {
9834 if (DEBUG_SERVICE) Log.v(
9835 TAG, "Removed service that is not running: " + r.shortName);
9836 }
9837 }
9838
9839 ComponentName startServiceLocked(IApplicationThread caller,
9840 Intent service, String resolvedType,
9841 int callingPid, int callingUid) {
9842 synchronized(this) {
9843 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9844 + " type=" + resolvedType + " args=" + service.getExtras());
9845
9846 if (caller != null) {
9847 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9848 if (callerApp == null) {
9849 throw new SecurityException(
9850 "Unable to find app for caller " + caller
9851 + " (pid=" + Binder.getCallingPid()
9852 + ") when starting service " + service);
9853 }
9854 }
9855
9856 ServiceLookupResult res =
9857 retrieveServiceLocked(service, resolvedType,
9858 callingPid, callingUid);
9859 if (res == null) {
9860 return null;
9861 }
9862 if (res.record == null) {
9863 return new ComponentName("!", res.permission != null
9864 ? res.permission : "private to package");
9865 }
9866 ServiceRecord r = res.record;
9867 if (unscheduleServiceRestartLocked(r)) {
9868 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9869 + r.shortName);
9870 }
9871 r.startRequested = true;
9872 r.startArgs.add(service);
9873 r.lastStartId++;
9874 if (r.lastStartId < 1) {
9875 r.lastStartId = 1;
9876 }
9877 r.lastActivity = SystemClock.uptimeMillis();
9878 synchronized (r.stats.getBatteryStats()) {
9879 r.stats.startRunningLocked();
9880 }
9881 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9882 return new ComponentName("!", "Service process is bad");
9883 }
9884 return r.name;
9885 }
9886 }
9887
9888 public ComponentName startService(IApplicationThread caller, Intent service,
9889 String resolvedType) {
9890 // Refuse possible leaked file descriptors
9891 if (service != null && service.hasFileDescriptors() == true) {
9892 throw new IllegalArgumentException("File descriptors passed in Intent");
9893 }
9894
9895 synchronized(this) {
9896 final int callingPid = Binder.getCallingPid();
9897 final int callingUid = Binder.getCallingUid();
9898 final long origId = Binder.clearCallingIdentity();
9899 ComponentName res = startServiceLocked(caller, service,
9900 resolvedType, callingPid, callingUid);
9901 Binder.restoreCallingIdentity(origId);
9902 return res;
9903 }
9904 }
9905
9906 ComponentName startServiceInPackage(int uid,
9907 Intent service, String resolvedType) {
9908 synchronized(this) {
9909 final long origId = Binder.clearCallingIdentity();
9910 ComponentName res = startServiceLocked(null, service,
9911 resolvedType, -1, uid);
9912 Binder.restoreCallingIdentity(origId);
9913 return res;
9914 }
9915 }
9916
9917 public int stopService(IApplicationThread caller, Intent service,
9918 String resolvedType) {
9919 // Refuse possible leaked file descriptors
9920 if (service != null && service.hasFileDescriptors() == true) {
9921 throw new IllegalArgumentException("File descriptors passed in Intent");
9922 }
9923
9924 synchronized(this) {
9925 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9926 + " type=" + resolvedType);
9927
9928 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9929 if (caller != null && callerApp == null) {
9930 throw new SecurityException(
9931 "Unable to find app for caller " + caller
9932 + " (pid=" + Binder.getCallingPid()
9933 + ") when stopping service " + service);
9934 }
9935
9936 // If this service is active, make sure it is stopped.
9937 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9938 if (r != null) {
9939 if (r.record != null) {
9940 synchronized (r.record.stats.getBatteryStats()) {
9941 r.record.stats.stopRunningLocked();
9942 }
9943 r.record.startRequested = false;
9944 final long origId = Binder.clearCallingIdentity();
9945 bringDownServiceLocked(r.record, false);
9946 Binder.restoreCallingIdentity(origId);
9947 return 1;
9948 }
9949 return -1;
9950 }
9951 }
9952
9953 return 0;
9954 }
9955
9956 public IBinder peekService(Intent service, String resolvedType) {
9957 // Refuse possible leaked file descriptors
9958 if (service != null && service.hasFileDescriptors() == true) {
9959 throw new IllegalArgumentException("File descriptors passed in Intent");
9960 }
9961
9962 IBinder ret = null;
9963
9964 synchronized(this) {
9965 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9966
9967 if (r != null) {
9968 // r.record is null if findServiceLocked() failed the caller permission check
9969 if (r.record == null) {
9970 throw new SecurityException(
9971 "Permission Denial: Accessing service " + r.record.name
9972 + " from pid=" + Binder.getCallingPid()
9973 + ", uid=" + Binder.getCallingUid()
9974 + " requires " + r.permission);
9975 }
9976 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9977 if (ib != null) {
9978 ret = ib.binder;
9979 }
9980 }
9981 }
9982
9983 return ret;
9984 }
9985
9986 public boolean stopServiceToken(ComponentName className, IBinder token,
9987 int startId) {
9988 synchronized(this) {
9989 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9990 + " " + token + " startId=" + startId);
9991 ServiceRecord r = findServiceLocked(className, token);
9992 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9993 synchronized (r.stats.getBatteryStats()) {
9994 r.stats.stopRunningLocked();
9995 r.startRequested = false;
9996 }
9997 final long origId = Binder.clearCallingIdentity();
9998 bringDownServiceLocked(r, false);
9999 Binder.restoreCallingIdentity(origId);
10000 return true;
10001 }
10002 }
10003 return false;
10004 }
10005
10006 public void setServiceForeground(ComponentName className, IBinder token,
10007 boolean isForeground) {
10008 synchronized(this) {
10009 ServiceRecord r = findServiceLocked(className, token);
10010 if (r != null) {
10011 if (r.isForeground != isForeground) {
10012 final long origId = Binder.clearCallingIdentity();
10013 r.isForeground = isForeground;
10014 if (r.app != null) {
10015 updateServiceForegroundLocked(r.app, true);
10016 }
10017 Binder.restoreCallingIdentity(origId);
10018 }
10019 }
10020 }
10021 }
10022
10023 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10024 boolean anyForeground = false;
10025 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10026 if (sr.isForeground) {
10027 anyForeground = true;
10028 break;
10029 }
10030 }
10031 if (anyForeground != proc.foregroundServices) {
10032 proc.foregroundServices = anyForeground;
10033 if (oomAdj) {
10034 updateOomAdjLocked();
10035 }
10036 }
10037 }
10038
10039 public int bindService(IApplicationThread caller, IBinder token,
10040 Intent service, String resolvedType,
10041 IServiceConnection connection, int flags) {
10042 // Refuse possible leaked file descriptors
10043 if (service != null && service.hasFileDescriptors() == true) {
10044 throw new IllegalArgumentException("File descriptors passed in Intent");
10045 }
10046
10047 synchronized(this) {
10048 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10049 + " type=" + resolvedType + " conn=" + connection.asBinder()
10050 + " flags=0x" + Integer.toHexString(flags));
10051 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10052 if (callerApp == null) {
10053 throw new SecurityException(
10054 "Unable to find app for caller " + caller
10055 + " (pid=" + Binder.getCallingPid()
10056 + ") when binding service " + service);
10057 }
10058
10059 HistoryRecord activity = null;
10060 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010061 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010062 if (aindex < 0) {
10063 Log.w(TAG, "Binding with unknown activity: " + token);
10064 return 0;
10065 }
10066 activity = (HistoryRecord)mHistory.get(aindex);
10067 }
10068
10069 ServiceLookupResult res =
10070 retrieveServiceLocked(service, resolvedType,
10071 Binder.getCallingPid(), Binder.getCallingUid());
10072 if (res == null) {
10073 return 0;
10074 }
10075 if (res.record == null) {
10076 return -1;
10077 }
10078 ServiceRecord s = res.record;
10079
10080 final long origId = Binder.clearCallingIdentity();
10081
10082 if (unscheduleServiceRestartLocked(s)) {
10083 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10084 + s.shortName);
10085 }
10086
10087 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10088 ConnectionRecord c = new ConnectionRecord(b, activity,
10089 connection, flags);
10090
10091 IBinder binder = connection.asBinder();
10092 s.connections.put(binder, c);
10093 b.connections.add(c);
10094 if (activity != null) {
10095 if (activity.connections == null) {
10096 activity.connections = new HashSet<ConnectionRecord>();
10097 }
10098 activity.connections.add(c);
10099 }
10100 b.client.connections.add(c);
10101 mServiceConnections.put(binder, c);
10102
10103 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10104 s.lastActivity = SystemClock.uptimeMillis();
10105 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10106 return 0;
10107 }
10108 }
10109
10110 if (s.app != null) {
10111 // This could have made the service more important.
10112 updateOomAdjLocked(s.app);
10113 }
10114
10115 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10116 + ": received=" + b.intent.received
10117 + " apps=" + b.intent.apps.size()
10118 + " doRebind=" + b.intent.doRebind);
10119
10120 if (s.app != null && b.intent.received) {
10121 // Service is already running, so we can immediately
10122 // publish the connection.
10123 try {
10124 c.conn.connected(s.name, b.intent.binder);
10125 } catch (Exception e) {
10126 Log.w(TAG, "Failure sending service " + s.shortName
10127 + " to connection " + c.conn.asBinder()
10128 + " (in " + c.binding.client.processName + ")", e);
10129 }
10130
10131 // If this is the first app connected back to this binding,
10132 // and the service had previously asked to be told when
10133 // rebound, then do so.
10134 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10135 requestServiceBindingLocked(s, b.intent, true);
10136 }
10137 } else if (!b.intent.requested) {
10138 requestServiceBindingLocked(s, b.intent, false);
10139 }
10140
10141 Binder.restoreCallingIdentity(origId);
10142 }
10143
10144 return 1;
10145 }
10146
10147 private void removeConnectionLocked(
10148 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10149 IBinder binder = c.conn.asBinder();
10150 AppBindRecord b = c.binding;
10151 ServiceRecord s = b.service;
10152 s.connections.remove(binder);
10153 b.connections.remove(c);
10154 if (c.activity != null && c.activity != skipAct) {
10155 if (c.activity.connections != null) {
10156 c.activity.connections.remove(c);
10157 }
10158 }
10159 if (b.client != skipApp) {
10160 b.client.connections.remove(c);
10161 }
10162 mServiceConnections.remove(binder);
10163
10164 if (b.connections.size() == 0) {
10165 b.intent.apps.remove(b.client);
10166 }
10167
10168 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10169 + ": shouldUnbind=" + b.intent.hasBound);
10170 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10171 && b.intent.hasBound) {
10172 try {
10173 bumpServiceExecutingLocked(s);
10174 updateOomAdjLocked(s.app);
10175 b.intent.hasBound = false;
10176 // Assume the client doesn't want to know about a rebind;
10177 // we will deal with that later if it asks for one.
10178 b.intent.doRebind = false;
10179 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10180 } catch (Exception e) {
10181 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10182 serviceDoneExecutingLocked(s, true);
10183 }
10184 }
10185
10186 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10187 bringDownServiceLocked(s, false);
10188 }
10189 }
10190
10191 public boolean unbindService(IServiceConnection connection) {
10192 synchronized (this) {
10193 IBinder binder = connection.asBinder();
10194 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10195 ConnectionRecord r = mServiceConnections.get(binder);
10196 if (r == null) {
10197 Log.w(TAG, "Unbind failed: could not find connection for "
10198 + connection.asBinder());
10199 return false;
10200 }
10201
10202 final long origId = Binder.clearCallingIdentity();
10203
10204 removeConnectionLocked(r, null, null);
10205
10206 if (r.binding.service.app != null) {
10207 // This could have made the service less important.
10208 updateOomAdjLocked(r.binding.service.app);
10209 }
10210
10211 Binder.restoreCallingIdentity(origId);
10212 }
10213
10214 return true;
10215 }
10216
10217 public void publishService(IBinder token, Intent intent, IBinder service) {
10218 // Refuse possible leaked file descriptors
10219 if (intent != null && intent.hasFileDescriptors() == true) {
10220 throw new IllegalArgumentException("File descriptors passed in Intent");
10221 }
10222
10223 synchronized(this) {
10224 if (!(token instanceof ServiceRecord)) {
10225 throw new IllegalArgumentException("Invalid service token");
10226 }
10227 ServiceRecord r = (ServiceRecord)token;
10228
10229 final long origId = Binder.clearCallingIdentity();
10230
10231 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10232 + " " + intent + ": " + service);
10233 if (r != null) {
10234 Intent.FilterComparison filter
10235 = new Intent.FilterComparison(intent);
10236 IntentBindRecord b = r.bindings.get(filter);
10237 if (b != null && !b.received) {
10238 b.binder = service;
10239 b.requested = true;
10240 b.received = true;
10241 if (r.connections.size() > 0) {
10242 Iterator<ConnectionRecord> it
10243 = r.connections.values().iterator();
10244 while (it.hasNext()) {
10245 ConnectionRecord c = it.next();
10246 if (!filter.equals(c.binding.intent.intent)) {
10247 if (DEBUG_SERVICE) Log.v(
10248 TAG, "Not publishing to: " + c);
10249 if (DEBUG_SERVICE) Log.v(
10250 TAG, "Bound intent: " + c.binding.intent.intent);
10251 if (DEBUG_SERVICE) Log.v(
10252 TAG, "Published intent: " + intent);
10253 continue;
10254 }
10255 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10256 try {
10257 c.conn.connected(r.name, service);
10258 } catch (Exception e) {
10259 Log.w(TAG, "Failure sending service " + r.name +
10260 " to connection " + c.conn.asBinder() +
10261 " (in " + c.binding.client.processName + ")", e);
10262 }
10263 }
10264 }
10265 }
10266
10267 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10268
10269 Binder.restoreCallingIdentity(origId);
10270 }
10271 }
10272 }
10273
10274 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10275 // Refuse possible leaked file descriptors
10276 if (intent != null && intent.hasFileDescriptors() == true) {
10277 throw new IllegalArgumentException("File descriptors passed in Intent");
10278 }
10279
10280 synchronized(this) {
10281 if (!(token instanceof ServiceRecord)) {
10282 throw new IllegalArgumentException("Invalid service token");
10283 }
10284 ServiceRecord r = (ServiceRecord)token;
10285
10286 final long origId = Binder.clearCallingIdentity();
10287
10288 if (r != null) {
10289 Intent.FilterComparison filter
10290 = new Intent.FilterComparison(intent);
10291 IntentBindRecord b = r.bindings.get(filter);
10292 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10293 + " at " + b + ": apps="
10294 + (b != null ? b.apps.size() : 0));
10295 if (b != null) {
10296 if (b.apps.size() > 0) {
10297 // Applications have already bound since the last
10298 // unbind, so just rebind right here.
10299 requestServiceBindingLocked(r, b, true);
10300 } else {
10301 // Note to tell the service the next time there is
10302 // a new client.
10303 b.doRebind = true;
10304 }
10305 }
10306
10307 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10308
10309 Binder.restoreCallingIdentity(origId);
10310 }
10311 }
10312 }
10313
10314 public void serviceDoneExecuting(IBinder token) {
10315 synchronized(this) {
10316 if (!(token instanceof ServiceRecord)) {
10317 throw new IllegalArgumentException("Invalid service token");
10318 }
10319 ServiceRecord r = (ServiceRecord)token;
10320 boolean inStopping = mStoppingServices.contains(token);
10321 if (r != null) {
10322 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10323 + ": nesting=" + r.executeNesting
10324 + ", inStopping=" + inStopping);
10325 if (r != token) {
10326 Log.w(TAG, "Done executing service " + r.name
10327 + " with incorrect token: given " + token
10328 + ", expected " + r);
10329 return;
10330 }
10331
10332 final long origId = Binder.clearCallingIdentity();
10333 serviceDoneExecutingLocked(r, inStopping);
10334 Binder.restoreCallingIdentity(origId);
10335 } else {
10336 Log.w(TAG, "Done executing unknown service " + r.name
10337 + " with token " + token);
10338 }
10339 }
10340 }
10341
10342 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10343 r.executeNesting--;
10344 if (r.executeNesting <= 0 && r.app != null) {
10345 r.app.executingServices.remove(r);
10346 if (r.app.executingServices.size() == 0) {
10347 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10348 }
10349 if (inStopping) {
10350 mStoppingServices.remove(r);
10351 }
10352 updateOomAdjLocked(r.app);
10353 }
10354 }
10355
10356 void serviceTimeout(ProcessRecord proc) {
10357 synchronized(this) {
10358 if (proc.executingServices.size() == 0 || proc.thread == null) {
10359 return;
10360 }
10361 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10362 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10363 ServiceRecord timeout = null;
10364 long nextTime = 0;
10365 while (it.hasNext()) {
10366 ServiceRecord sr = it.next();
10367 if (sr.executingStart < maxTime) {
10368 timeout = sr;
10369 break;
10370 }
10371 if (sr.executingStart > nextTime) {
10372 nextTime = sr.executingStart;
10373 }
10374 }
10375 if (timeout != null && mLRUProcesses.contains(proc)) {
10376 Log.w(TAG, "Timeout executing service: " + timeout);
10377 appNotRespondingLocked(proc, null, "Executing service "
10378 + timeout.name);
10379 } else {
10380 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10381 msg.obj = proc;
10382 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10383 }
10384 }
10385 }
10386
10387 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010388 // BACKUP AND RESTORE
10389 // =========================================================
10390
10391 // Cause the target app to be launched if necessary and its backup agent
10392 // instantiated. The backup agent will invoke backupAgentCreated() on the
10393 // activity manager to announce its creation.
10394 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10395 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10396 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10397
10398 synchronized(this) {
10399 // !!! TODO: currently no check here that we're already bound
10400 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10401 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10402 synchronized (stats) {
10403 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10404 }
10405
10406 BackupRecord r = new BackupRecord(ss, app, backupMode);
10407 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10408 // startProcessLocked() returns existing proc's record if it's already running
10409 ProcessRecord proc = startProcessLocked(app.processName, app,
10410 false, 0, "backup", hostingName);
10411 if (proc == null) {
10412 Log.e(TAG, "Unable to start backup agent process " + r);
10413 return false;
10414 }
10415
10416 r.app = proc;
10417 mBackupTarget = r;
10418 mBackupAppName = app.packageName;
10419
Christopher Tate6fa95972009-06-05 18:43:55 -070010420 // Try not to kill the process during backup
10421 updateOomAdjLocked(proc);
10422
Christopher Tate181fafa2009-05-14 11:12:14 -070010423 // If the process is already attached, schedule the creation of the backup agent now.
10424 // If it is not yet live, this will be done when it attaches to the framework.
10425 if (proc.thread != null) {
10426 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10427 try {
10428 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10429 } catch (RemoteException e) {
10430 // !!! TODO: notify the backup manager that we crashed, or rely on
10431 // death notices, or...?
10432 }
10433 } else {
10434 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10435 }
10436 // Invariants: at this point, the target app process exists and the application
10437 // is either already running or in the process of coming up. mBackupTarget and
10438 // mBackupAppName describe the app, so that when it binds back to the AM we
10439 // know that it's scheduled for a backup-agent operation.
10440 }
10441
10442 return true;
10443 }
10444
10445 // A backup agent has just come up
10446 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10447 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10448 + " = " + agent);
10449
10450 synchronized(this) {
10451 if (!agentPackageName.equals(mBackupAppName)) {
10452 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10453 return;
10454 }
10455
Christopher Tate043dadc2009-06-02 16:11:00 -070010456 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010457 try {
10458 IBackupManager bm = IBackupManager.Stub.asInterface(
10459 ServiceManager.getService(Context.BACKUP_SERVICE));
10460 bm.agentConnected(agentPackageName, agent);
10461 } catch (RemoteException e) {
10462 // can't happen; the backup manager service is local
10463 } catch (Exception e) {
10464 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10465 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010466 } finally {
10467 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010468 }
10469 }
10470 }
10471
10472 // done with this agent
10473 public void unbindBackupAgent(ApplicationInfo appInfo) {
10474 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010475 if (appInfo == null) {
10476 Log.w(TAG, "unbind backup agent for null app");
10477 return;
10478 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010479
10480 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010481 if (mBackupAppName == null) {
10482 Log.w(TAG, "Unbinding backup agent with no active backup");
10483 return;
10484 }
10485
Christopher Tate181fafa2009-05-14 11:12:14 -070010486 if (!mBackupAppName.equals(appInfo.packageName)) {
10487 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10488 return;
10489 }
10490
Christopher Tate6fa95972009-06-05 18:43:55 -070010491 ProcessRecord proc = mBackupTarget.app;
10492 mBackupTarget = null;
10493 mBackupAppName = null;
10494
10495 // Not backing this app up any more; reset its OOM adjustment
10496 updateOomAdjLocked(proc);
10497
Christopher Tatec7b31e32009-06-10 15:49:30 -070010498 // If the app crashed during backup, 'thread' will be null here
10499 if (proc.thread != null) {
10500 try {
10501 proc.thread.scheduleDestroyBackupAgent(appInfo);
10502 } catch (Exception e) {
10503 Log.e(TAG, "Exception when unbinding backup agent:");
10504 e.printStackTrace();
10505 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010506 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010507 }
10508 }
10509 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010510 // BROADCASTS
10511 // =========================================================
10512
10513 private final List getStickies(String action, IntentFilter filter,
10514 List cur) {
10515 final ContentResolver resolver = mContext.getContentResolver();
10516 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10517 if (list == null) {
10518 return cur;
10519 }
10520 int N = list.size();
10521 for (int i=0; i<N; i++) {
10522 Intent intent = list.get(i);
10523 if (filter.match(resolver, intent, true, TAG) >= 0) {
10524 if (cur == null) {
10525 cur = new ArrayList<Intent>();
10526 }
10527 cur.add(intent);
10528 }
10529 }
10530 return cur;
10531 }
10532
10533 private final void scheduleBroadcastsLocked() {
10534 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10535 + mBroadcastsScheduled);
10536
10537 if (mBroadcastsScheduled) {
10538 return;
10539 }
10540 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10541 mBroadcastsScheduled = true;
10542 }
10543
10544 public Intent registerReceiver(IApplicationThread caller,
10545 IIntentReceiver receiver, IntentFilter filter, String permission) {
10546 synchronized(this) {
10547 ProcessRecord callerApp = null;
10548 if (caller != null) {
10549 callerApp = getRecordForAppLocked(caller);
10550 if (callerApp == null) {
10551 throw new SecurityException(
10552 "Unable to find app for caller " + caller
10553 + " (pid=" + Binder.getCallingPid()
10554 + ") when registering receiver " + receiver);
10555 }
10556 }
10557
10558 List allSticky = null;
10559
10560 // Look for any matching sticky broadcasts...
10561 Iterator actions = filter.actionsIterator();
10562 if (actions != null) {
10563 while (actions.hasNext()) {
10564 String action = (String)actions.next();
10565 allSticky = getStickies(action, filter, allSticky);
10566 }
10567 } else {
10568 allSticky = getStickies(null, filter, allSticky);
10569 }
10570
10571 // The first sticky in the list is returned directly back to
10572 // the client.
10573 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10574
10575 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10576 + ": " + sticky);
10577
10578 if (receiver == null) {
10579 return sticky;
10580 }
10581
10582 ReceiverList rl
10583 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10584 if (rl == null) {
10585 rl = new ReceiverList(this, callerApp,
10586 Binder.getCallingPid(),
10587 Binder.getCallingUid(), receiver);
10588 if (rl.app != null) {
10589 rl.app.receivers.add(rl);
10590 } else {
10591 try {
10592 receiver.asBinder().linkToDeath(rl, 0);
10593 } catch (RemoteException e) {
10594 return sticky;
10595 }
10596 rl.linkedToDeath = true;
10597 }
10598 mRegisteredReceivers.put(receiver.asBinder(), rl);
10599 }
10600 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10601 rl.add(bf);
10602 if (!bf.debugCheck()) {
10603 Log.w(TAG, "==> For Dynamic broadast");
10604 }
10605 mReceiverResolver.addFilter(bf);
10606
10607 // Enqueue broadcasts for all existing stickies that match
10608 // this filter.
10609 if (allSticky != null) {
10610 ArrayList receivers = new ArrayList();
10611 receivers.add(bf);
10612
10613 int N = allSticky.size();
10614 for (int i=0; i<N; i++) {
10615 Intent intent = (Intent)allSticky.get(i);
10616 BroadcastRecord r = new BroadcastRecord(intent, null,
10617 null, -1, -1, null, receivers, null, 0, null, null,
10618 false);
10619 if (mParallelBroadcasts.size() == 0) {
10620 scheduleBroadcastsLocked();
10621 }
10622 mParallelBroadcasts.add(r);
10623 }
10624 }
10625
10626 return sticky;
10627 }
10628 }
10629
10630 public void unregisterReceiver(IIntentReceiver receiver) {
10631 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10632
10633 boolean doNext = false;
10634
10635 synchronized(this) {
10636 ReceiverList rl
10637 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10638 if (rl != null) {
10639 if (rl.curBroadcast != null) {
10640 BroadcastRecord r = rl.curBroadcast;
10641 doNext = finishReceiverLocked(
10642 receiver.asBinder(), r.resultCode, r.resultData,
10643 r.resultExtras, r.resultAbort, true);
10644 }
10645
10646 if (rl.app != null) {
10647 rl.app.receivers.remove(rl);
10648 }
10649 removeReceiverLocked(rl);
10650 if (rl.linkedToDeath) {
10651 rl.linkedToDeath = false;
10652 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10653 }
10654 }
10655 }
10656
10657 if (!doNext) {
10658 return;
10659 }
10660
10661 final long origId = Binder.clearCallingIdentity();
10662 processNextBroadcast(false);
10663 trimApplications();
10664 Binder.restoreCallingIdentity(origId);
10665 }
10666
10667 void removeReceiverLocked(ReceiverList rl) {
10668 mRegisteredReceivers.remove(rl.receiver.asBinder());
10669 int N = rl.size();
10670 for (int i=0; i<N; i++) {
10671 mReceiverResolver.removeFilter(rl.get(i));
10672 }
10673 }
10674
10675 private final int broadcastIntentLocked(ProcessRecord callerApp,
10676 String callerPackage, Intent intent, String resolvedType,
10677 IIntentReceiver resultTo, int resultCode, String resultData,
10678 Bundle map, String requiredPermission,
10679 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10680 intent = new Intent(intent);
10681
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010682 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010683 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10684 + " ordered=" + ordered);
10685 if ((resultTo != null) && !ordered) {
10686 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10687 }
10688
10689 // Handle special intents: if this broadcast is from the package
10690 // manager about a package being removed, we need to remove all of
10691 // its activities from the history stack.
10692 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10693 intent.getAction());
10694 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10695 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10696 || uidRemoved) {
10697 if (checkComponentPermission(
10698 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10699 callingPid, callingUid, -1)
10700 == PackageManager.PERMISSION_GRANTED) {
10701 if (uidRemoved) {
10702 final Bundle intentExtras = intent.getExtras();
10703 final int uid = intentExtras != null
10704 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10705 if (uid >= 0) {
10706 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10707 synchronized (bs) {
10708 bs.removeUidStatsLocked(uid);
10709 }
10710 }
10711 } else {
10712 Uri data = intent.getData();
10713 String ssp;
10714 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10715 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10716 uninstallPackageLocked(ssp,
10717 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10718 }
10719 }
10720 }
10721 } else {
10722 String msg = "Permission Denial: " + intent.getAction()
10723 + " broadcast from " + callerPackage + " (pid=" + callingPid
10724 + ", uid=" + callingUid + ")"
10725 + " requires "
10726 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10727 Log.w(TAG, msg);
10728 throw new SecurityException(msg);
10729 }
10730 }
10731
10732 /*
10733 * If this is the time zone changed action, queue up a message that will reset the timezone
10734 * of all currently running processes. This message will get queued up before the broadcast
10735 * happens.
10736 */
10737 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10738 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10739 }
10740
10741 // Add to the sticky list if requested.
10742 if (sticky) {
10743 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10744 callingPid, callingUid)
10745 != PackageManager.PERMISSION_GRANTED) {
10746 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10747 + callingPid + ", uid=" + callingUid
10748 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10749 Log.w(TAG, msg);
10750 throw new SecurityException(msg);
10751 }
10752 if (requiredPermission != null) {
10753 Log.w(TAG, "Can't broadcast sticky intent " + intent
10754 + " and enforce permission " + requiredPermission);
10755 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10756 }
10757 if (intent.getComponent() != null) {
10758 throw new SecurityException(
10759 "Sticky broadcasts can't target a specific component");
10760 }
10761 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10762 if (list == null) {
10763 list = new ArrayList<Intent>();
10764 mStickyBroadcasts.put(intent.getAction(), list);
10765 }
10766 int N = list.size();
10767 int i;
10768 for (i=0; i<N; i++) {
10769 if (intent.filterEquals(list.get(i))) {
10770 // This sticky already exists, replace it.
10771 list.set(i, new Intent(intent));
10772 break;
10773 }
10774 }
10775 if (i >= N) {
10776 list.add(new Intent(intent));
10777 }
10778 }
10779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010780 // Figure out who all will receive this broadcast.
10781 List receivers = null;
10782 List<BroadcastFilter> registeredReceivers = null;
10783 try {
10784 if (intent.getComponent() != null) {
10785 // Broadcast is going to one specific receiver class...
10786 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010787 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010788 if (ai != null) {
10789 receivers = new ArrayList();
10790 ResolveInfo ri = new ResolveInfo();
10791 ri.activityInfo = ai;
10792 receivers.add(ri);
10793 }
10794 } else {
10795 // Need to resolve the intent to interested receivers...
10796 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10797 == 0) {
10798 receivers =
10799 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010800 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010801 }
Mihai Preda074edef2009-05-18 17:13:31 +020010802 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010803 }
10804 } catch (RemoteException ex) {
10805 // pm is in same process, this will never happen.
10806 }
10807
10808 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10809 if (!ordered && NR > 0) {
10810 // If we are not serializing this broadcast, then send the
10811 // registered receivers separately so they don't wait for the
10812 // components to be launched.
10813 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10814 callerPackage, callingPid, callingUid, requiredPermission,
10815 registeredReceivers, resultTo, resultCode, resultData, map,
10816 ordered);
10817 if (DEBUG_BROADCAST) Log.v(
10818 TAG, "Enqueueing parallel broadcast " + r
10819 + ": prev had " + mParallelBroadcasts.size());
10820 mParallelBroadcasts.add(r);
10821 scheduleBroadcastsLocked();
10822 registeredReceivers = null;
10823 NR = 0;
10824 }
10825
10826 // Merge into one list.
10827 int ir = 0;
10828 if (receivers != null) {
10829 // A special case for PACKAGE_ADDED: do not allow the package
10830 // being added to see this broadcast. This prevents them from
10831 // using this as a back door to get run as soon as they are
10832 // installed. Maybe in the future we want to have a special install
10833 // broadcast or such for apps, but we'd like to deliberately make
10834 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010835 boolean skip = false;
10836 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010837 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010838 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10839 skip = true;
10840 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10841 skip = true;
10842 }
10843 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010844 ? intent.getData().getSchemeSpecificPart()
10845 : null;
10846 if (skipPackage != null && receivers != null) {
10847 int NT = receivers.size();
10848 for (int it=0; it<NT; it++) {
10849 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10850 if (curt.activityInfo.packageName.equals(skipPackage)) {
10851 receivers.remove(it);
10852 it--;
10853 NT--;
10854 }
10855 }
10856 }
10857
10858 int NT = receivers != null ? receivers.size() : 0;
10859 int it = 0;
10860 ResolveInfo curt = null;
10861 BroadcastFilter curr = null;
10862 while (it < NT && ir < NR) {
10863 if (curt == null) {
10864 curt = (ResolveInfo)receivers.get(it);
10865 }
10866 if (curr == null) {
10867 curr = registeredReceivers.get(ir);
10868 }
10869 if (curr.getPriority() >= curt.priority) {
10870 // Insert this broadcast record into the final list.
10871 receivers.add(it, curr);
10872 ir++;
10873 curr = null;
10874 it++;
10875 NT++;
10876 } else {
10877 // Skip to the next ResolveInfo in the final list.
10878 it++;
10879 curt = null;
10880 }
10881 }
10882 }
10883 while (ir < NR) {
10884 if (receivers == null) {
10885 receivers = new ArrayList();
10886 }
10887 receivers.add(registeredReceivers.get(ir));
10888 ir++;
10889 }
10890
10891 if ((receivers != null && receivers.size() > 0)
10892 || resultTo != null) {
10893 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10894 callerPackage, callingPid, callingUid, requiredPermission,
10895 receivers, resultTo, resultCode, resultData, map, ordered);
10896 if (DEBUG_BROADCAST) Log.v(
10897 TAG, "Enqueueing ordered broadcast " + r
10898 + ": prev had " + mOrderedBroadcasts.size());
10899 if (DEBUG_BROADCAST) {
10900 int seq = r.intent.getIntExtra("seq", -1);
10901 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10902 }
10903 mOrderedBroadcasts.add(r);
10904 scheduleBroadcastsLocked();
10905 }
10906
10907 return BROADCAST_SUCCESS;
10908 }
10909
10910 public final int broadcastIntent(IApplicationThread caller,
10911 Intent intent, String resolvedType, IIntentReceiver resultTo,
10912 int resultCode, String resultData, Bundle map,
10913 String requiredPermission, boolean serialized, boolean sticky) {
10914 // Refuse possible leaked file descriptors
10915 if (intent != null && intent.hasFileDescriptors() == true) {
10916 throw new IllegalArgumentException("File descriptors passed in Intent");
10917 }
10918
10919 synchronized(this) {
10920 if (!mSystemReady) {
10921 // if the caller really truly claims to know what they're doing, go
10922 // ahead and allow the broadcast without launching any receivers
10923 int flags = intent.getFlags();
10924 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10925 intent = new Intent(intent);
10926 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10927 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10928 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10929 + " before boot completion");
10930 throw new IllegalStateException("Cannot broadcast before boot completed");
10931 }
10932 }
10933
10934 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10935 final int callingPid = Binder.getCallingPid();
10936 final int callingUid = Binder.getCallingUid();
10937 final long origId = Binder.clearCallingIdentity();
10938 int res = broadcastIntentLocked(callerApp,
10939 callerApp != null ? callerApp.info.packageName : null,
10940 intent, resolvedType, resultTo,
10941 resultCode, resultData, map, requiredPermission, serialized,
10942 sticky, callingPid, callingUid);
10943 Binder.restoreCallingIdentity(origId);
10944 return res;
10945 }
10946 }
10947
10948 int broadcastIntentInPackage(String packageName, int uid,
10949 Intent intent, String resolvedType, IIntentReceiver resultTo,
10950 int resultCode, String resultData, Bundle map,
10951 String requiredPermission, boolean serialized, boolean sticky) {
10952 synchronized(this) {
10953 final long origId = Binder.clearCallingIdentity();
10954 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10955 resultTo, resultCode, resultData, map, requiredPermission,
10956 serialized, sticky, -1, uid);
10957 Binder.restoreCallingIdentity(origId);
10958 return res;
10959 }
10960 }
10961
10962 public final void unbroadcastIntent(IApplicationThread caller,
10963 Intent intent) {
10964 // Refuse possible leaked file descriptors
10965 if (intent != null && intent.hasFileDescriptors() == true) {
10966 throw new IllegalArgumentException("File descriptors passed in Intent");
10967 }
10968
10969 synchronized(this) {
10970 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10971 != PackageManager.PERMISSION_GRANTED) {
10972 String msg = "Permission Denial: unbroadcastIntent() from pid="
10973 + Binder.getCallingPid()
10974 + ", uid=" + Binder.getCallingUid()
10975 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10976 Log.w(TAG, msg);
10977 throw new SecurityException(msg);
10978 }
10979 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10980 if (list != null) {
10981 int N = list.size();
10982 int i;
10983 for (i=0; i<N; i++) {
10984 if (intent.filterEquals(list.get(i))) {
10985 list.remove(i);
10986 break;
10987 }
10988 }
10989 }
10990 }
10991 }
10992
10993 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10994 String resultData, Bundle resultExtras, boolean resultAbort,
10995 boolean explicit) {
10996 if (mOrderedBroadcasts.size() == 0) {
10997 if (explicit) {
10998 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10999 }
11000 return false;
11001 }
11002 BroadcastRecord r = mOrderedBroadcasts.get(0);
11003 if (r.receiver == null) {
11004 if (explicit) {
11005 Log.w(TAG, "finishReceiver called but none active");
11006 }
11007 return false;
11008 }
11009 if (r.receiver != receiver) {
11010 Log.w(TAG, "finishReceiver called but active receiver is different");
11011 return false;
11012 }
11013 int state = r.state;
11014 r.state = r.IDLE;
11015 if (state == r.IDLE) {
11016 if (explicit) {
11017 Log.w(TAG, "finishReceiver called but state is IDLE");
11018 }
11019 }
11020 r.receiver = null;
11021 r.intent.setComponent(null);
11022 if (r.curApp != null) {
11023 r.curApp.curReceiver = null;
11024 }
11025 if (r.curFilter != null) {
11026 r.curFilter.receiverList.curBroadcast = null;
11027 }
11028 r.curFilter = null;
11029 r.curApp = null;
11030 r.curComponent = null;
11031 r.curReceiver = null;
11032 mPendingBroadcast = null;
11033
11034 r.resultCode = resultCode;
11035 r.resultData = resultData;
11036 r.resultExtras = resultExtras;
11037 r.resultAbort = resultAbort;
11038
11039 // We will process the next receiver right now if this is finishing
11040 // an app receiver (which is always asynchronous) or after we have
11041 // come back from calling a receiver.
11042 return state == BroadcastRecord.APP_RECEIVE
11043 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11044 }
11045
11046 public void finishReceiver(IBinder who, int resultCode, String resultData,
11047 Bundle resultExtras, boolean resultAbort) {
11048 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11049
11050 // Refuse possible leaked file descriptors
11051 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11052 throw new IllegalArgumentException("File descriptors passed in Bundle");
11053 }
11054
11055 boolean doNext;
11056
11057 final long origId = Binder.clearCallingIdentity();
11058
11059 synchronized(this) {
11060 doNext = finishReceiverLocked(
11061 who, resultCode, resultData, resultExtras, resultAbort, true);
11062 }
11063
11064 if (doNext) {
11065 processNextBroadcast(false);
11066 }
11067 trimApplications();
11068
11069 Binder.restoreCallingIdentity(origId);
11070 }
11071
11072 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11073 if (r.nextReceiver > 0) {
11074 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11075 if (curReceiver instanceof BroadcastFilter) {
11076 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11077 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11078 System.identityHashCode(r),
11079 r.intent.getAction(),
11080 r.nextReceiver - 1,
11081 System.identityHashCode(bf));
11082 } else {
11083 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11084 System.identityHashCode(r),
11085 r.intent.getAction(),
11086 r.nextReceiver - 1,
11087 ((ResolveInfo)curReceiver).toString());
11088 }
11089 } else {
11090 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11091 + r);
11092 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11093 System.identityHashCode(r),
11094 r.intent.getAction(),
11095 r.nextReceiver,
11096 "NONE");
11097 }
11098 }
11099
11100 private final void broadcastTimeout() {
11101 synchronized (this) {
11102 if (mOrderedBroadcasts.size() == 0) {
11103 return;
11104 }
11105 long now = SystemClock.uptimeMillis();
11106 BroadcastRecord r = mOrderedBroadcasts.get(0);
11107 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11108 if (DEBUG_BROADCAST) Log.v(TAG,
11109 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11110 + (r.startTime + BROADCAST_TIMEOUT));
11111 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11112 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11113 return;
11114 }
11115
11116 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11117 r.startTime = now;
11118 r.anrCount++;
11119
11120 // Current receiver has passed its expiration date.
11121 if (r.nextReceiver <= 0) {
11122 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11123 return;
11124 }
11125
11126 ProcessRecord app = null;
11127
11128 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11129 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11130 logBroadcastReceiverDiscard(r);
11131 if (curReceiver instanceof BroadcastFilter) {
11132 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11133 if (bf.receiverList.pid != 0
11134 && bf.receiverList.pid != MY_PID) {
11135 synchronized (this.mPidsSelfLocked) {
11136 app = this.mPidsSelfLocked.get(
11137 bf.receiverList.pid);
11138 }
11139 }
11140 } else {
11141 app = r.curApp;
11142 }
11143
11144 if (app != null) {
11145 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11146 }
11147
11148 if (mPendingBroadcast == r) {
11149 mPendingBroadcast = null;
11150 }
11151
11152 // Move on to the next receiver.
11153 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11154 r.resultExtras, r.resultAbort, true);
11155 scheduleBroadcastsLocked();
11156 }
11157 }
11158
11159 private final void processCurBroadcastLocked(BroadcastRecord r,
11160 ProcessRecord app) throws RemoteException {
11161 if (app.thread == null) {
11162 throw new RemoteException();
11163 }
11164 r.receiver = app.thread.asBinder();
11165 r.curApp = app;
11166 app.curReceiver = r;
11167 updateLRUListLocked(app, true);
11168
11169 // Tell the application to launch this receiver.
11170 r.intent.setComponent(r.curComponent);
11171
11172 boolean started = false;
11173 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011174 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011175 "Delivering to component " + r.curComponent
11176 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011177 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011178 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11179 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11180 started = true;
11181 } finally {
11182 if (!started) {
11183 r.receiver = null;
11184 r.curApp = null;
11185 app.curReceiver = null;
11186 }
11187 }
11188
11189 }
11190
11191 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11192 Intent intent, int resultCode, String data,
11193 Bundle extras, boolean ordered) throws RemoteException {
11194 if (app != null && app.thread != null) {
11195 // If we have an app thread, do the call through that so it is
11196 // correctly ordered with other one-way calls.
11197 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11198 data, extras, ordered);
11199 } else {
11200 receiver.performReceive(intent, resultCode, data, extras, ordered);
11201 }
11202 }
11203
11204 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11205 BroadcastFilter filter, boolean ordered) {
11206 boolean skip = false;
11207 if (filter.requiredPermission != null) {
11208 int perm = checkComponentPermission(filter.requiredPermission,
11209 r.callingPid, r.callingUid, -1);
11210 if (perm != PackageManager.PERMISSION_GRANTED) {
11211 Log.w(TAG, "Permission Denial: broadcasting "
11212 + r.intent.toString()
11213 + " from " + r.callerPackage + " (pid="
11214 + r.callingPid + ", uid=" + r.callingUid + ")"
11215 + " requires " + filter.requiredPermission
11216 + " due to registered receiver " + filter);
11217 skip = true;
11218 }
11219 }
11220 if (r.requiredPermission != null) {
11221 int perm = checkComponentPermission(r.requiredPermission,
11222 filter.receiverList.pid, filter.receiverList.uid, -1);
11223 if (perm != PackageManager.PERMISSION_GRANTED) {
11224 Log.w(TAG, "Permission Denial: receiving "
11225 + r.intent.toString()
11226 + " to " + filter.receiverList.app
11227 + " (pid=" + filter.receiverList.pid
11228 + ", uid=" + filter.receiverList.uid + ")"
11229 + " requires " + r.requiredPermission
11230 + " due to sender " + r.callerPackage
11231 + " (uid " + r.callingUid + ")");
11232 skip = true;
11233 }
11234 }
11235
11236 if (!skip) {
11237 // If this is not being sent as an ordered broadcast, then we
11238 // don't want to touch the fields that keep track of the current
11239 // state of ordered broadcasts.
11240 if (ordered) {
11241 r.receiver = filter.receiverList.receiver.asBinder();
11242 r.curFilter = filter;
11243 filter.receiverList.curBroadcast = r;
11244 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011245 if (filter.receiverList.app != null) {
11246 // Bump hosting application to no longer be in background
11247 // scheduling class. Note that we can't do that if there
11248 // isn't an app... but we can only be in that case for
11249 // things that directly call the IActivityManager API, which
11250 // are already core system stuff so don't matter for this.
11251 r.curApp = filter.receiverList.app;
11252 filter.receiverList.app.curReceiver = r;
11253 updateOomAdjLocked();
11254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011255 }
11256 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011257 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011258 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011259 Log.i(TAG, "Delivering to " + filter.receiverList.app
11260 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011261 }
11262 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11263 new Intent(r.intent), r.resultCode,
11264 r.resultData, r.resultExtras, r.ordered);
11265 if (ordered) {
11266 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11267 }
11268 } catch (RemoteException e) {
11269 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11270 if (ordered) {
11271 r.receiver = null;
11272 r.curFilter = null;
11273 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011274 if (filter.receiverList.app != null) {
11275 filter.receiverList.app.curReceiver = null;
11276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011277 }
11278 }
11279 }
11280 }
11281
11282 private final void processNextBroadcast(boolean fromMsg) {
11283 synchronized(this) {
11284 BroadcastRecord r;
11285
11286 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11287 + mParallelBroadcasts.size() + " broadcasts, "
11288 + mOrderedBroadcasts.size() + " serialized broadcasts");
11289
11290 updateCpuStats();
11291
11292 if (fromMsg) {
11293 mBroadcastsScheduled = false;
11294 }
11295
11296 // First, deliver any non-serialized broadcasts right away.
11297 while (mParallelBroadcasts.size() > 0) {
11298 r = mParallelBroadcasts.remove(0);
11299 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011300 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11301 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011302 for (int i=0; i<N; i++) {
11303 Object target = r.receivers.get(i);
11304 if (DEBUG_BROADCAST) Log.v(TAG,
11305 "Delivering non-serialized to registered "
11306 + target + ": " + r);
11307 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11308 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011309 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11310 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011311 }
11312
11313 // Now take care of the next serialized one...
11314
11315 // If we are waiting for a process to come up to handle the next
11316 // broadcast, then do nothing at this point. Just in case, we
11317 // check that the process we're waiting for still exists.
11318 if (mPendingBroadcast != null) {
11319 Log.i(TAG, "processNextBroadcast: waiting for "
11320 + mPendingBroadcast.curApp);
11321
11322 boolean isDead;
11323 synchronized (mPidsSelfLocked) {
11324 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11325 }
11326 if (!isDead) {
11327 // It's still alive, so keep waiting
11328 return;
11329 } else {
11330 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11331 + " died before responding to broadcast");
11332 mPendingBroadcast = null;
11333 }
11334 }
11335
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011336 boolean looped = false;
11337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011338 do {
11339 if (mOrderedBroadcasts.size() == 0) {
11340 // No more broadcasts pending, so all done!
11341 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011342 if (looped) {
11343 // If we had finished the last ordered broadcast, then
11344 // make sure all processes have correct oom and sched
11345 // adjustments.
11346 updateOomAdjLocked();
11347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011348 return;
11349 }
11350 r = mOrderedBroadcasts.get(0);
11351 boolean forceReceive = false;
11352
11353 // Ensure that even if something goes awry with the timeout
11354 // detection, we catch "hung" broadcasts here, discard them,
11355 // and continue to make progress.
11356 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11357 long now = SystemClock.uptimeMillis();
11358 if (r.dispatchTime > 0) {
11359 if ((numReceivers > 0) &&
11360 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11361 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11362 + " now=" + now
11363 + " dispatchTime=" + r.dispatchTime
11364 + " startTime=" + r.startTime
11365 + " intent=" + r.intent
11366 + " numReceivers=" + numReceivers
11367 + " nextReceiver=" + r.nextReceiver
11368 + " state=" + r.state);
11369 broadcastTimeout(); // forcibly finish this broadcast
11370 forceReceive = true;
11371 r.state = BroadcastRecord.IDLE;
11372 }
11373 }
11374
11375 if (r.state != BroadcastRecord.IDLE) {
11376 if (DEBUG_BROADCAST) Log.d(TAG,
11377 "processNextBroadcast() called when not idle (state="
11378 + r.state + ")");
11379 return;
11380 }
11381
11382 if (r.receivers == null || r.nextReceiver >= numReceivers
11383 || r.resultAbort || forceReceive) {
11384 // No more receivers for this broadcast! Send the final
11385 // result if requested...
11386 if (r.resultTo != null) {
11387 try {
11388 if (DEBUG_BROADCAST) {
11389 int seq = r.intent.getIntExtra("seq", -1);
11390 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11391 + " seq=" + seq + " app=" + r.callerApp);
11392 }
11393 performReceive(r.callerApp, r.resultTo,
11394 new Intent(r.intent), r.resultCode,
11395 r.resultData, r.resultExtras, false);
11396 } catch (RemoteException e) {
11397 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11398 }
11399 }
11400
11401 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11402 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11403
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011404 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11405 + r);
11406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011407 // ... and on to the next...
11408 mOrderedBroadcasts.remove(0);
11409 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011410 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011411 continue;
11412 }
11413 } while (r == null);
11414
11415 // Get the next receiver...
11416 int recIdx = r.nextReceiver++;
11417
11418 // Keep track of when this receiver started, and make sure there
11419 // is a timeout message pending to kill it if need be.
11420 r.startTime = SystemClock.uptimeMillis();
11421 if (recIdx == 0) {
11422 r.dispatchTime = r.startTime;
11423
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011424 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11425 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011426 if (DEBUG_BROADCAST) Log.v(TAG,
11427 "Submitting BROADCAST_TIMEOUT_MSG for "
11428 + (r.startTime + BROADCAST_TIMEOUT));
11429 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11430 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11431 }
11432
11433 Object nextReceiver = r.receivers.get(recIdx);
11434 if (nextReceiver instanceof BroadcastFilter) {
11435 // Simple case: this is a registered receiver who gets
11436 // a direct call.
11437 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11438 if (DEBUG_BROADCAST) Log.v(TAG,
11439 "Delivering serialized to registered "
11440 + filter + ": " + r);
11441 deliverToRegisteredReceiver(r, filter, r.ordered);
11442 if (r.receiver == null || !r.ordered) {
11443 // The receiver has already finished, so schedule to
11444 // process the next one.
11445 r.state = BroadcastRecord.IDLE;
11446 scheduleBroadcastsLocked();
11447 }
11448 return;
11449 }
11450
11451 // Hard case: need to instantiate the receiver, possibly
11452 // starting its application process to host it.
11453
11454 ResolveInfo info =
11455 (ResolveInfo)nextReceiver;
11456
11457 boolean skip = false;
11458 int perm = checkComponentPermission(info.activityInfo.permission,
11459 r.callingPid, r.callingUid,
11460 info.activityInfo.exported
11461 ? -1 : info.activityInfo.applicationInfo.uid);
11462 if (perm != PackageManager.PERMISSION_GRANTED) {
11463 Log.w(TAG, "Permission Denial: broadcasting "
11464 + r.intent.toString()
11465 + " from " + r.callerPackage + " (pid=" + r.callingPid
11466 + ", uid=" + r.callingUid + ")"
11467 + " requires " + info.activityInfo.permission
11468 + " due to receiver " + info.activityInfo.packageName
11469 + "/" + info.activityInfo.name);
11470 skip = true;
11471 }
11472 if (r.callingUid != Process.SYSTEM_UID &&
11473 r.requiredPermission != null) {
11474 try {
11475 perm = ActivityThread.getPackageManager().
11476 checkPermission(r.requiredPermission,
11477 info.activityInfo.applicationInfo.packageName);
11478 } catch (RemoteException e) {
11479 perm = PackageManager.PERMISSION_DENIED;
11480 }
11481 if (perm != PackageManager.PERMISSION_GRANTED) {
11482 Log.w(TAG, "Permission Denial: receiving "
11483 + r.intent + " to "
11484 + info.activityInfo.applicationInfo.packageName
11485 + " requires " + r.requiredPermission
11486 + " due to sender " + r.callerPackage
11487 + " (uid " + r.callingUid + ")");
11488 skip = true;
11489 }
11490 }
11491 if (r.curApp != null && r.curApp.crashing) {
11492 // If the target process is crashing, just skip it.
11493 skip = true;
11494 }
11495
11496 if (skip) {
11497 r.receiver = null;
11498 r.curFilter = null;
11499 r.state = BroadcastRecord.IDLE;
11500 scheduleBroadcastsLocked();
11501 return;
11502 }
11503
11504 r.state = BroadcastRecord.APP_RECEIVE;
11505 String targetProcess = info.activityInfo.processName;
11506 r.curComponent = new ComponentName(
11507 info.activityInfo.applicationInfo.packageName,
11508 info.activityInfo.name);
11509 r.curReceiver = info.activityInfo;
11510
11511 // Is this receiver's application already running?
11512 ProcessRecord app = getProcessRecordLocked(targetProcess,
11513 info.activityInfo.applicationInfo.uid);
11514 if (app != null && app.thread != null) {
11515 try {
11516 processCurBroadcastLocked(r, app);
11517 return;
11518 } catch (RemoteException e) {
11519 Log.w(TAG, "Exception when sending broadcast to "
11520 + r.curComponent, e);
11521 }
11522
11523 // If a dead object exception was thrown -- fall through to
11524 // restart the application.
11525 }
11526
11527 // Not running -- get it started, and enqueue this history record
11528 // to be executed when the app comes up.
11529 if ((r.curApp=startProcessLocked(targetProcess,
11530 info.activityInfo.applicationInfo, true,
11531 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11532 "broadcast", r.curComponent)) == null) {
11533 // Ah, this recipient is unavailable. Finish it if necessary,
11534 // and mark the broadcast record as ready for the next.
11535 Log.w(TAG, "Unable to launch app "
11536 + info.activityInfo.applicationInfo.packageName + "/"
11537 + info.activityInfo.applicationInfo.uid + " for broadcast "
11538 + r.intent + ": process is bad");
11539 logBroadcastReceiverDiscard(r);
11540 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11541 r.resultExtras, r.resultAbort, true);
11542 scheduleBroadcastsLocked();
11543 r.state = BroadcastRecord.IDLE;
11544 return;
11545 }
11546
11547 mPendingBroadcast = r;
11548 }
11549 }
11550
11551 // =========================================================
11552 // INSTRUMENTATION
11553 // =========================================================
11554
11555 public boolean startInstrumentation(ComponentName className,
11556 String profileFile, int flags, Bundle arguments,
11557 IInstrumentationWatcher watcher) {
11558 // Refuse possible leaked file descriptors
11559 if (arguments != null && arguments.hasFileDescriptors()) {
11560 throw new IllegalArgumentException("File descriptors passed in Bundle");
11561 }
11562
11563 synchronized(this) {
11564 InstrumentationInfo ii = null;
11565 ApplicationInfo ai = null;
11566 try {
11567 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011568 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011569 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011570 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011571 } catch (PackageManager.NameNotFoundException e) {
11572 }
11573 if (ii == null) {
11574 reportStartInstrumentationFailure(watcher, className,
11575 "Unable to find instrumentation info for: " + className);
11576 return false;
11577 }
11578 if (ai == null) {
11579 reportStartInstrumentationFailure(watcher, className,
11580 "Unable to find instrumentation target package: " + ii.targetPackage);
11581 return false;
11582 }
11583
11584 int match = mContext.getPackageManager().checkSignatures(
11585 ii.targetPackage, ii.packageName);
11586 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11587 String msg = "Permission Denial: starting instrumentation "
11588 + className + " from pid="
11589 + Binder.getCallingPid()
11590 + ", uid=" + Binder.getCallingPid()
11591 + " not allowed because package " + ii.packageName
11592 + " does not have a signature matching the target "
11593 + ii.targetPackage;
11594 reportStartInstrumentationFailure(watcher, className, msg);
11595 throw new SecurityException(msg);
11596 }
11597
11598 final long origId = Binder.clearCallingIdentity();
11599 uninstallPackageLocked(ii.targetPackage, -1, true);
11600 ProcessRecord app = addAppLocked(ai);
11601 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011602 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011603 app.instrumentationProfileFile = profileFile;
11604 app.instrumentationArguments = arguments;
11605 app.instrumentationWatcher = watcher;
11606 app.instrumentationResultClass = className;
11607 Binder.restoreCallingIdentity(origId);
11608 }
11609
11610 return true;
11611 }
11612
11613 /**
11614 * Report errors that occur while attempting to start Instrumentation. Always writes the
11615 * error to the logs, but if somebody is watching, send the report there too. This enables
11616 * the "am" command to report errors with more information.
11617 *
11618 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11619 * @param cn The component name of the instrumentation.
11620 * @param report The error report.
11621 */
11622 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11623 ComponentName cn, String report) {
11624 Log.w(TAG, report);
11625 try {
11626 if (watcher != null) {
11627 Bundle results = new Bundle();
11628 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11629 results.putString("Error", report);
11630 watcher.instrumentationStatus(cn, -1, results);
11631 }
11632 } catch (RemoteException e) {
11633 Log.w(TAG, e);
11634 }
11635 }
11636
11637 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11638 if (app.instrumentationWatcher != null) {
11639 try {
11640 // NOTE: IInstrumentationWatcher *must* be oneway here
11641 app.instrumentationWatcher.instrumentationFinished(
11642 app.instrumentationClass,
11643 resultCode,
11644 results);
11645 } catch (RemoteException e) {
11646 }
11647 }
11648 app.instrumentationWatcher = null;
11649 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011650 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011651 app.instrumentationProfileFile = null;
11652 app.instrumentationArguments = null;
11653
11654 uninstallPackageLocked(app.processName, -1, false);
11655 }
11656
11657 public void finishInstrumentation(IApplicationThread target,
11658 int resultCode, Bundle results) {
11659 // Refuse possible leaked file descriptors
11660 if (results != null && results.hasFileDescriptors()) {
11661 throw new IllegalArgumentException("File descriptors passed in Intent");
11662 }
11663
11664 synchronized(this) {
11665 ProcessRecord app = getRecordForAppLocked(target);
11666 if (app == null) {
11667 Log.w(TAG, "finishInstrumentation: no app for " + target);
11668 return;
11669 }
11670 final long origId = Binder.clearCallingIdentity();
11671 finishInstrumentationLocked(app, resultCode, results);
11672 Binder.restoreCallingIdentity(origId);
11673 }
11674 }
11675
11676 // =========================================================
11677 // CONFIGURATION
11678 // =========================================================
11679
11680 public ConfigurationInfo getDeviceConfigurationInfo() {
11681 ConfigurationInfo config = new ConfigurationInfo();
11682 synchronized (this) {
11683 config.reqTouchScreen = mConfiguration.touchscreen;
11684 config.reqKeyboardType = mConfiguration.keyboard;
11685 config.reqNavigation = mConfiguration.navigation;
11686 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11687 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11688 }
11689 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11690 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11691 }
11692 }
11693 return config;
11694 }
11695
11696 public Configuration getConfiguration() {
11697 Configuration ci;
11698 synchronized(this) {
11699 ci = new Configuration(mConfiguration);
11700 }
11701 return ci;
11702 }
11703
11704 public void updateConfiguration(Configuration values) {
11705 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11706 "updateConfiguration()");
11707
11708 synchronized(this) {
11709 if (values == null && mWindowManager != null) {
11710 // sentinel: fetch the current configuration from the window manager
11711 values = mWindowManager.computeNewConfiguration();
11712 }
11713
11714 final long origId = Binder.clearCallingIdentity();
11715 updateConfigurationLocked(values, null);
11716 Binder.restoreCallingIdentity(origId);
11717 }
11718 }
11719
11720 /**
11721 * Do either or both things: (1) change the current configuration, and (2)
11722 * make sure the given activity is running with the (now) current
11723 * configuration. Returns true if the activity has been left running, or
11724 * false if <var>starting</var> is being destroyed to match the new
11725 * configuration.
11726 */
11727 public boolean updateConfigurationLocked(Configuration values,
11728 HistoryRecord starting) {
11729 int changes = 0;
11730
11731 boolean kept = true;
11732
11733 if (values != null) {
11734 Configuration newConfig = new Configuration(mConfiguration);
11735 changes = newConfig.updateFrom(values);
11736 if (changes != 0) {
11737 if (DEBUG_SWITCH) {
11738 Log.i(TAG, "Updating configuration to: " + values);
11739 }
11740
11741 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11742
11743 if (values.locale != null) {
11744 saveLocaleLocked(values.locale,
11745 !values.locale.equals(mConfiguration.locale),
11746 values.userSetLocale);
11747 }
11748
11749 mConfiguration = newConfig;
11750
11751 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11752 msg.obj = new Configuration(mConfiguration);
11753 mHandler.sendMessage(msg);
11754
11755 final int N = mLRUProcesses.size();
11756 for (int i=0; i<N; i++) {
11757 ProcessRecord app = mLRUProcesses.get(i);
11758 try {
11759 if (app.thread != null) {
11760 app.thread.scheduleConfigurationChanged(mConfiguration);
11761 }
11762 } catch (Exception e) {
11763 }
11764 }
11765 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11766 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11767 null, false, false, MY_PID, Process.SYSTEM_UID);
11768 }
11769 }
11770
11771 if (changes != 0 && starting == null) {
11772 // If the configuration changed, and the caller is not already
11773 // in the process of starting an activity, then find the top
11774 // activity to check if its configuration needs to change.
11775 starting = topRunningActivityLocked(null);
11776 }
11777
11778 if (starting != null) {
11779 kept = ensureActivityConfigurationLocked(starting, changes);
11780 if (kept) {
11781 // If this didn't result in the starting activity being
11782 // destroyed, then we need to make sure at this point that all
11783 // other activities are made visible.
11784 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11785 + ", ensuring others are correct.");
11786 ensureActivitiesVisibleLocked(starting, changes);
11787 }
11788 }
11789
11790 return kept;
11791 }
11792
11793 private final boolean relaunchActivityLocked(HistoryRecord r,
11794 int changes, boolean andResume) {
11795 List<ResultInfo> results = null;
11796 List<Intent> newIntents = null;
11797 if (andResume) {
11798 results = r.results;
11799 newIntents = r.newIntents;
11800 }
11801 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11802 + " with results=" + results + " newIntents=" + newIntents
11803 + " andResume=" + andResume);
11804 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11805 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11806 r.task.taskId, r.shortComponentName);
11807
11808 r.startFreezingScreenLocked(r.app, 0);
11809
11810 try {
11811 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11812 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11813 changes, !andResume);
11814 // Note: don't need to call pauseIfSleepingLocked() here, because
11815 // the caller will only pass in 'andResume' if this activity is
11816 // currently resumed, which implies we aren't sleeping.
11817 } catch (RemoteException e) {
11818 return false;
11819 }
11820
11821 if (andResume) {
11822 r.results = null;
11823 r.newIntents = null;
11824 }
11825
11826 return true;
11827 }
11828
11829 /**
11830 * Make sure the given activity matches the current configuration. Returns
11831 * false if the activity had to be destroyed. Returns true if the
11832 * configuration is the same, or the activity will remain running as-is
11833 * for whatever reason. Ensures the HistoryRecord is updated with the
11834 * correct configuration and all other bookkeeping is handled.
11835 */
11836 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11837 int globalChanges) {
11838 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11839
11840 // Short circuit: if the two configurations are the exact same
11841 // object (the common case), then there is nothing to do.
11842 Configuration newConfig = mConfiguration;
11843 if (r.configuration == newConfig) {
11844 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11845 return true;
11846 }
11847
11848 // We don't worry about activities that are finishing.
11849 if (r.finishing) {
11850 if (DEBUG_SWITCH) Log.i(TAG,
11851 "Configuration doesn't matter in finishing " + r);
11852 r.stopFreezingScreenLocked(false);
11853 return true;
11854 }
11855
11856 // Okay we now are going to make this activity have the new config.
11857 // But then we need to figure out how it needs to deal with that.
11858 Configuration oldConfig = r.configuration;
11859 r.configuration = newConfig;
11860
11861 // If the activity isn't currently running, just leave the new
11862 // configuration and it will pick that up next time it starts.
11863 if (r.app == null || r.app.thread == null) {
11864 if (DEBUG_SWITCH) Log.i(TAG,
11865 "Configuration doesn't matter not running " + r);
11866 r.stopFreezingScreenLocked(false);
11867 return true;
11868 }
11869
11870 // If the activity isn't persistent, there is a chance we will
11871 // need to restart it.
11872 if (!r.persistent) {
11873
11874 // Figure out what has changed between the two configurations.
11875 int changes = oldConfig.diff(newConfig);
11876 if (DEBUG_SWITCH) {
11877 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11878 + Integer.toHexString(changes) + ", handles=0x"
11879 + Integer.toHexString(r.info.configChanges));
11880 }
11881 if ((changes&(~r.info.configChanges)) != 0) {
11882 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11883 r.configChangeFlags |= changes;
11884 r.startFreezingScreenLocked(r.app, globalChanges);
11885 if (r.app == null || r.app.thread == null) {
11886 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11887 destroyActivityLocked(r, true);
11888 } else if (r.state == ActivityState.PAUSING) {
11889 // A little annoying: we are waiting for this activity to
11890 // finish pausing. Let's not do anything now, but just
11891 // flag that it needs to be restarted when done pausing.
11892 r.configDestroy = true;
11893 return true;
11894 } else if (r.state == ActivityState.RESUMED) {
11895 // Try to optimize this case: the configuration is changing
11896 // and we need to restart the top, resumed activity.
11897 // Instead of doing the normal handshaking, just say
11898 // "restart!".
11899 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11900 relaunchActivityLocked(r, r.configChangeFlags, true);
11901 r.configChangeFlags = 0;
11902 } else {
11903 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11904 relaunchActivityLocked(r, r.configChangeFlags, false);
11905 r.configChangeFlags = 0;
11906 }
11907
11908 // All done... tell the caller we weren't able to keep this
11909 // activity around.
11910 return false;
11911 }
11912 }
11913
11914 // Default case: the activity can handle this new configuration, so
11915 // hand it over. Note that we don't need to give it the new
11916 // configuration, since we always send configuration changes to all
11917 // process when they happen so it can just use whatever configuration
11918 // it last got.
11919 if (r.app != null && r.app.thread != null) {
11920 try {
11921 r.app.thread.scheduleActivityConfigurationChanged(r);
11922 } catch (RemoteException e) {
11923 // If process died, whatever.
11924 }
11925 }
11926 r.stopFreezingScreenLocked(false);
11927
11928 return true;
11929 }
11930
11931 /**
11932 * Save the locale. You must be inside a synchronized (this) block.
11933 */
11934 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11935 if(isDiff) {
11936 SystemProperties.set("user.language", l.getLanguage());
11937 SystemProperties.set("user.region", l.getCountry());
11938 }
11939
11940 if(isPersist) {
11941 SystemProperties.set("persist.sys.language", l.getLanguage());
11942 SystemProperties.set("persist.sys.country", l.getCountry());
11943 SystemProperties.set("persist.sys.localevar", l.getVariant());
11944 }
11945 }
11946
11947 // =========================================================
11948 // LIFETIME MANAGEMENT
11949 // =========================================================
11950
11951 private final int computeOomAdjLocked(
11952 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11953 if (mAdjSeq == app.adjSeq) {
11954 // This adjustment has already been computed.
11955 return app.curAdj;
11956 }
11957
11958 if (app.thread == null) {
11959 app.adjSeq = mAdjSeq;
11960 return (app.curAdj=EMPTY_APP_ADJ);
11961 }
11962
11963 app.isForeground = false;
11964
The Android Open Source Project4df24232009-03-05 14:34:35 -080011965 // Determine the importance of the process, starting with most
11966 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011967 int adj;
11968 int N;
11969 if (app == TOP_APP || app.instrumentationClass != null
11970 || app.persistentActivities > 0) {
11971 // The last app on the list is the foreground app.
11972 adj = FOREGROUND_APP_ADJ;
11973 app.isForeground = true;
11974 } else if (app.curReceiver != null ||
11975 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11976 // An app that is currently receiving a broadcast also
11977 // counts as being in the foreground.
11978 adj = FOREGROUND_APP_ADJ;
11979 } else if (app.executingServices.size() > 0) {
11980 // An app that is currently executing a service callback also
11981 // counts as being in the foreground.
11982 adj = FOREGROUND_APP_ADJ;
11983 } else if (app.foregroundServices || app.forcingToForeground != null) {
11984 // The user is aware of this app, so make it visible.
11985 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011986 } else if (app == mHomeProcess) {
11987 // This process is hosting what we currently consider to be the
11988 // home app, so we don't want to let it go into the background.
11989 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011990 } else if ((N=app.activities.size()) != 0) {
11991 // This app is in the background with paused activities.
11992 adj = hiddenAdj;
11993 for (int j=0; j<N; j++) {
11994 if (((HistoryRecord)app.activities.get(j)).visible) {
11995 // This app has a visible activity!
11996 adj = VISIBLE_APP_ADJ;
11997 break;
11998 }
11999 }
12000 } else {
12001 // A very not-needed process.
12002 adj = EMPTY_APP_ADJ;
12003 }
12004
The Android Open Source Project4df24232009-03-05 14:34:35 -080012005 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012006 // there are applications dependent on our services or providers, but
12007 // this gives us a baseline and makes sure we don't get into an
12008 // infinite recursion.
12009 app.adjSeq = mAdjSeq;
12010 app.curRawAdj = adj;
12011 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12012
Christopher Tate6fa95972009-06-05 18:43:55 -070012013 if (mBackupTarget != null && app == mBackupTarget.app) {
12014 // If possible we want to avoid killing apps while they're being backed up
12015 if (adj > BACKUP_APP_ADJ) {
12016 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12017 adj = BACKUP_APP_ADJ;
12018 }
12019 }
12020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012021 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12022 // If this process has active services running in it, we would
12023 // like to avoid killing it unless it would prevent the current
12024 // application from running.
12025 if (adj > hiddenAdj) {
12026 adj = hiddenAdj;
12027 }
12028 final long now = SystemClock.uptimeMillis();
12029 // This process is more important if the top activity is
12030 // bound to the service.
12031 Iterator jt = app.services.iterator();
12032 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12033 ServiceRecord s = (ServiceRecord)jt.next();
12034 if (s.startRequested) {
12035 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12036 // This service has seen some activity within
12037 // recent memory, so we will keep its process ahead
12038 // of the background processes.
12039 if (adj > SECONDARY_SERVER_ADJ) {
12040 adj = SECONDARY_SERVER_ADJ;
12041 }
12042 } else {
12043 // This service has been inactive for too long, just
12044 // put it with the rest of the background processes.
12045 if (adj > hiddenAdj) {
12046 adj = hiddenAdj;
12047 }
12048 }
12049 }
12050 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12051 Iterator<ConnectionRecord> kt
12052 = s.connections.values().iterator();
12053 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12054 // XXX should compute this based on the max of
12055 // all connected clients.
12056 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012057 if (cr.binding.client == app) {
12058 // Binding to ourself is not interesting.
12059 continue;
12060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012061 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12062 ProcessRecord client = cr.binding.client;
12063 int myHiddenAdj = hiddenAdj;
12064 if (myHiddenAdj > client.hiddenAdj) {
12065 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12066 myHiddenAdj = client.hiddenAdj;
12067 } else {
12068 myHiddenAdj = VISIBLE_APP_ADJ;
12069 }
12070 }
12071 int clientAdj = computeOomAdjLocked(
12072 client, myHiddenAdj, TOP_APP);
12073 if (adj > clientAdj) {
12074 adj = clientAdj > VISIBLE_APP_ADJ
12075 ? clientAdj : VISIBLE_APP_ADJ;
12076 }
12077 }
12078 HistoryRecord a = cr.activity;
12079 //if (a != null) {
12080 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12081 //}
12082 if (a != null && adj > FOREGROUND_APP_ADJ &&
12083 (a.state == ActivityState.RESUMED
12084 || a.state == ActivityState.PAUSING)) {
12085 adj = FOREGROUND_APP_ADJ;
12086 }
12087 }
12088 }
12089 }
12090 }
12091
12092 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12093 // If this process has published any content providers, then
12094 // its adjustment makes it at least as important as any of the
12095 // processes using those providers, and no less important than
12096 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12097 if (adj > CONTENT_PROVIDER_ADJ) {
12098 adj = CONTENT_PROVIDER_ADJ;
12099 }
12100 Iterator jt = app.pubProviders.values().iterator();
12101 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12102 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12103 if (cpr.clients.size() != 0) {
12104 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12105 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12106 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012107 if (client == app) {
12108 // Being our own client is not interesting.
12109 continue;
12110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012111 int myHiddenAdj = hiddenAdj;
12112 if (myHiddenAdj > client.hiddenAdj) {
12113 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12114 myHiddenAdj = client.hiddenAdj;
12115 } else {
12116 myHiddenAdj = FOREGROUND_APP_ADJ;
12117 }
12118 }
12119 int clientAdj = computeOomAdjLocked(
12120 client, myHiddenAdj, TOP_APP);
12121 if (adj > clientAdj) {
12122 adj = clientAdj > FOREGROUND_APP_ADJ
12123 ? clientAdj : FOREGROUND_APP_ADJ;
12124 }
12125 }
12126 }
12127 // If the provider has external (non-framework) process
12128 // dependencies, ensure that its adjustment is at least
12129 // FOREGROUND_APP_ADJ.
12130 if (cpr.externals != 0) {
12131 if (adj > FOREGROUND_APP_ADJ) {
12132 adj = FOREGROUND_APP_ADJ;
12133 }
12134 }
12135 }
12136 }
12137
12138 app.curRawAdj = adj;
12139
12140 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12141 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12142 if (adj > app.maxAdj) {
12143 adj = app.maxAdj;
12144 }
12145
12146 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012147 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12148 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12149 : Process.THREAD_GROUP_DEFAULT;
12150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012151 return adj;
12152 }
12153
12154 /**
12155 * Ask a given process to GC right now.
12156 */
12157 final void performAppGcLocked(ProcessRecord app) {
12158 try {
12159 app.lastRequestedGc = SystemClock.uptimeMillis();
12160 if (app.thread != null) {
12161 app.thread.processInBackground();
12162 }
12163 } catch (Exception e) {
12164 // whatever.
12165 }
12166 }
12167
12168 /**
12169 * Returns true if things are idle enough to perform GCs.
12170 */
12171 private final boolean canGcNow() {
12172 return mParallelBroadcasts.size() == 0
12173 && mOrderedBroadcasts.size() == 0
12174 && (mSleeping || (mResumedActivity != null &&
12175 mResumedActivity.idle));
12176 }
12177
12178 /**
12179 * Perform GCs on all processes that are waiting for it, but only
12180 * if things are idle.
12181 */
12182 final void performAppGcsLocked() {
12183 final int N = mProcessesToGc.size();
12184 if (N <= 0) {
12185 return;
12186 }
12187 if (canGcNow()) {
12188 while (mProcessesToGc.size() > 0) {
12189 ProcessRecord proc = mProcessesToGc.remove(0);
12190 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12191 // To avoid spamming the system, we will GC processes one
12192 // at a time, waiting a few seconds between each.
12193 performAppGcLocked(proc);
12194 scheduleAppGcsLocked();
12195 return;
12196 }
12197 }
12198 }
12199 }
12200
12201 /**
12202 * If all looks good, perform GCs on all processes waiting for them.
12203 */
12204 final void performAppGcsIfAppropriateLocked() {
12205 if (canGcNow()) {
12206 performAppGcsLocked();
12207 return;
12208 }
12209 // Still not idle, wait some more.
12210 scheduleAppGcsLocked();
12211 }
12212
12213 /**
12214 * Schedule the execution of all pending app GCs.
12215 */
12216 final void scheduleAppGcsLocked() {
12217 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12218 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12219 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12220 }
12221
12222 /**
12223 * Set up to ask a process to GC itself. This will either do it
12224 * immediately, or put it on the list of processes to gc the next
12225 * time things are idle.
12226 */
12227 final void scheduleAppGcLocked(ProcessRecord app) {
12228 long now = SystemClock.uptimeMillis();
12229 if ((app.lastRequestedGc+5000) > now) {
12230 return;
12231 }
12232 if (!mProcessesToGc.contains(app)) {
12233 mProcessesToGc.add(app);
12234 scheduleAppGcsLocked();
12235 }
12236 }
12237
12238 private final boolean updateOomAdjLocked(
12239 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12240 app.hiddenAdj = hiddenAdj;
12241
12242 if (app.thread == null) {
12243 return true;
12244 }
12245
12246 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12247
12248 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12249 //Thread priority adjustment is disabled out to see
12250 //how the kernel scheduler performs.
12251 if (false) {
12252 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12253 app.setIsForeground = app.isForeground;
12254 if (app.pid != MY_PID) {
12255 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12256 + " to " + (app.isForeground
12257 ? Process.THREAD_PRIORITY_FOREGROUND
12258 : Process.THREAD_PRIORITY_DEFAULT));
12259 try {
12260 Process.setThreadPriority(app.pid, app.isForeground
12261 ? Process.THREAD_PRIORITY_FOREGROUND
12262 : Process.THREAD_PRIORITY_DEFAULT);
12263 } catch (RuntimeException e) {
12264 Log.w(TAG, "Exception trying to set priority of application thread "
12265 + app.pid, e);
12266 }
12267 }
12268 }
12269 }
12270 if (app.pid != 0 && app.pid != MY_PID) {
12271 if (app.curRawAdj != app.setRawAdj) {
12272 if (app.curRawAdj > FOREGROUND_APP_ADJ
12273 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12274 // If this app is transitioning from foreground to
12275 // non-foreground, have it do a gc.
12276 scheduleAppGcLocked(app);
12277 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12278 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12279 // Likewise do a gc when an app is moving in to the
12280 // background (such as a service stopping).
12281 scheduleAppGcLocked(app);
12282 }
12283 app.setRawAdj = app.curRawAdj;
12284 }
12285 if (adj != app.setAdj) {
12286 if (Process.setOomAdj(app.pid, adj)) {
12287 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12288 TAG, "Set app " + app.processName +
12289 " oom adj to " + adj);
12290 app.setAdj = adj;
12291 } else {
12292 return false;
12293 }
12294 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012295 if (app.setSchedGroup != app.curSchedGroup) {
12296 app.setSchedGroup = app.curSchedGroup;
12297 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12298 "Setting process group of " + app.processName
12299 + " to " + app.curSchedGroup);
12300 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012301 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012302 try {
12303 Process.setProcessGroup(app.pid, app.curSchedGroup);
12304 } catch (Exception e) {
12305 Log.w(TAG, "Failed setting process group of " + app.pid
12306 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012307 e.printStackTrace();
12308 } finally {
12309 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012310 }
12311 }
12312 if (false) {
12313 if (app.thread != null) {
12314 try {
12315 app.thread.setSchedulingGroup(app.curSchedGroup);
12316 } catch (RemoteException e) {
12317 }
12318 }
12319 }
12320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012321 }
12322
12323 return true;
12324 }
12325
12326 private final HistoryRecord resumedAppLocked() {
12327 HistoryRecord resumedActivity = mResumedActivity;
12328 if (resumedActivity == null || resumedActivity.app == null) {
12329 resumedActivity = mPausingActivity;
12330 if (resumedActivity == null || resumedActivity.app == null) {
12331 resumedActivity = topRunningActivityLocked(null);
12332 }
12333 }
12334 return resumedActivity;
12335 }
12336
12337 private final boolean updateOomAdjLocked(ProcessRecord app) {
12338 final HistoryRecord TOP_ACT = resumedAppLocked();
12339 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12340 int curAdj = app.curAdj;
12341 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12342 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12343
12344 mAdjSeq++;
12345
12346 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12347 if (res) {
12348 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12349 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12350 if (nowHidden != wasHidden) {
12351 // Changed to/from hidden state, so apps after it in the LRU
12352 // list may also be changed.
12353 updateOomAdjLocked();
12354 }
12355 }
12356 return res;
12357 }
12358
12359 private final boolean updateOomAdjLocked() {
12360 boolean didOomAdj = true;
12361 final HistoryRecord TOP_ACT = resumedAppLocked();
12362 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12363
12364 if (false) {
12365 RuntimeException e = new RuntimeException();
12366 e.fillInStackTrace();
12367 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12368 }
12369
12370 mAdjSeq++;
12371
12372 // First try updating the OOM adjustment for each of the
12373 // application processes based on their current state.
12374 int i = mLRUProcesses.size();
12375 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12376 while (i > 0) {
12377 i--;
12378 ProcessRecord app = mLRUProcesses.get(i);
12379 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12380 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12381 && app.curAdj == curHiddenAdj) {
12382 curHiddenAdj++;
12383 }
12384 } else {
12385 didOomAdj = false;
12386 }
12387 }
12388
12389 // todo: for now pretend like OOM ADJ didn't work, because things
12390 // aren't behaving as expected on Linux -- it's not killing processes.
12391 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12392 }
12393
12394 private final void trimApplications() {
12395 synchronized (this) {
12396 int i;
12397
12398 // First remove any unused application processes whose package
12399 // has been removed.
12400 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12401 final ProcessRecord app = mRemovedProcesses.get(i);
12402 if (app.activities.size() == 0
12403 && app.curReceiver == null && app.services.size() == 0) {
12404 Log.i(
12405 TAG, "Exiting empty application process "
12406 + app.processName + " ("
12407 + (app.thread != null ? app.thread.asBinder() : null)
12408 + ")\n");
12409 if (app.pid > 0 && app.pid != MY_PID) {
12410 Process.killProcess(app.pid);
12411 } else {
12412 try {
12413 app.thread.scheduleExit();
12414 } catch (Exception e) {
12415 // Ignore exceptions.
12416 }
12417 }
12418 cleanUpApplicationRecordLocked(app, false, -1);
12419 mRemovedProcesses.remove(i);
12420
12421 if (app.persistent) {
12422 if (app.persistent) {
12423 addAppLocked(app.info);
12424 }
12425 }
12426 }
12427 }
12428
12429 // Now try updating the OOM adjustment for each of the
12430 // application processes based on their current state.
12431 // If the setOomAdj() API is not supported, then go with our
12432 // back-up plan...
12433 if (!updateOomAdjLocked()) {
12434
12435 // Count how many processes are running services.
12436 int numServiceProcs = 0;
12437 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12438 final ProcessRecord app = mLRUProcesses.get(i);
12439
12440 if (app.persistent || app.services.size() != 0
12441 || app.curReceiver != null
12442 || app.persistentActivities > 0) {
12443 // Don't count processes holding services against our
12444 // maximum process count.
12445 if (localLOGV) Log.v(
12446 TAG, "Not trimming app " + app + " with services: "
12447 + app.services);
12448 numServiceProcs++;
12449 }
12450 }
12451
12452 int curMaxProcs = mProcessLimit;
12453 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12454 if (mAlwaysFinishActivities) {
12455 curMaxProcs = 1;
12456 }
12457 curMaxProcs += numServiceProcs;
12458
12459 // Quit as many processes as we can to get down to the desired
12460 // process count. First remove any processes that no longer
12461 // have activites running in them.
12462 for ( i=0;
12463 i<mLRUProcesses.size()
12464 && mLRUProcesses.size() > curMaxProcs;
12465 i++) {
12466 final ProcessRecord app = mLRUProcesses.get(i);
12467 // Quit an application only if it is not currently
12468 // running any activities.
12469 if (!app.persistent && app.activities.size() == 0
12470 && app.curReceiver == null && app.services.size() == 0) {
12471 Log.i(
12472 TAG, "Exiting empty application process "
12473 + app.processName + " ("
12474 + (app.thread != null ? app.thread.asBinder() : null)
12475 + ")\n");
12476 if (app.pid > 0 && app.pid != MY_PID) {
12477 Process.killProcess(app.pid);
12478 } else {
12479 try {
12480 app.thread.scheduleExit();
12481 } catch (Exception e) {
12482 // Ignore exceptions.
12483 }
12484 }
12485 // todo: For now we assume the application is not buggy
12486 // or evil, and will quit as a result of our request.
12487 // Eventually we need to drive this off of the death
12488 // notification, and kill the process if it takes too long.
12489 cleanUpApplicationRecordLocked(app, false, i);
12490 i--;
12491 }
12492 }
12493
12494 // If we still have too many processes, now from the least
12495 // recently used process we start finishing activities.
12496 if (Config.LOGV) Log.v(
12497 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12498 " of " + curMaxProcs + " processes");
12499 for ( i=0;
12500 i<mLRUProcesses.size()
12501 && mLRUProcesses.size() > curMaxProcs;
12502 i++) {
12503 final ProcessRecord app = mLRUProcesses.get(i);
12504 // Quit the application only if we have a state saved for
12505 // all of its activities.
12506 boolean canQuit = !app.persistent && app.curReceiver == null
12507 && app.services.size() == 0
12508 && app.persistentActivities == 0;
12509 int NUMA = app.activities.size();
12510 int j;
12511 if (Config.LOGV) Log.v(
12512 TAG, "Looking to quit " + app.processName);
12513 for (j=0; j<NUMA && canQuit; j++) {
12514 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12515 if (Config.LOGV) Log.v(
12516 TAG, " " + r.intent.getComponent().flattenToShortString()
12517 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12518 canQuit = (r.haveState || !r.stateNotNeeded)
12519 && !r.visible && r.stopped;
12520 }
12521 if (canQuit) {
12522 // Finish all of the activities, and then the app itself.
12523 for (j=0; j<NUMA; j++) {
12524 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12525 if (!r.finishing) {
12526 destroyActivityLocked(r, false);
12527 }
12528 r.resultTo = null;
12529 }
12530 Log.i(TAG, "Exiting application process "
12531 + app.processName + " ("
12532 + (app.thread != null ? app.thread.asBinder() : null)
12533 + ")\n");
12534 if (app.pid > 0 && app.pid != MY_PID) {
12535 Process.killProcess(app.pid);
12536 } else {
12537 try {
12538 app.thread.scheduleExit();
12539 } catch (Exception e) {
12540 // Ignore exceptions.
12541 }
12542 }
12543 // todo: For now we assume the application is not buggy
12544 // or evil, and will quit as a result of our request.
12545 // Eventually we need to drive this off of the death
12546 // notification, and kill the process if it takes too long.
12547 cleanUpApplicationRecordLocked(app, false, i);
12548 i--;
12549 //dump();
12550 }
12551 }
12552
12553 }
12554
12555 int curMaxActivities = MAX_ACTIVITIES;
12556 if (mAlwaysFinishActivities) {
12557 curMaxActivities = 1;
12558 }
12559
12560 // Finally, if there are too many activities now running, try to
12561 // finish as many as we can to get back down to the limit.
12562 for ( i=0;
12563 i<mLRUActivities.size()
12564 && mLRUActivities.size() > curMaxActivities;
12565 i++) {
12566 final HistoryRecord r
12567 = (HistoryRecord)mLRUActivities.get(i);
12568
12569 // We can finish this one if we have its icicle saved and
12570 // it is not persistent.
12571 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12572 && r.stopped && !r.persistent && !r.finishing) {
12573 final int origSize = mLRUActivities.size();
12574 destroyActivityLocked(r, true);
12575
12576 // This will remove it from the LRU list, so keep
12577 // our index at the same value. Note that this check to
12578 // see if the size changes is just paranoia -- if
12579 // something unexpected happens, we don't want to end up
12580 // in an infinite loop.
12581 if (origSize > mLRUActivities.size()) {
12582 i--;
12583 }
12584 }
12585 }
12586 }
12587 }
12588
12589 /** This method sends the specified signal to each of the persistent apps */
12590 public void signalPersistentProcesses(int sig) throws RemoteException {
12591 if (sig != Process.SIGNAL_USR1) {
12592 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12593 }
12594
12595 synchronized (this) {
12596 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12597 != PackageManager.PERMISSION_GRANTED) {
12598 throw new SecurityException("Requires permission "
12599 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12600 }
12601
12602 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12603 ProcessRecord r = mLRUProcesses.get(i);
12604 if (r.thread != null && r.persistent) {
12605 Process.sendSignal(r.pid, sig);
12606 }
12607 }
12608 }
12609 }
12610
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012611 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012612 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012613
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012614 try {
12615 synchronized (this) {
12616 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12617 // its own permission.
12618 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12619 != PackageManager.PERMISSION_GRANTED) {
12620 throw new SecurityException("Requires permission "
12621 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012622 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012623
12624 if (start && fd == null) {
12625 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012626 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012627
12628 ProcessRecord proc = null;
12629 try {
12630 int pid = Integer.parseInt(process);
12631 synchronized (mPidsSelfLocked) {
12632 proc = mPidsSelfLocked.get(pid);
12633 }
12634 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012635 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012636
12637 if (proc == null) {
12638 HashMap<String, SparseArray<ProcessRecord>> all
12639 = mProcessNames.getMap();
12640 SparseArray<ProcessRecord> procs = all.get(process);
12641 if (procs != null && procs.size() > 0) {
12642 proc = procs.valueAt(0);
12643 }
12644 }
12645
12646 if (proc == null || proc.thread == null) {
12647 throw new IllegalArgumentException("Unknown process: " + process);
12648 }
12649
12650 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12651 if (isSecure) {
12652 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12653 throw new SecurityException("Process not debuggable: " + proc);
12654 }
12655 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012656
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012657 proc.thread.profilerControl(start, path, fd);
12658 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012659 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012660 }
12661 } catch (RemoteException e) {
12662 throw new IllegalStateException("Process disappeared");
12663 } finally {
12664 if (fd != null) {
12665 try {
12666 fd.close();
12667 } catch (IOException e) {
12668 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012669 }
12670 }
12671 }
12672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012673 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12674 public void monitor() {
12675 synchronized (this) { }
12676 }
12677}