blob: 62b4d5ef463595d14cefaf5e5aa6103b91ab8189 [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 Yamasani32dbefd2009-06-19 09:21:17 -07001521 final BatteryStatsImpl bstats =
1522 (BatteryStatsImpl) mBatteryStatsService.getActiveStatistics();
1523 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 synchronized(mPidsSelfLocked) {
1525 if (haveNewCpuStats) {
1526 if (mBatteryStatsService.isOnBattery()) {
1527 final int N = mProcessStats.countWorkingStats();
1528 for (int i=0; i<N; i++) {
1529 ProcessStats.Stats st
1530 = mProcessStats.getWorkingStats(i);
1531 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1532 if (pr != null) {
1533 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1534 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001535 } else {
1536 BatteryStatsImpl.Uid.Proc ps =
1537 bstats.getProcessStatsLocked(st.name);
1538 if (ps != null) {
1539 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 }
1542 }
1543 }
1544 }
1545 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1548 mLastWriteTime = now;
1549 mBatteryStatsService.getActiveStatistics().writeLocked();
1550 }
1551 }
1552 }
1553 }
1554
1555 /**
1556 * Initialize the application bind args. These are passed to each
1557 * process when the bindApplication() IPC is sent to the process. They're
1558 * lazily setup to make sure the services are running when they're asked for.
1559 */
1560 private HashMap<String, IBinder> getCommonServicesLocked() {
1561 if (mAppBindArgs == null) {
1562 mAppBindArgs = new HashMap<String, IBinder>();
1563
1564 // Setup the application init args
1565 mAppBindArgs.put("package", ServiceManager.getService("package"));
1566 mAppBindArgs.put("window", ServiceManager.getService("window"));
1567 mAppBindArgs.put(Context.ALARM_SERVICE,
1568 ServiceManager.getService(Context.ALARM_SERVICE));
1569 }
1570 return mAppBindArgs;
1571 }
1572
1573 private final void setFocusedActivityLocked(HistoryRecord r) {
1574 if (mFocusedActivity != r) {
1575 mFocusedActivity = r;
1576 mWindowManager.setFocusedApp(r, true);
1577 }
1578 }
1579
1580 private final void updateLRUListLocked(ProcessRecord app,
1581 boolean oomAdj) {
1582 // put it on the LRU to keep track of when it should be exited.
1583 int lrui = mLRUProcesses.indexOf(app);
1584 if (lrui >= 0) mLRUProcesses.remove(lrui);
1585 mLRUProcesses.add(app);
1586 //Log.i(TAG, "Putting proc to front: " + app.processName);
1587 if (oomAdj) {
1588 updateOomAdjLocked();
1589 }
1590 }
1591
1592 private final boolean updateLRUListLocked(HistoryRecord r) {
1593 final boolean hadit = mLRUActivities.remove(r);
1594 mLRUActivities.add(r);
1595 return hadit;
1596 }
1597
1598 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1599 int i = mHistory.size()-1;
1600 while (i >= 0) {
1601 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1602 if (!r.finishing && r != notTop) {
1603 return r;
1604 }
1605 i--;
1606 }
1607 return null;
1608 }
1609
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001610 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1611 int i = mHistory.size()-1;
1612 while (i >= 0) {
1613 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1614 if (!r.finishing && !r.delayedResume && r != notTop) {
1615 return r;
1616 }
1617 i--;
1618 }
1619 return null;
1620 }
1621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 /**
1623 * This is a simplified version of topRunningActivityLocked that provides a number of
1624 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1625 *
1626 * @param token If non-null, any history records matching this token will be skipped.
1627 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1628 *
1629 * @return Returns the HistoryRecord of the next activity on the stack.
1630 */
1631 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1632 int i = mHistory.size()-1;
1633 while (i >= 0) {
1634 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1635 // Note: the taskId check depends on real taskId fields being non-zero
1636 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1637 return r;
1638 }
1639 i--;
1640 }
1641 return null;
1642 }
1643
1644 private final ProcessRecord getProcessRecordLocked(
1645 String processName, int uid) {
1646 if (uid == Process.SYSTEM_UID) {
1647 // The system gets to run in any process. If there are multiple
1648 // processes with the same uid, just pick the first (this
1649 // should never happen).
1650 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1651 processName);
1652 return procs != null ? procs.valueAt(0) : null;
1653 }
1654 ProcessRecord proc = mProcessNames.get(processName, uid);
1655 return proc;
1656 }
1657
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001658 private void ensurePackageDexOpt(String packageName) {
1659 IPackageManager pm = ActivityThread.getPackageManager();
1660 try {
1661 if (pm.performDexOpt(packageName)) {
1662 mDidDexOpt = true;
1663 }
1664 } catch (RemoteException e) {
1665 }
1666 }
1667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 private boolean isNextTransitionForward() {
1669 int transit = mWindowManager.getPendingAppTransition();
1670 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1671 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1672 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1673 }
1674
1675 private final boolean realStartActivityLocked(HistoryRecord r,
1676 ProcessRecord app, boolean andResume, boolean checkConfig)
1677 throws RemoteException {
1678
1679 r.startFreezingScreenLocked(app, 0);
1680 mWindowManager.setAppVisibility(r, true);
1681
1682 // Have the window manager re-evaluate the orientation of
1683 // the screen based on the new activity order. Note that
1684 // as a result of this, it can call back into the activity
1685 // manager with a new orientation. We don't care about that,
1686 // because the activity is not currently running so we are
1687 // just restarting it anyway.
1688 if (checkConfig) {
1689 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001690 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 r.mayFreezeScreenLocked(app) ? r : null);
1692 updateConfigurationLocked(config, r);
1693 }
1694
1695 r.app = app;
1696
1697 if (localLOGV) Log.v(TAG, "Launching: " + r);
1698
1699 int idx = app.activities.indexOf(r);
1700 if (idx < 0) {
1701 app.activities.add(r);
1702 }
1703 updateLRUListLocked(app, true);
1704
1705 try {
1706 if (app.thread == null) {
1707 throw new RemoteException();
1708 }
1709 List<ResultInfo> results = null;
1710 List<Intent> newIntents = null;
1711 if (andResume) {
1712 results = r.results;
1713 newIntents = r.newIntents;
1714 }
1715 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1716 + " icicle=" + r.icicle
1717 + " with results=" + results + " newIntents=" + newIntents
1718 + " andResume=" + andResume);
1719 if (andResume) {
1720 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1721 System.identityHashCode(r),
1722 r.task.taskId, r.shortComponentName);
1723 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001724 if (r.isHomeActivity) {
1725 mHomeProcess = app;
1726 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001727 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1729 r.info, r.icicle, results, newIntents, !andResume,
1730 isNextTransitionForward());
1731 // Update usage stats for launched activity
1732 updateUsageStats(r, true);
1733 } catch (RemoteException e) {
1734 if (r.launchFailed) {
1735 // This is the second time we failed -- finish activity
1736 // and give up.
1737 Log.e(TAG, "Second failure launching "
1738 + r.intent.getComponent().flattenToShortString()
1739 + ", giving up", e);
1740 appDiedLocked(app, app.pid, app.thread);
1741 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1742 "2nd-crash");
1743 return false;
1744 }
1745
1746 // This is the first time we failed -- restart process and
1747 // retry.
1748 app.activities.remove(r);
1749 throw e;
1750 }
1751
1752 r.launchFailed = false;
1753 if (updateLRUListLocked(r)) {
1754 Log.w(TAG, "Activity " + r
1755 + " being launched, but already in LRU list");
1756 }
1757
1758 if (andResume) {
1759 // As part of the process of launching, ActivityThread also performs
1760 // a resume.
1761 r.state = ActivityState.RESUMED;
1762 r.icicle = null;
1763 r.haveState = false;
1764 r.stopped = false;
1765 mResumedActivity = r;
1766 r.task.touchActiveTime();
1767 completeResumeLocked(r);
1768 pauseIfSleepingLocked();
1769 } else {
1770 // This activity is not starting in the resumed state... which
1771 // should look like we asked it to pause+stop (but remain visible),
1772 // and it has done so and reported back the current icicle and
1773 // other state.
1774 r.state = ActivityState.STOPPED;
1775 r.stopped = true;
1776 }
1777
1778 return true;
1779 }
1780
1781 private final void startSpecificActivityLocked(HistoryRecord r,
1782 boolean andResume, boolean checkConfig) {
1783 // Is this activity's application already running?
1784 ProcessRecord app = getProcessRecordLocked(r.processName,
1785 r.info.applicationInfo.uid);
1786
1787 if (r.startTime == 0) {
1788 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001789 if (mInitialStartTime == 0) {
1790 mInitialStartTime = r.startTime;
1791 }
1792 } else if (mInitialStartTime == 0) {
1793 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 }
1795
1796 if (app != null && app.thread != null) {
1797 try {
1798 realStartActivityLocked(r, app, andResume, checkConfig);
1799 return;
1800 } catch (RemoteException e) {
1801 Log.w(TAG, "Exception when starting activity "
1802 + r.intent.getComponent().flattenToShortString(), e);
1803 }
1804
1805 // If a dead object exception was thrown -- fall through to
1806 // restart the application.
1807 }
1808
1809 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1810 "activity", r.intent.getComponent());
1811 }
1812
1813 private final ProcessRecord startProcessLocked(String processName,
1814 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1815 String hostingType, ComponentName hostingName) {
1816 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1817 // We don't have to do anything more if:
1818 // (1) There is an existing application record; and
1819 // (2) The caller doesn't think it is dead, OR there is no thread
1820 // object attached to it so we know it couldn't have crashed; and
1821 // (3) There is a pid assigned to it, so it is either starting or
1822 // already running.
1823 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1824 + " app=" + app + " knownToBeDead=" + knownToBeDead
1825 + " thread=" + (app != null ? app.thread : null)
1826 + " pid=" + (app != null ? app.pid : -1));
1827 if (app != null &&
1828 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1829 return app;
1830 }
1831
1832 String hostingNameStr = hostingName != null
1833 ? hostingName.flattenToShortString() : null;
1834
1835 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1836 // If we are in the background, then check to see if this process
1837 // is bad. If so, we will just silently fail.
1838 if (mBadProcesses.get(info.processName, info.uid) != null) {
1839 return null;
1840 }
1841 } else {
1842 // When the user is explicitly starting a process, then clear its
1843 // crash count so that we won't make it bad until they see at
1844 // least one crash dialog again, and make the process good again
1845 // if it had been bad.
1846 mProcessCrashTimes.remove(info.processName, info.uid);
1847 if (mBadProcesses.get(info.processName, info.uid) != null) {
1848 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1849 info.processName);
1850 mBadProcesses.remove(info.processName, info.uid);
1851 if (app != null) {
1852 app.bad = false;
1853 }
1854 }
1855 }
1856
1857 if (app == null) {
1858 app = newProcessRecordLocked(null, info, processName);
1859 mProcessNames.put(processName, info.uid, app);
1860 } else {
1861 // If this is a new package in the process, add the package to the list
1862 app.addPackage(info.packageName);
1863 }
1864
1865 // If the system is not ready yet, then hold off on starting this
1866 // process until it is.
1867 if (!mSystemReady
1868 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1869 if (!mProcessesOnHold.contains(app)) {
1870 mProcessesOnHold.add(app);
1871 }
1872 return app;
1873 }
1874
1875 startProcessLocked(app, hostingType, hostingNameStr);
1876 return (app.pid != 0) ? app : null;
1877 }
1878
1879 private final void startProcessLocked(ProcessRecord app,
1880 String hostingType, String hostingNameStr) {
1881 if (app.pid > 0 && app.pid != MY_PID) {
1882 synchronized (mPidsSelfLocked) {
1883 mPidsSelfLocked.remove(app.pid);
1884 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1885 }
1886 app.pid = 0;
1887 }
1888
1889 mProcessesOnHold.remove(app);
1890
1891 updateCpuStats();
1892
1893 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1894 mProcDeaths[0] = 0;
1895
1896 try {
1897 int uid = app.info.uid;
1898 int[] gids = null;
1899 try {
1900 gids = mContext.getPackageManager().getPackageGids(
1901 app.info.packageName);
1902 } catch (PackageManager.NameNotFoundException e) {
1903 Log.w(TAG, "Unable to retrieve gids", e);
1904 }
1905 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1906 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1907 && mTopComponent != null
1908 && app.processName.equals(mTopComponent.getPackageName())) {
1909 uid = 0;
1910 }
1911 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1912 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1913 uid = 0;
1914 }
1915 }
1916 int debugFlags = 0;
1917 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1918 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1919 }
1920 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1921 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1922 }
1923 if ("1".equals(SystemProperties.get("debug.assert"))) {
1924 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1925 }
1926 int pid = Process.start("android.app.ActivityThread",
1927 mSimpleProcessManagement ? app.processName : null, uid, uid,
1928 gids, debugFlags, null);
1929 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1930 synchronized (bs) {
1931 if (bs.isOnBattery()) {
1932 app.batteryStats.incStartsLocked();
1933 }
1934 }
1935
1936 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1937 app.processName, hostingType,
1938 hostingNameStr != null ? hostingNameStr : "");
1939
1940 if (app.persistent) {
1941 Watchdog.getInstance().processStarted(app, app.processName, pid);
1942 }
1943
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001944 StringBuilder buf = mStringBuilder;
1945 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001946 buf.append("Start proc ");
1947 buf.append(app.processName);
1948 buf.append(" for ");
1949 buf.append(hostingType);
1950 if (hostingNameStr != null) {
1951 buf.append(" ");
1952 buf.append(hostingNameStr);
1953 }
1954 buf.append(": pid=");
1955 buf.append(pid);
1956 buf.append(" uid=");
1957 buf.append(uid);
1958 buf.append(" gids={");
1959 if (gids != null) {
1960 for (int gi=0; gi<gids.length; gi++) {
1961 if (gi != 0) buf.append(", ");
1962 buf.append(gids[gi]);
1963
1964 }
1965 }
1966 buf.append("}");
1967 Log.i(TAG, buf.toString());
1968 if (pid == 0 || pid == MY_PID) {
1969 // Processes are being emulated with threads.
1970 app.pid = MY_PID;
1971 app.removed = false;
1972 mStartingProcesses.add(app);
1973 } else if (pid > 0) {
1974 app.pid = pid;
1975 app.removed = false;
1976 synchronized (mPidsSelfLocked) {
1977 this.mPidsSelfLocked.put(pid, app);
1978 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1979 msg.obj = app;
1980 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1981 }
1982 } else {
1983 app.pid = 0;
1984 RuntimeException e = new RuntimeException(
1985 "Failure starting process " + app.processName
1986 + ": returned pid=" + pid);
1987 Log.e(TAG, e.getMessage(), e);
1988 }
1989 } catch (RuntimeException e) {
1990 // XXX do better error recovery.
1991 app.pid = 0;
1992 Log.e(TAG, "Failure starting process " + app.processName, e);
1993 }
1994 }
1995
1996 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1997 if (mPausingActivity != null) {
1998 RuntimeException e = new RuntimeException();
1999 Log.e(TAG, "Trying to pause when pause is already pending for "
2000 + mPausingActivity, e);
2001 }
2002 HistoryRecord prev = mResumedActivity;
2003 if (prev == null) {
2004 RuntimeException e = new RuntimeException();
2005 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2006 resumeTopActivityLocked(null);
2007 return;
2008 }
2009 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2010 mResumedActivity = null;
2011 mPausingActivity = prev;
2012 mLastPausedActivity = prev;
2013 prev.state = ActivityState.PAUSING;
2014 prev.task.touchActiveTime();
2015
2016 updateCpuStats();
2017
2018 if (prev.app != null && prev.app.thread != null) {
2019 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2020 try {
2021 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2022 System.identityHashCode(prev),
2023 prev.shortComponentName);
2024 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2025 prev.configChangeFlags);
2026 updateUsageStats(prev, false);
2027 } catch (Exception e) {
2028 // Ignore exception, if process died other code will cleanup.
2029 Log.w(TAG, "Exception thrown during pause", e);
2030 mPausingActivity = null;
2031 mLastPausedActivity = null;
2032 }
2033 } else {
2034 mPausingActivity = null;
2035 mLastPausedActivity = null;
2036 }
2037
2038 // If we are not going to sleep, we want to ensure the device is
2039 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002040 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002041 mLaunchingActivity.acquire();
2042 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2043 // To be safe, don't allow the wake lock to be held for too long.
2044 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2045 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2046 }
2047 }
2048
2049
2050 if (mPausingActivity != null) {
2051 // Have the window manager pause its key dispatching until the new
2052 // activity has started. If we're pausing the activity just because
2053 // the screen is being turned off and the UI is sleeping, don't interrupt
2054 // key dispatch; the same activity will pick it up again on wakeup.
2055 if (!uiSleeping) {
2056 prev.pauseKeyDispatchingLocked();
2057 } else {
2058 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2059 }
2060
2061 // Schedule a pause timeout in case the app doesn't respond.
2062 // We don't give it much time because this directly impacts the
2063 // responsiveness seen by the user.
2064 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2065 msg.obj = prev;
2066 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2067 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2068 } else {
2069 // This activity failed to schedule the
2070 // pause, so just treat it as being paused now.
2071 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2072 resumeTopActivityLocked(null);
2073 }
2074 }
2075
2076 private final void completePauseLocked() {
2077 HistoryRecord prev = mPausingActivity;
2078 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2079
2080 if (prev != null) {
2081 if (prev.finishing) {
2082 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2083 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2084 } else if (prev.app != null) {
2085 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2086 if (prev.waitingVisible) {
2087 prev.waitingVisible = false;
2088 mWaitingVisibleActivities.remove(prev);
2089 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2090 TAG, "Complete pause, no longer waiting: " + prev);
2091 }
2092 if (prev.configDestroy) {
2093 // The previous is being paused because the configuration
2094 // is changing, which means it is actually stopping...
2095 // To juggle the fact that we are also starting a new
2096 // instance right now, we need to first completely stop
2097 // the current instance before starting the new one.
2098 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2099 destroyActivityLocked(prev, true);
2100 } else {
2101 mStoppingActivities.add(prev);
2102 if (mStoppingActivities.size() > 3) {
2103 // If we already have a few activities waiting to stop,
2104 // then give up on things going idle and start clearing
2105 // them out.
2106 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2107 Message msg = Message.obtain();
2108 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2109 mHandler.sendMessage(msg);
2110 }
2111 }
2112 } else {
2113 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2114 prev = null;
2115 }
2116 mPausingActivity = null;
2117 }
2118
Dianne Hackborn55280a92009-05-07 15:53:46 -07002119 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 resumeTopActivityLocked(prev);
2121 } else {
2122 if (mGoingToSleep.isHeld()) {
2123 mGoingToSleep.release();
2124 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002125 if (mShuttingDown) {
2126 notifyAll();
2127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 }
2129
2130 if (prev != null) {
2131 prev.resumeKeyDispatchingLocked();
2132 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002133
2134 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2135 long diff = 0;
2136 synchronized (mProcessStatsThread) {
2137 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2138 }
2139 if (diff > 0) {
2140 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2141 synchronized (bsi) {
2142 BatteryStatsImpl.Uid.Proc ps =
2143 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2144 prev.info.packageName);
2145 if (ps != null) {
2146 ps.addForegroundTimeLocked(diff);
2147 }
2148 }
2149 }
2150 }
2151 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 }
2153
2154 /**
2155 * Once we know that we have asked an application to put an activity in
2156 * the resumed state (either by launching it or explicitly telling it),
2157 * this function updates the rest of our state to match that fact.
2158 */
2159 private final void completeResumeLocked(HistoryRecord next) {
2160 next.idle = false;
2161 next.results = null;
2162 next.newIntents = null;
2163
2164 // schedule an idle timeout in case the app doesn't do it for us.
2165 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2166 msg.obj = next;
2167 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2168
2169 if (false) {
2170 // The activity was never told to pause, so just keep
2171 // things going as-is. To maintain our own state,
2172 // we need to emulate it coming back and saying it is
2173 // idle.
2174 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2175 msg.obj = next;
2176 mHandler.sendMessage(msg);
2177 }
2178
2179 next.thumbnail = null;
2180 setFocusedActivityLocked(next);
2181 next.resumeKeyDispatchingLocked();
2182 ensureActivitiesVisibleLocked(null, 0);
2183 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002184
2185 // Mark the point when the activity is resuming
2186 // TODO: To be more accurate, the mark should be before the onCreate,
2187 // not after the onResume. But for subsequent starts, onResume is fine.
2188 if (next.app != null) {
2189 synchronized (mProcessStatsThread) {
2190 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2191 }
2192 } else {
2193 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 }
2196
2197 /**
2198 * Make sure that all activities that need to be visible (that is, they
2199 * currently can be seen by the user) actually are.
2200 */
2201 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2202 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2203 if (DEBUG_VISBILITY) Log.v(
2204 TAG, "ensureActivitiesVisible behind " + top
2205 + " configChanges=0x" + Integer.toHexString(configChanges));
2206
2207 // If the top activity is not fullscreen, then we need to
2208 // make sure any activities under it are now visible.
2209 final int count = mHistory.size();
2210 int i = count-1;
2211 while (mHistory.get(i) != top) {
2212 i--;
2213 }
2214 HistoryRecord r;
2215 boolean behindFullscreen = false;
2216 for (; i>=0; i--) {
2217 r = (HistoryRecord)mHistory.get(i);
2218 if (DEBUG_VISBILITY) Log.v(
2219 TAG, "Make visible? " + r + " finishing=" + r.finishing
2220 + " state=" + r.state);
2221 if (r.finishing) {
2222 continue;
2223 }
2224
2225 final boolean doThisProcess = onlyThisProcess == null
2226 || onlyThisProcess.equals(r.processName);
2227
2228 // First: if this is not the current activity being started, make
2229 // sure it matches the current configuration.
2230 if (r != starting && doThisProcess) {
2231 ensureActivityConfigurationLocked(r, 0);
2232 }
2233
2234 if (r.app == null || r.app.thread == null) {
2235 if (onlyThisProcess == null
2236 || onlyThisProcess.equals(r.processName)) {
2237 // This activity needs to be visible, but isn't even
2238 // running... get it started, but don't resume it
2239 // at this point.
2240 if (DEBUG_VISBILITY) Log.v(
2241 TAG, "Start and freeze screen for " + r);
2242 if (r != starting) {
2243 r.startFreezingScreenLocked(r.app, configChanges);
2244 }
2245 if (!r.visible) {
2246 if (DEBUG_VISBILITY) Log.v(
2247 TAG, "Starting and making visible: " + r);
2248 mWindowManager.setAppVisibility(r, true);
2249 }
2250 if (r != starting) {
2251 startSpecificActivityLocked(r, false, false);
2252 }
2253 }
2254
2255 } else if (r.visible) {
2256 // If this activity is already visible, then there is nothing
2257 // else to do here.
2258 if (DEBUG_VISBILITY) Log.v(
2259 TAG, "Skipping: already visible at " + r);
2260 r.stopFreezingScreenLocked(false);
2261
2262 } else if (onlyThisProcess == null) {
2263 // This activity is not currently visible, but is running.
2264 // Tell it to become visible.
2265 r.visible = true;
2266 if (r.state != ActivityState.RESUMED && r != starting) {
2267 // If this activity is paused, tell it
2268 // to now show its window.
2269 if (DEBUG_VISBILITY) Log.v(
2270 TAG, "Making visible and scheduling visibility: " + r);
2271 try {
2272 mWindowManager.setAppVisibility(r, true);
2273 r.app.thread.scheduleWindowVisibility(r, true);
2274 r.stopFreezingScreenLocked(false);
2275 } catch (Exception e) {
2276 // Just skip on any failure; we'll make it
2277 // visible when it next restarts.
2278 Log.w(TAG, "Exception thrown making visibile: "
2279 + r.intent.getComponent(), e);
2280 }
2281 }
2282 }
2283
2284 // Aggregate current change flags.
2285 configChanges |= r.configChangeFlags;
2286
2287 if (r.fullscreen) {
2288 // At this point, nothing else needs to be shown
2289 if (DEBUG_VISBILITY) Log.v(
2290 TAG, "Stopping: fullscreen at " + r);
2291 behindFullscreen = true;
2292 i--;
2293 break;
2294 }
2295 }
2296
2297 // Now for any activities that aren't visible to the user, make
2298 // sure they no longer are keeping the screen frozen.
2299 while (i >= 0) {
2300 r = (HistoryRecord)mHistory.get(i);
2301 if (DEBUG_VISBILITY) Log.v(
2302 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2303 + " state=" + r.state
2304 + " behindFullscreen=" + behindFullscreen);
2305 if (!r.finishing) {
2306 if (behindFullscreen) {
2307 if (r.visible) {
2308 if (DEBUG_VISBILITY) Log.v(
2309 TAG, "Making invisible: " + r);
2310 r.visible = false;
2311 try {
2312 mWindowManager.setAppVisibility(r, false);
2313 if ((r.state == ActivityState.STOPPING
2314 || r.state == ActivityState.STOPPED)
2315 && r.app != null && r.app.thread != null) {
2316 if (DEBUG_VISBILITY) Log.v(
2317 TAG, "Scheduling invisibility: " + r);
2318 r.app.thread.scheduleWindowVisibility(r, false);
2319 }
2320 } catch (Exception e) {
2321 // Just skip on any failure; we'll make it
2322 // visible when it next restarts.
2323 Log.w(TAG, "Exception thrown making hidden: "
2324 + r.intent.getComponent(), e);
2325 }
2326 } else {
2327 if (DEBUG_VISBILITY) Log.v(
2328 TAG, "Already invisible: " + r);
2329 }
2330 } else if (r.fullscreen) {
2331 if (DEBUG_VISBILITY) Log.v(
2332 TAG, "Now behindFullscreen: " + r);
2333 behindFullscreen = true;
2334 }
2335 }
2336 i--;
2337 }
2338 }
2339
2340 /**
2341 * Version of ensureActivitiesVisible that can easily be called anywhere.
2342 */
2343 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2344 int configChanges) {
2345 HistoryRecord r = topRunningActivityLocked(null);
2346 if (r != null) {
2347 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2348 }
2349 }
2350
2351 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2352 if (resumed) {
2353 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2354 } else {
2355 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2356 }
2357 }
2358
2359 /**
2360 * Ensure that the top activity in the stack is resumed.
2361 *
2362 * @param prev The previously resumed activity, for when in the process
2363 * of pausing; can be null to call from elsewhere.
2364 *
2365 * @return Returns true if something is being resumed, or false if
2366 * nothing happened.
2367 */
2368 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2369 // Find the first activity that is not finishing.
2370 HistoryRecord next = topRunningActivityLocked(null);
2371
2372 // Remember how we'll process this pause/resume situation, and ensure
2373 // that the state is reset however we wind up proceeding.
2374 final boolean userLeaving = mUserLeaving;
2375 mUserLeaving = false;
2376
2377 if (next == null) {
2378 // There are no more activities! Let's just start up the
2379 // Launcher...
2380 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2381 && mTopAction == null) {
2382 // We are running in factory test mode, but unable to find
2383 // the factory test app, so just sit around displaying the
2384 // error message and don't try to start anything.
2385 return false;
2386 }
2387 Intent intent = new Intent(
2388 mTopAction,
2389 mTopData != null ? Uri.parse(mTopData) : null);
2390 intent.setComponent(mTopComponent);
2391 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2392 intent.addCategory(Intent.CATEGORY_HOME);
2393 }
2394 ActivityInfo aInfo =
2395 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002396 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 if (aInfo != null) {
2398 intent.setComponent(new ComponentName(
2399 aInfo.applicationInfo.packageName, aInfo.name));
2400 // Don't do this if the home app is currently being
2401 // instrumented.
2402 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2403 aInfo.applicationInfo.uid);
2404 if (app == null || app.instrumentationClass == null) {
2405 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2406 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002407 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002408 }
2409 }
2410 return true;
2411 }
2412
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002413 next.delayedResume = false;
2414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002415 // If the top activity is the resumed one, nothing to do.
2416 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2417 // Make sure we have executed any pending transitions, since there
2418 // should be nothing left to do at this point.
2419 mWindowManager.executeAppTransition();
2420 return false;
2421 }
2422
2423 // If we are sleeping, and there is no resumed activity, and the top
2424 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002425 if ((mSleeping || mShuttingDown)
2426 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002427 // Make sure we have executed any pending transitions, since there
2428 // should be nothing left to do at this point.
2429 mWindowManager.executeAppTransition();
2430 return false;
2431 }
2432
2433 // The activity may be waiting for stop, but that is no longer
2434 // appropriate for it.
2435 mStoppingActivities.remove(next);
2436 mWaitingVisibleActivities.remove(next);
2437
2438 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2439
2440 // If we are currently pausing an activity, then don't do anything
2441 // until that is done.
2442 if (mPausingActivity != null) {
2443 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2444 return false;
2445 }
2446
2447 // We need to start pausing the current activity so the top one
2448 // can be resumed...
2449 if (mResumedActivity != null) {
2450 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2451 startPausingLocked(userLeaving, false);
2452 return true;
2453 }
2454
2455 if (prev != null && prev != next) {
2456 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2457 prev.waitingVisible = true;
2458 mWaitingVisibleActivities.add(prev);
2459 if (DEBUG_SWITCH) Log.v(
2460 TAG, "Resuming top, waiting visible to hide: " + prev);
2461 } else {
2462 // The next activity is already visible, so hide the previous
2463 // activity's windows right now so we can show the new one ASAP.
2464 // We only do this if the previous is finishing, which should mean
2465 // it is on top of the one being resumed so hiding it quickly
2466 // is good. Otherwise, we want to do the normal route of allowing
2467 // the resumed activity to be shown so we can decide if the
2468 // previous should actually be hidden depending on whether the
2469 // new one is found to be full-screen or not.
2470 if (prev.finishing) {
2471 mWindowManager.setAppVisibility(prev, false);
2472 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2473 + prev + ", waitingVisible="
2474 + (prev != null ? prev.waitingVisible : null)
2475 + ", nowVisible=" + next.nowVisible);
2476 } else {
2477 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2478 + prev + ", waitingVisible="
2479 + (prev != null ? prev.waitingVisible : null)
2480 + ", nowVisible=" + next.nowVisible);
2481 }
2482 }
2483 }
2484
2485 // We are starting up the next activity, so tell the window manager
2486 // that the previous one will be hidden soon. This way it can know
2487 // to ignore it when computing the desired screen orientation.
2488 if (prev != null) {
2489 if (prev.finishing) {
2490 if (DEBUG_TRANSITION) Log.v(TAG,
2491 "Prepare close transition: prev=" + prev);
2492 mWindowManager.prepareAppTransition(prev.task == next.task
2493 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2494 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2495 mWindowManager.setAppWillBeHidden(prev);
2496 mWindowManager.setAppVisibility(prev, false);
2497 } else {
2498 if (DEBUG_TRANSITION) Log.v(TAG,
2499 "Prepare open transition: prev=" + prev);
2500 mWindowManager.prepareAppTransition(prev.task == next.task
2501 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2502 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2503 }
2504 if (false) {
2505 mWindowManager.setAppWillBeHidden(prev);
2506 mWindowManager.setAppVisibility(prev, false);
2507 }
2508 } else if (mHistory.size() > 1) {
2509 if (DEBUG_TRANSITION) Log.v(TAG,
2510 "Prepare open transition: no previous");
2511 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2512 }
2513
2514 if (next.app != null && next.app.thread != null) {
2515 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2516
2517 // This activity is now becoming visible.
2518 mWindowManager.setAppVisibility(next, true);
2519
2520 HistoryRecord lastResumedActivity = mResumedActivity;
2521 ActivityState lastState = next.state;
2522
2523 updateCpuStats();
2524
2525 next.state = ActivityState.RESUMED;
2526 mResumedActivity = next;
2527 next.task.touchActiveTime();
2528 updateLRUListLocked(next.app, true);
2529 updateLRUListLocked(next);
2530
2531 // Have the window manager re-evaluate the orientation of
2532 // the screen based on the new activity order.
2533 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002534 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 next.mayFreezeScreenLocked(next.app) ? next : null);
2536 if (config != null) {
2537 next.frozenBeforeDestroy = true;
2538 }
2539 if (!updateConfigurationLocked(config, next)) {
2540 // The configuration update wasn't able to keep the existing
2541 // instance of the activity, and instead started a new one.
2542 // We should be all done, but let's just make sure our activity
2543 // is still at the top and schedule another run if something
2544 // weird happened.
2545 HistoryRecord nextNext = topRunningActivityLocked(null);
2546 if (DEBUG_SWITCH) Log.i(TAG,
2547 "Activity config changed during resume: " + next
2548 + ", new next: " + nextNext);
2549 if (nextNext != next) {
2550 // Do over!
2551 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2552 }
2553 mWindowManager.executeAppTransition();
2554 return true;
2555 }
2556
2557 try {
2558 // Deliver all pending results.
2559 ArrayList a = next.results;
2560 if (a != null) {
2561 final int N = a.size();
2562 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002563 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002564 TAG, "Delivering results to " + next
2565 + ": " + a);
2566 next.app.thread.scheduleSendResult(next, a);
2567 }
2568 }
2569
2570 if (next.newIntents != null) {
2571 next.app.thread.scheduleNewIntent(next.newIntents, next);
2572 }
2573
2574 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2575 System.identityHashCode(next),
2576 next.task.taskId, next.shortComponentName);
2577 updateUsageStats(next, true);
2578
2579 next.app.thread.scheduleResumeActivity(next,
2580 isNextTransitionForward());
2581 pauseIfSleepingLocked();
2582
2583 } catch (Exception e) {
2584 // Whoops, need to restart this activity!
2585 next.state = lastState;
2586 mResumedActivity = lastResumedActivity;
2587 if (Config.LOGD) Log.d(TAG,
2588 "Restarting because process died: " + next);
2589 if (!next.hasBeenLaunched) {
2590 next.hasBeenLaunched = true;
2591 } else {
2592 if (SHOW_APP_STARTING_ICON) {
2593 mWindowManager.setAppStartingWindow(
2594 next, next.packageName, next.theme,
2595 next.nonLocalizedLabel,
2596 next.labelRes, next.icon, null, true);
2597 }
2598 }
2599 startSpecificActivityLocked(next, true, false);
2600 return true;
2601 }
2602
2603 // From this point on, if something goes wrong there is no way
2604 // to recover the activity.
2605 try {
2606 next.visible = true;
2607 completeResumeLocked(next);
2608 } catch (Exception e) {
2609 // If any exception gets thrown, toss away this
2610 // activity and try the next one.
2611 Log.w(TAG, "Exception thrown during resume of " + next, e);
2612 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2613 "resume-exception");
2614 return true;
2615 }
2616
2617 // Didn't need to use the icicle, and it is now out of date.
2618 next.icicle = null;
2619 next.haveState = false;
2620 next.stopped = false;
2621
2622 } else {
2623 // Whoops, need to restart this activity!
2624 if (!next.hasBeenLaunched) {
2625 next.hasBeenLaunched = true;
2626 } else {
2627 if (SHOW_APP_STARTING_ICON) {
2628 mWindowManager.setAppStartingWindow(
2629 next, next.packageName, next.theme,
2630 next.nonLocalizedLabel,
2631 next.labelRes, next.icon, null, true);
2632 }
2633 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2634 }
2635 startSpecificActivityLocked(next, true, true);
2636 }
2637
2638 return true;
2639 }
2640
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002641 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2642 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 final int NH = mHistory.size();
2644
2645 int addPos = -1;
2646
2647 if (!newTask) {
2648 // If starting in an existing task, find where that is...
2649 HistoryRecord next = null;
2650 boolean startIt = true;
2651 for (int i = NH-1; i >= 0; i--) {
2652 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2653 if (p.finishing) {
2654 continue;
2655 }
2656 if (p.task == r.task) {
2657 // Here it is! Now, if this is not yet visible to the
2658 // user, then just add it without starting; it will
2659 // get started when the user navigates back to it.
2660 addPos = i+1;
2661 if (!startIt) {
2662 mHistory.add(addPos, r);
2663 r.inHistory = true;
2664 r.task.numActivities++;
2665 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2666 r.info.screenOrientation, r.fullscreen);
2667 if (VALIDATE_TOKENS) {
2668 mWindowManager.validateAppTokens(mHistory);
2669 }
2670 return;
2671 }
2672 break;
2673 }
2674 if (p.fullscreen) {
2675 startIt = false;
2676 }
2677 next = p;
2678 }
2679 }
2680
2681 // Place a new activity at top of stack, so it is next to interact
2682 // with the user.
2683 if (addPos < 0) {
2684 addPos = mHistory.size();
2685 }
2686
2687 // If we are not placing the new activity frontmost, we do not want
2688 // to deliver the onUserLeaving callback to the actual frontmost
2689 // activity
2690 if (addPos < NH) {
2691 mUserLeaving = false;
2692 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2693 }
2694
2695 // Slot the activity into the history stack and proceed
2696 mHistory.add(addPos, r);
2697 r.inHistory = true;
2698 r.frontOfTask = newTask;
2699 r.task.numActivities++;
2700 if (NH > 0) {
2701 // We want to show the starting preview window if we are
2702 // switching to a new task, or the next activity's process is
2703 // not currently running.
2704 boolean showStartingIcon = newTask;
2705 ProcessRecord proc = r.app;
2706 if (proc == null) {
2707 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2708 }
2709 if (proc == null || proc.thread == null) {
2710 showStartingIcon = true;
2711 }
2712 if (DEBUG_TRANSITION) Log.v(TAG,
2713 "Prepare open transition: starting " + r);
2714 mWindowManager.prepareAppTransition(newTask
2715 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2716 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2717 mWindowManager.addAppToken(
2718 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2719 boolean doShow = true;
2720 if (newTask) {
2721 // Even though this activity is starting fresh, we still need
2722 // to reset it to make sure we apply affinities to move any
2723 // existing activities from other tasks in to it.
2724 // If the caller has requested that the target task be
2725 // reset, then do so.
2726 if ((r.intent.getFlags()
2727 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2728 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002729 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 }
2731 }
2732 if (SHOW_APP_STARTING_ICON && doShow) {
2733 // Figure out if we are transitioning from another activity that is
2734 // "has the same starting icon" as the next one. This allows the
2735 // window manager to keep the previous window it had previously
2736 // created, if it still had one.
2737 HistoryRecord prev = mResumedActivity;
2738 if (prev != null) {
2739 // We don't want to reuse the previous starting preview if:
2740 // (1) The current activity is in a different task.
2741 if (prev.task != r.task) prev = null;
2742 // (2) The current activity is already displayed.
2743 else if (prev.nowVisible) prev = null;
2744 }
2745 mWindowManager.setAppStartingWindow(
2746 r, r.packageName, r.theme, r.nonLocalizedLabel,
2747 r.labelRes, r.icon, prev, showStartingIcon);
2748 }
2749 } else {
2750 // If this is the first activity, don't do any fancy animations,
2751 // because there is nothing for it to animate on top of.
2752 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2753 r.info.screenOrientation, r.fullscreen);
2754 }
2755 if (VALIDATE_TOKENS) {
2756 mWindowManager.validateAppTokens(mHistory);
2757 }
2758
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002759 if (doResume) {
2760 resumeTopActivityLocked(null);
2761 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002762 }
2763
2764 /**
2765 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002766 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2767 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002768 * an instance of that activity in the stack and, if found, finish all
2769 * activities on top of it and return the instance.
2770 *
2771 * @param newR Description of the new activity being started.
2772 * @return Returns the old activity that should be continue to be used,
2773 * or null if none was found.
2774 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002775 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002776 HistoryRecord newR, boolean doClear) {
2777 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002778
2779 // First find the requested task.
2780 while (i > 0) {
2781 i--;
2782 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2783 if (r.task.taskId == taskId) {
2784 i++;
2785 break;
2786 }
2787 }
2788
2789 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 while (i > 0) {
2791 i--;
2792 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2793 if (r.finishing) {
2794 continue;
2795 }
2796 if (r.task.taskId != taskId) {
2797 return null;
2798 }
2799 if (r.realActivity.equals(newR.realActivity)) {
2800 // Here it is! Now finish everything in front...
2801 HistoryRecord ret = r;
2802 if (doClear) {
2803 while (i < (mHistory.size()-1)) {
2804 i++;
2805 r = (HistoryRecord)mHistory.get(i);
2806 if (r.finishing) {
2807 continue;
2808 }
2809 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2810 null, "clear")) {
2811 i--;
2812 }
2813 }
2814 }
2815
2816 // Finally, if this is a normal launch mode (that is, not
2817 // expecting onNewIntent()), then we will finish the current
2818 // instance of the activity so a new fresh one can be started.
2819 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2820 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002821 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002822 if (index >= 0) {
2823 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2824 null, "clear");
2825 }
2826 return null;
2827 }
2828 }
2829
2830 return ret;
2831 }
2832 }
2833
2834 return null;
2835 }
2836
2837 /**
2838 * Find the activity in the history stack within the given task. Returns
2839 * the index within the history at which it's found, or < 0 if not found.
2840 */
2841 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2842 int i = mHistory.size();
2843 while (i > 0) {
2844 i--;
2845 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2846 if (candidate.task.taskId != task) {
2847 break;
2848 }
2849 if (candidate.realActivity.equals(r.realActivity)) {
2850 return i;
2851 }
2852 }
2853
2854 return -1;
2855 }
2856
2857 /**
2858 * Reorder the history stack so that the activity at the given index is
2859 * brought to the front.
2860 */
2861 private final HistoryRecord moveActivityToFrontLocked(int where) {
2862 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2863 int top = mHistory.size();
2864 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2865 mHistory.add(top, newTop);
2866 oldTop.frontOfTask = false;
2867 newTop.frontOfTask = true;
2868 return newTop;
2869 }
2870
2871 /**
2872 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2873 * method will be called at the proper time.
2874 */
2875 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2876 boolean sent = false;
2877 if (r.state == ActivityState.RESUMED
2878 && r.app != null && r.app.thread != null) {
2879 try {
2880 ArrayList<Intent> ar = new ArrayList<Intent>();
2881 ar.add(new Intent(intent));
2882 r.app.thread.scheduleNewIntent(ar, r);
2883 sent = true;
2884 } catch (Exception e) {
2885 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2886 }
2887 }
2888 if (!sent) {
2889 r.addNewIntentLocked(new Intent(intent));
2890 }
2891 }
2892
2893 private final void logStartActivity(int tag, HistoryRecord r,
2894 TaskRecord task) {
2895 EventLog.writeEvent(tag,
2896 System.identityHashCode(r), task.taskId,
2897 r.shortComponentName, r.intent.getAction(),
2898 r.intent.getType(), r.intent.getDataString(),
2899 r.intent.getFlags());
2900 }
2901
2902 private final int startActivityLocked(IApplicationThread caller,
2903 Intent intent, String resolvedType,
2904 Uri[] grantedUriPermissions,
2905 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2906 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002907 int callingPid, int callingUid, boolean onlyIfNeeded,
2908 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002909 Log.i(TAG, "Starting activity: " + intent);
2910
2911 HistoryRecord sourceRecord = null;
2912 HistoryRecord resultRecord = null;
2913 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002914 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07002915 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002916 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2917 if (index >= 0) {
2918 sourceRecord = (HistoryRecord)mHistory.get(index);
2919 if (requestCode >= 0 && !sourceRecord.finishing) {
2920 resultRecord = sourceRecord;
2921 }
2922 }
2923 }
2924
2925 int launchFlags = intent.getFlags();
2926
2927 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2928 && sourceRecord != null) {
2929 // Transfer the result target from the source activity to the new
2930 // one being started, including any failures.
2931 if (requestCode >= 0) {
2932 return START_FORWARD_AND_REQUEST_CONFLICT;
2933 }
2934 resultRecord = sourceRecord.resultTo;
2935 resultWho = sourceRecord.resultWho;
2936 requestCode = sourceRecord.requestCode;
2937 sourceRecord.resultTo = null;
2938 if (resultRecord != null) {
2939 resultRecord.removeResultsLocked(
2940 sourceRecord, resultWho, requestCode);
2941 }
2942 }
2943
2944 int err = START_SUCCESS;
2945
2946 if (intent.getComponent() == null) {
2947 // We couldn't find a class that can handle the given Intent.
2948 // That's the end of that!
2949 err = START_INTENT_NOT_RESOLVED;
2950 }
2951
2952 if (err == START_SUCCESS && aInfo == null) {
2953 // We couldn't find the specific class specified in the Intent.
2954 // Also the end of the line.
2955 err = START_CLASS_NOT_FOUND;
2956 }
2957
2958 ProcessRecord callerApp = null;
2959 if (err == START_SUCCESS && caller != null) {
2960 callerApp = getRecordForAppLocked(caller);
2961 if (callerApp != null) {
2962 callingPid = callerApp.pid;
2963 callingUid = callerApp.info.uid;
2964 } else {
2965 Log.w(TAG, "Unable to find app for caller " + caller
2966 + " (pid=" + callingPid + ") when starting: "
2967 + intent.toString());
2968 err = START_PERMISSION_DENIED;
2969 }
2970 }
2971
2972 if (err != START_SUCCESS) {
2973 if (resultRecord != null) {
2974 sendActivityResultLocked(-1,
2975 resultRecord, resultWho, requestCode,
2976 Activity.RESULT_CANCELED, null);
2977 }
2978 return err;
2979 }
2980
2981 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2982 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2983 if (perm != PackageManager.PERMISSION_GRANTED) {
2984 if (resultRecord != null) {
2985 sendActivityResultLocked(-1,
2986 resultRecord, resultWho, requestCode,
2987 Activity.RESULT_CANCELED, null);
2988 }
2989 String msg = "Permission Denial: starting " + intent.toString()
2990 + " from " + callerApp + " (pid=" + callingPid
2991 + ", uid=" + callingUid + ")"
2992 + " requires " + aInfo.permission;
2993 Log.w(TAG, msg);
2994 throw new SecurityException(msg);
2995 }
2996
2997 if (mWatcher != null) {
2998 boolean abort = false;
2999 try {
3000 // The Intent we give to the watcher has the extra data
3001 // stripped off, since it can contain private information.
3002 Intent watchIntent = intent.cloneFilter();
3003 abort = !mWatcher.activityStarting(watchIntent,
3004 aInfo.applicationInfo.packageName);
3005 } catch (RemoteException e) {
3006 mWatcher = null;
3007 }
3008
3009 if (abort) {
3010 if (resultRecord != null) {
3011 sendActivityResultLocked(-1,
3012 resultRecord, resultWho, requestCode,
3013 Activity.RESULT_CANCELED, null);
3014 }
3015 // We pretend to the caller that it was really started, but
3016 // they will just get a cancel result.
3017 return START_SUCCESS;
3018 }
3019 }
3020
3021 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3022 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003023 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003025 if (mResumedActivity == null
3026 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3027 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3028 PendingActivityLaunch pal = new PendingActivityLaunch();
3029 pal.r = r;
3030 pal.sourceRecord = sourceRecord;
3031 pal.grantedUriPermissions = grantedUriPermissions;
3032 pal.grantedMode = grantedMode;
3033 pal.onlyIfNeeded = onlyIfNeeded;
3034 mPendingActivityLaunches.add(pal);
3035 return START_SWITCHES_CANCELED;
3036 }
3037 }
3038
3039 if (mDidAppSwitch) {
3040 // This is the second allowed switch since we stopped switches,
3041 // so now just generally allow switches. Use case: user presses
3042 // home (switches disabled, switch to home, mDidAppSwitch now true);
3043 // user taps a home icon (coming from home so allowed, we hit here
3044 // and now allow anyone to switch again).
3045 mAppSwitchesAllowedTime = 0;
3046 } else {
3047 mDidAppSwitch = true;
3048 }
3049
3050 doPendingActivityLaunchesLocked(false);
3051
3052 return startActivityUncheckedLocked(r, sourceRecord,
3053 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3054 }
3055
3056 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3057 final int N = mPendingActivityLaunches.size();
3058 if (N <= 0) {
3059 return;
3060 }
3061 for (int i=0; i<N; i++) {
3062 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3063 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3064 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3065 doResume && i == (N-1));
3066 }
3067 mPendingActivityLaunches.clear();
3068 }
3069
3070 private final int startActivityUncheckedLocked(HistoryRecord r,
3071 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3072 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3073 final Intent intent = r.intent;
3074 final int callingUid = r.launchedFromUid;
3075
3076 int launchFlags = intent.getFlags();
3077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003078 // We'll invoke onUserLeaving before onPause only if the launching
3079 // activity did not explicitly state that this is an automated launch.
3080 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3081 if (DEBUG_USER_LEAVING) Log.v(TAG,
3082 "startActivity() => mUserLeaving=" + mUserLeaving);
3083
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003084 // If the caller has asked not to resume at this point, we make note
3085 // of this in the record so that we can skip it when trying to find
3086 // the top running activity.
3087 if (!doResume) {
3088 r.delayedResume = true;
3089 }
3090
3091 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3092 != 0 ? r : null;
3093
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003094 // If the onlyIfNeeded flag is set, then we can do this if the activity
3095 // being launched is the same as the one making the call... or, as
3096 // a special case, if we do not know the caller then we count the
3097 // current top activity as the caller.
3098 if (onlyIfNeeded) {
3099 HistoryRecord checkedCaller = sourceRecord;
3100 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003101 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 }
3103 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3104 // Caller is not the same as launcher, so always needed.
3105 onlyIfNeeded = false;
3106 }
3107 }
3108
3109 if (grantedUriPermissions != null && callingUid > 0) {
3110 for (int i=0; i<grantedUriPermissions.length; i++) {
3111 grantUriPermissionLocked(callingUid, r.packageName,
3112 grantedUriPermissions[i], grantedMode, r);
3113 }
3114 }
3115
3116 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3117 intent, r);
3118
3119 if (sourceRecord == null) {
3120 // This activity is not being started from another... in this
3121 // case we -always- start a new task.
3122 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3123 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3124 + intent);
3125 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3126 }
3127 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3128 // The original activity who is starting us is running as a single
3129 // instance... this new activity it is starting must go on its
3130 // own task.
3131 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3132 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3133 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3134 // The activity being started is a single instance... it always
3135 // gets launched into its own task.
3136 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3137 }
3138
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003139 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003140 // For whatever reason this activity is being launched into a new
3141 // task... yet the caller has requested a result back. Well, that
3142 // is pretty messed up, so instead immediately send back a cancel
3143 // and let the new task continue launched as normal without a
3144 // dependency on its originator.
3145 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3146 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003147 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 Activity.RESULT_CANCELED, null);
3149 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 }
3151
3152 boolean addingToTask = false;
3153 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3154 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3155 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3156 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3157 // If bring to front is requested, and no result is requested, and
3158 // we can find a task that was started with this same
3159 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003160 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 // See if there is a task to bring to the front. If this is
3162 // a SINGLE_INSTANCE activity, there can be one and only one
3163 // instance of it in the history, and it is always in its own
3164 // unique task, so we do a special search.
3165 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3166 ? findTaskLocked(intent, r.info)
3167 : findActivityLocked(intent, r.info);
3168 if (taskTop != null) {
3169 if (taskTop.task.intent == null) {
3170 // This task was started because of movement of
3171 // the activity based on affinity... now that we
3172 // are actually launching it, we can assign the
3173 // base intent.
3174 taskTop.task.setIntent(intent, r.info);
3175 }
3176 // If the target task is not in the front, then we need
3177 // to bring it to the front... except... well, with
3178 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3179 // to have the same behavior as if a new instance was
3180 // being started, which means not bringing it to the front
3181 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003182 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 if (curTop.task != taskTop.task) {
3184 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3185 boolean callerAtFront = sourceRecord == null
3186 || curTop.task == sourceRecord.task;
3187 if (callerAtFront) {
3188 // We really do want to push this one into the
3189 // user's face, right now.
3190 moveTaskToFrontLocked(taskTop.task);
3191 }
3192 }
3193 // If the caller has requested that the target task be
3194 // reset, then do so.
3195 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3196 taskTop = resetTaskIfNeededLocked(taskTop, r);
3197 }
3198 if (onlyIfNeeded) {
3199 // We don't need to start a new activity, and
3200 // the client said not to do anything if that
3201 // is the case, so this is it! And for paranoia, make
3202 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003203 if (doResume) {
3204 resumeTopActivityLocked(null);
3205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 return START_RETURN_INTENT_TO_CALLER;
3207 }
3208 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3209 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3210 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3211 // In this situation we want to remove all activities
3212 // from the task up to the one being started. In most
3213 // cases this means we are resetting the task to its
3214 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003215 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 taskTop.task.taskId, r, true);
3217 if (top != null) {
3218 if (top.frontOfTask) {
3219 // Activity aliases may mean we use different
3220 // intents for the top activity, so make sure
3221 // the task now has the identity of the new
3222 // intent.
3223 top.task.setIntent(r.intent, r.info);
3224 }
3225 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3226 deliverNewIntentLocked(top, r.intent);
3227 } else {
3228 // A special case: we need to
3229 // start the activity because it is not currently
3230 // running, and the caller has asked to clear the
3231 // current task to have this activity at the top.
3232 addingToTask = true;
3233 // Now pretend like this activity is being started
3234 // by the top of its task, so it is put in the
3235 // right place.
3236 sourceRecord = taskTop;
3237 }
3238 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3239 // In this case the top activity on the task is the
3240 // same as the one being launched, so we take that
3241 // as a request to bring the task to the foreground.
3242 // If the top activity in the task is the root
3243 // activity, deliver this new intent to it if it
3244 // desires.
3245 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3246 && taskTop.realActivity.equals(r.realActivity)) {
3247 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3248 if (taskTop.frontOfTask) {
3249 taskTop.task.setIntent(r.intent, r.info);
3250 }
3251 deliverNewIntentLocked(taskTop, r.intent);
3252 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3253 // In this case we are launching the root activity
3254 // of the task, but with a different intent. We
3255 // should start a new instance on top.
3256 addingToTask = true;
3257 sourceRecord = taskTop;
3258 }
3259 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3260 // In this case an activity is being launched in to an
3261 // existing task, without resetting that task. This
3262 // is typically the situation of launching an activity
3263 // from a notification or shortcut. We want to place
3264 // the new activity on top of the current task.
3265 addingToTask = true;
3266 sourceRecord = taskTop;
3267 } else if (!taskTop.task.rootWasReset) {
3268 // In this case we are launching in to an existing task
3269 // that has not yet been started from its front door.
3270 // The current task has been brought to the front.
3271 // Ideally, we'd probably like to place this new task
3272 // at the bottom of its stack, but that's a little hard
3273 // to do with the current organization of the code so
3274 // for now we'll just drop it.
3275 taskTop.task.setIntent(r.intent, r.info);
3276 }
3277 if (!addingToTask) {
3278 // We didn't do anything... but it was needed (a.k.a., client
3279 // don't use that intent!) And for paranoia, make
3280 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003281 if (doResume) {
3282 resumeTopActivityLocked(null);
3283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 return START_TASK_TO_FRONT;
3285 }
3286 }
3287 }
3288 }
3289
3290 //String uri = r.intent.toURI();
3291 //Intent intent2 = new Intent(uri);
3292 //Log.i(TAG, "Given intent: " + r.intent);
3293 //Log.i(TAG, "URI is: " + uri);
3294 //Log.i(TAG, "To intent: " + intent2);
3295
3296 if (r.packageName != null) {
3297 // If the activity being launched is the same as the one currently
3298 // at the top, then we need to check if it should only be launched
3299 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003300 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3301 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003302 if (top.realActivity.equals(r.realActivity)) {
3303 if (top.app != null && top.app.thread != null) {
3304 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3305 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3306 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3307 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3308 // For paranoia, make sure we have correctly
3309 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003310 if (doResume) {
3311 resumeTopActivityLocked(null);
3312 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 if (onlyIfNeeded) {
3314 // We don't need to start a new activity, and
3315 // the client said not to do anything if that
3316 // is the case, so this is it!
3317 return START_RETURN_INTENT_TO_CALLER;
3318 }
3319 deliverNewIntentLocked(top, r.intent);
3320 return START_DELIVERED_TO_TOP;
3321 }
3322 }
3323 }
3324 }
3325
3326 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003327 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003329 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003330 Activity.RESULT_CANCELED, null);
3331 }
3332 return START_CLASS_NOT_FOUND;
3333 }
3334
3335 boolean newTask = false;
3336
3337 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003338 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003339 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3340 // todo: should do better management of integers.
3341 mCurTask++;
3342 if (mCurTask <= 0) {
3343 mCurTask = 1;
3344 }
3345 r.task = new TaskRecord(mCurTask, r.info, intent,
3346 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3347 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3348 + " in new task " + r.task);
3349 newTask = true;
3350 addRecentTask(r.task);
3351
3352 } else if (sourceRecord != null) {
3353 if (!addingToTask &&
3354 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3355 // In this case, we are adding the activity to an existing
3356 // task, but the caller has asked to clear that task if the
3357 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003358 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 sourceRecord.task.taskId, r, true);
3360 if (top != null) {
3361 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3362 deliverNewIntentLocked(top, r.intent);
3363 // For paranoia, make sure we have correctly
3364 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003365 if (doResume) {
3366 resumeTopActivityLocked(null);
3367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 return START_DELIVERED_TO_TOP;
3369 }
3370 } else if (!addingToTask &&
3371 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3372 // In this case, we are launching an activity in our own task
3373 // that may already be running somewhere in the history, and
3374 // we want to shuffle it to the front of the stack if so.
3375 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3376 if (where >= 0) {
3377 HistoryRecord top = moveActivityToFrontLocked(where);
3378 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3379 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003380 if (doResume) {
3381 resumeTopActivityLocked(null);
3382 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003383 return START_DELIVERED_TO_TOP;
3384 }
3385 }
3386 // An existing activity is starting this new activity, so we want
3387 // to keep the new one in the same task as the one that is starting
3388 // it.
3389 r.task = sourceRecord.task;
3390 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3391 + " in existing task " + r.task);
3392
3393 } else {
3394 // This not being started from an existing activity, and not part
3395 // of a new task... just put it in the top task, though these days
3396 // this case should never happen.
3397 final int N = mHistory.size();
3398 HistoryRecord prev =
3399 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3400 r.task = prev != null
3401 ? prev.task
3402 : new TaskRecord(mCurTask, r.info, intent,
3403 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3404 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3405 + " in new guessed " + r.task);
3406 }
3407 if (newTask) {
3408 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3409 }
3410 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003411 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 return START_SUCCESS;
3413 }
3414
3415 public final int startActivity(IApplicationThread caller,
3416 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3417 int grantedMode, IBinder resultTo,
3418 String resultWho, int requestCode, boolean onlyIfNeeded,
3419 boolean debug) {
3420 // Refuse possible leaked file descriptors
3421 if (intent != null && intent.hasFileDescriptors()) {
3422 throw new IllegalArgumentException("File descriptors passed in Intent");
3423 }
3424
The Android Open Source Project4df24232009-03-05 14:34:35 -08003425 final boolean componentSpecified = intent.getComponent() != null;
3426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 // Don't modify the client's object!
3428 intent = new Intent(intent);
3429
3430 // Collect information about the target of the Intent.
3431 // Must do this before locking, because resolving the intent
3432 // may require launching a process to run its content provider.
3433 ActivityInfo aInfo;
3434 try {
3435 ResolveInfo rInfo =
3436 ActivityThread.getPackageManager().resolveIntent(
3437 intent, resolvedType,
3438 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003439 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 aInfo = rInfo != null ? rInfo.activityInfo : null;
3441 } catch (RemoteException e) {
3442 aInfo = null;
3443 }
3444
3445 if (aInfo != null) {
3446 // Store the found target back into the intent, because now that
3447 // we have it we never want to do this again. For example, if the
3448 // user navigates back to this point in the history, we should
3449 // always restart the exact same activity.
3450 intent.setComponent(new ComponentName(
3451 aInfo.applicationInfo.packageName, aInfo.name));
3452
3453 // Don't debug things in the system process
3454 if (debug) {
3455 if (!aInfo.processName.equals("system")) {
3456 setDebugApp(aInfo.processName, true, false);
3457 }
3458 }
3459 }
3460
3461 synchronized(this) {
3462 final long origId = Binder.clearCallingIdentity();
3463 int res = startActivityLocked(caller, intent, resolvedType,
3464 grantedUriPermissions, grantedMode, aInfo,
3465 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003466 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003467 Binder.restoreCallingIdentity(origId);
3468 return res;
3469 }
3470 }
3471
3472 public boolean startNextMatchingActivity(IBinder callingActivity,
3473 Intent intent) {
3474 // Refuse possible leaked file descriptors
3475 if (intent != null && intent.hasFileDescriptors() == true) {
3476 throw new IllegalArgumentException("File descriptors passed in Intent");
3477 }
3478
3479 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003480 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003481 if (index < 0) {
3482 return false;
3483 }
3484 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3485 if (r.app == null || r.app.thread == null) {
3486 // The caller is not running... d'oh!
3487 return false;
3488 }
3489 intent = new Intent(intent);
3490 // The caller is not allowed to change the data.
3491 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3492 // And we are resetting to find the next component...
3493 intent.setComponent(null);
3494
3495 ActivityInfo aInfo = null;
3496 try {
3497 List<ResolveInfo> resolves =
3498 ActivityThread.getPackageManager().queryIntentActivities(
3499 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003500 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003501
3502 // Look for the original activity in the list...
3503 final int N = resolves != null ? resolves.size() : 0;
3504 for (int i=0; i<N; i++) {
3505 ResolveInfo rInfo = resolves.get(i);
3506 if (rInfo.activityInfo.packageName.equals(r.packageName)
3507 && rInfo.activityInfo.name.equals(r.info.name)) {
3508 // We found the current one... the next matching is
3509 // after it.
3510 i++;
3511 if (i<N) {
3512 aInfo = resolves.get(i).activityInfo;
3513 }
3514 break;
3515 }
3516 }
3517 } catch (RemoteException e) {
3518 }
3519
3520 if (aInfo == null) {
3521 // Nobody who is next!
3522 return false;
3523 }
3524
3525 intent.setComponent(new ComponentName(
3526 aInfo.applicationInfo.packageName, aInfo.name));
3527 intent.setFlags(intent.getFlags()&~(
3528 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3529 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3530 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3531 Intent.FLAG_ACTIVITY_NEW_TASK));
3532
3533 // Okay now we need to start the new activity, replacing the
3534 // currently running activity. This is a little tricky because
3535 // we want to start the new one as if the current one is finished,
3536 // but not finish the current one first so that there is no flicker.
3537 // And thus...
3538 final boolean wasFinishing = r.finishing;
3539 r.finishing = true;
3540
3541 // Propagate reply information over to the new activity.
3542 final HistoryRecord resultTo = r.resultTo;
3543 final String resultWho = r.resultWho;
3544 final int requestCode = r.requestCode;
3545 r.resultTo = null;
3546 if (resultTo != null) {
3547 resultTo.removeResultsLocked(r, resultWho, requestCode);
3548 }
3549
3550 final long origId = Binder.clearCallingIdentity();
3551 // XXX we are not dealing with propagating grantedUriPermissions...
3552 // those are not yet exposed to user code, so there is no need.
3553 int res = startActivityLocked(r.app.thread, intent,
3554 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003555 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 Binder.restoreCallingIdentity(origId);
3557
3558 r.finishing = wasFinishing;
3559 if (res != START_SUCCESS) {
3560 return false;
3561 }
3562 return true;
3563 }
3564 }
3565
3566 final int startActivityInPackage(int uid,
3567 Intent intent, String resolvedType, IBinder resultTo,
3568 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003569 final boolean componentSpecified = intent.getComponent() != null;
3570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 // Don't modify the client's object!
3572 intent = new Intent(intent);
3573
3574 // Collect information about the target of the Intent.
3575 // Must do this before locking, because resolving the intent
3576 // may require launching a process to run its content provider.
3577 ActivityInfo aInfo;
3578 try {
3579 ResolveInfo rInfo =
3580 ActivityThread.getPackageManager().resolveIntent(
3581 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003582 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003583 aInfo = rInfo != null ? rInfo.activityInfo : null;
3584 } catch (RemoteException e) {
3585 aInfo = null;
3586 }
3587
3588 if (aInfo != null) {
3589 // Store the found target back into the intent, because now that
3590 // we have it we never want to do this again. For example, if the
3591 // user navigates back to this point in the history, we should
3592 // always restart the exact same activity.
3593 intent.setComponent(new ComponentName(
3594 aInfo.applicationInfo.packageName, aInfo.name));
3595 }
3596
3597 synchronized(this) {
3598 return startActivityLocked(null, intent, resolvedType,
3599 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003600 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003601 }
3602 }
3603
3604 private final void addRecentTask(TaskRecord task) {
3605 // Remove any existing entries that are the same kind of task.
3606 int N = mRecentTasks.size();
3607 for (int i=0; i<N; i++) {
3608 TaskRecord tr = mRecentTasks.get(i);
3609 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3610 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3611 mRecentTasks.remove(i);
3612 i--;
3613 N--;
3614 if (task.intent == null) {
3615 // If the new recent task we are adding is not fully
3616 // specified, then replace it with the existing recent task.
3617 task = tr;
3618 }
3619 }
3620 }
3621 if (N >= MAX_RECENT_TASKS) {
3622 mRecentTasks.remove(N-1);
3623 }
3624 mRecentTasks.add(0, task);
3625 }
3626
3627 public void setRequestedOrientation(IBinder token,
3628 int requestedOrientation) {
3629 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003630 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003631 if (index < 0) {
3632 return;
3633 }
3634 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3635 final long origId = Binder.clearCallingIdentity();
3636 mWindowManager.setAppOrientation(r, requestedOrientation);
3637 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003638 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 r.mayFreezeScreenLocked(r.app) ? r : null);
3640 if (config != null) {
3641 r.frozenBeforeDestroy = true;
3642 if (!updateConfigurationLocked(config, r)) {
3643 resumeTopActivityLocked(null);
3644 }
3645 }
3646 Binder.restoreCallingIdentity(origId);
3647 }
3648 }
3649
3650 public int getRequestedOrientation(IBinder token) {
3651 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003652 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 if (index < 0) {
3654 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3655 }
3656 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3657 return mWindowManager.getAppOrientation(r);
3658 }
3659 }
3660
3661 private final void stopActivityLocked(HistoryRecord r) {
3662 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3663 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3664 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3665 if (!r.finishing) {
3666 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3667 "no-history");
3668 }
3669 } else if (r.app != null && r.app.thread != null) {
3670 if (mFocusedActivity == r) {
3671 setFocusedActivityLocked(topRunningActivityLocked(null));
3672 }
3673 r.resumeKeyDispatchingLocked();
3674 try {
3675 r.stopped = false;
3676 r.state = ActivityState.STOPPING;
3677 if (DEBUG_VISBILITY) Log.v(
3678 TAG, "Stopping visible=" + r.visible + " for " + r);
3679 if (!r.visible) {
3680 mWindowManager.setAppVisibility(r, false);
3681 }
3682 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3683 } catch (Exception e) {
3684 // Maybe just ignore exceptions here... if the process
3685 // has crashed, our death notification will clean things
3686 // up.
3687 Log.w(TAG, "Exception thrown during pause", e);
3688 // Just in case, assume it to be stopped.
3689 r.stopped = true;
3690 r.state = ActivityState.STOPPED;
3691 if (r.configDestroy) {
3692 destroyActivityLocked(r, true);
3693 }
3694 }
3695 }
3696 }
3697
3698 /**
3699 * @return Returns true if the activity is being finished, false if for
3700 * some reason it is being left as-is.
3701 */
3702 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3703 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003704 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 TAG, "Finishing activity: token=" + token
3706 + ", result=" + resultCode + ", data=" + resultData);
3707
Dianne Hackborn75b03852009-06-12 15:43:26 -07003708 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709 if (index < 0) {
3710 return false;
3711 }
3712 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3713
3714 // Is this the last activity left?
3715 boolean lastActivity = true;
3716 for (int i=mHistory.size()-1; i>=0; i--) {
3717 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3718 if (!p.finishing && p != r) {
3719 lastActivity = false;
3720 break;
3721 }
3722 }
3723
3724 // If this is the last activity, but it is the home activity, then
3725 // just don't finish it.
3726 if (lastActivity) {
3727 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3728 return false;
3729 }
3730 }
3731
3732 finishActivityLocked(r, index, resultCode, resultData, reason);
3733 return true;
3734 }
3735
3736 /**
3737 * @return Returns true if this activity has been removed from the history
3738 * list, or false if it is still in the list and will be removed later.
3739 */
3740 private final boolean finishActivityLocked(HistoryRecord r, int index,
3741 int resultCode, Intent resultData, String reason) {
3742 if (r.finishing) {
3743 Log.w(TAG, "Duplicate finish request for " + r);
3744 return false;
3745 }
3746
3747 r.finishing = true;
3748 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3749 System.identityHashCode(r),
3750 r.task.taskId, r.shortComponentName, reason);
3751 r.task.numActivities--;
3752 if (r.frontOfTask && index < (mHistory.size()-1)) {
3753 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3754 if (next.task == r.task) {
3755 next.frontOfTask = true;
3756 }
3757 }
3758
3759 r.pauseKeyDispatchingLocked();
3760 if (mFocusedActivity == r) {
3761 setFocusedActivityLocked(topRunningActivityLocked(null));
3762 }
3763
3764 // send the result
3765 HistoryRecord resultTo = r.resultTo;
3766 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003767 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3768 + " who=" + r.resultWho + " req=" + r.requestCode
3769 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 if (r.info.applicationInfo.uid > 0) {
3771 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3772 r.packageName, resultData, r);
3773 }
3774 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3775 resultData);
3776 r.resultTo = null;
3777 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003778 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003779
3780 // Make sure this HistoryRecord is not holding on to other resources,
3781 // because clients have remote IPC references to this object so we
3782 // can't assume that will go away and want to avoid circular IPC refs.
3783 r.results = null;
3784 r.pendingResults = null;
3785 r.newIntents = null;
3786 r.icicle = null;
3787
3788 if (mPendingThumbnails.size() > 0) {
3789 // There are clients waiting to receive thumbnails so, in case
3790 // this is an activity that someone is waiting for, add it
3791 // to the pending list so we can correctly update the clients.
3792 mCancelledThumbnails.add(r);
3793 }
3794
3795 if (mResumedActivity == r) {
3796 boolean endTask = index <= 0
3797 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3798 if (DEBUG_TRANSITION) Log.v(TAG,
3799 "Prepare close transition: finishing " + r);
3800 mWindowManager.prepareAppTransition(endTask
3801 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3802 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3803
3804 // Tell window manager to prepare for this one to be removed.
3805 mWindowManager.setAppVisibility(r, false);
3806
3807 if (mPausingActivity == null) {
3808 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3809 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3810 startPausingLocked(false, false);
3811 }
3812
3813 } else if (r.state != ActivityState.PAUSING) {
3814 // If the activity is PAUSING, we will complete the finish once
3815 // it is done pausing; else we can just directly finish it here.
3816 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3817 return finishCurrentActivityLocked(r, index,
3818 FINISH_AFTER_PAUSE) == null;
3819 } else {
3820 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3821 }
3822
3823 return false;
3824 }
3825
3826 private static final int FINISH_IMMEDIATELY = 0;
3827 private static final int FINISH_AFTER_PAUSE = 1;
3828 private static final int FINISH_AFTER_VISIBLE = 2;
3829
3830 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3831 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003832 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 if (index < 0) {
3834 return null;
3835 }
3836
3837 return finishCurrentActivityLocked(r, index, mode);
3838 }
3839
3840 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3841 int index, int mode) {
3842 // First things first: if this activity is currently visible,
3843 // and the resumed activity is not yet visible, then hold off on
3844 // finishing until the resumed one becomes visible.
3845 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3846 if (!mStoppingActivities.contains(r)) {
3847 mStoppingActivities.add(r);
3848 if (mStoppingActivities.size() > 3) {
3849 // If we already have a few activities waiting to stop,
3850 // then give up on things going idle and start clearing
3851 // them out.
3852 Message msg = Message.obtain();
3853 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3854 mHandler.sendMessage(msg);
3855 }
3856 }
3857 r.state = ActivityState.STOPPING;
3858 updateOomAdjLocked();
3859 return r;
3860 }
3861
3862 // make sure the record is cleaned out of other places.
3863 mStoppingActivities.remove(r);
3864 mWaitingVisibleActivities.remove(r);
3865 if (mResumedActivity == r) {
3866 mResumedActivity = null;
3867 }
3868 final ActivityState prevState = r.state;
3869 r.state = ActivityState.FINISHING;
3870
3871 if (mode == FINISH_IMMEDIATELY
3872 || prevState == ActivityState.STOPPED
3873 || prevState == ActivityState.INITIALIZING) {
3874 // If this activity is already stopped, we can just finish
3875 // it right now.
3876 return destroyActivityLocked(r, true) ? null : r;
3877 } else {
3878 // Need to go through the full pause cycle to get this
3879 // activity into the stopped state and then finish it.
3880 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3881 mFinishingActivities.add(r);
3882 resumeTopActivityLocked(null);
3883 }
3884 return r;
3885 }
3886
3887 /**
3888 * This is the internal entry point for handling Activity.finish().
3889 *
3890 * @param token The Binder token referencing the Activity we want to finish.
3891 * @param resultCode Result code, if any, from this Activity.
3892 * @param resultData Result data (Intent), if any, from this Activity.
3893 *
3894 * @result Returns true if the activity successfully finished, or false if it is still running.
3895 */
3896 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3897 // Refuse possible leaked file descriptors
3898 if (resultData != null && resultData.hasFileDescriptors() == true) {
3899 throw new IllegalArgumentException("File descriptors passed in Intent");
3900 }
3901
3902 synchronized(this) {
3903 if (mWatcher != null) {
3904 // Find the first activity that is not finishing.
3905 HistoryRecord next = topRunningActivityLocked(token, 0);
3906 if (next != null) {
3907 // ask watcher if this is allowed
3908 boolean resumeOK = true;
3909 try {
3910 resumeOK = mWatcher.activityResuming(next.packageName);
3911 } catch (RemoteException e) {
3912 mWatcher = null;
3913 }
3914
3915 if (!resumeOK) {
3916 return false;
3917 }
3918 }
3919 }
3920 final long origId = Binder.clearCallingIdentity();
3921 boolean res = requestFinishActivityLocked(token, resultCode,
3922 resultData, "app-request");
3923 Binder.restoreCallingIdentity(origId);
3924 return res;
3925 }
3926 }
3927
3928 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3929 String resultWho, int requestCode, int resultCode, Intent data) {
3930
3931 if (callingUid > 0) {
3932 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3933 data, r);
3934 }
3935
The Android Open Source Project10592532009-03-18 17:39:46 -07003936 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3937 + " : who=" + resultWho + " req=" + requestCode
3938 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003939 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3940 try {
3941 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3942 list.add(new ResultInfo(resultWho, requestCode,
3943 resultCode, data));
3944 r.app.thread.scheduleSendResult(r, list);
3945 return;
3946 } catch (Exception e) {
3947 Log.w(TAG, "Exception thrown sending result to " + r, e);
3948 }
3949 }
3950
3951 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3952 }
3953
3954 public final void finishSubActivity(IBinder token, String resultWho,
3955 int requestCode) {
3956 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003957 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003958 if (index < 0) {
3959 return;
3960 }
3961 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3962
3963 final long origId = Binder.clearCallingIdentity();
3964
3965 int i;
3966 for (i=mHistory.size()-1; i>=0; i--) {
3967 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3968 if (r.resultTo == self && r.requestCode == requestCode) {
3969 if ((r.resultWho == null && resultWho == null) ||
3970 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3971 finishActivityLocked(r, i,
3972 Activity.RESULT_CANCELED, null, "request-sub");
3973 }
3974 }
3975 }
3976
3977 Binder.restoreCallingIdentity(origId);
3978 }
3979 }
3980
3981 /**
3982 * Perform clean-up of service connections in an activity record.
3983 */
3984 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3985 // Throw away any services that have been bound by this activity.
3986 if (r.connections != null) {
3987 Iterator<ConnectionRecord> it = r.connections.iterator();
3988 while (it.hasNext()) {
3989 ConnectionRecord c = it.next();
3990 removeConnectionLocked(c, null, r);
3991 }
3992 r.connections = null;
3993 }
3994 }
3995
3996 /**
3997 * Perform the common clean-up of an activity record. This is called both
3998 * as part of destroyActivityLocked() (when destroying the client-side
3999 * representation) and cleaning things up as a result of its hosting
4000 * processing going away, in which case there is no remaining client-side
4001 * state to destroy so only the cleanup here is needed.
4002 */
4003 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4004 if (mResumedActivity == r) {
4005 mResumedActivity = null;
4006 }
4007 if (mFocusedActivity == r) {
4008 mFocusedActivity = null;
4009 }
4010
4011 r.configDestroy = false;
4012 r.frozenBeforeDestroy = false;
4013
4014 // Make sure this record is no longer in the pending finishes list.
4015 // This could happen, for example, if we are trimming activities
4016 // down to the max limit while they are still waiting to finish.
4017 mFinishingActivities.remove(r);
4018 mWaitingVisibleActivities.remove(r);
4019
4020 // Remove any pending results.
4021 if (r.finishing && r.pendingResults != null) {
4022 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4023 PendingIntentRecord rec = apr.get();
4024 if (rec != null) {
4025 cancelIntentSenderLocked(rec, false);
4026 }
4027 }
4028 r.pendingResults = null;
4029 }
4030
4031 if (cleanServices) {
4032 cleanUpActivityServicesLocked(r);
4033 }
4034
4035 if (mPendingThumbnails.size() > 0) {
4036 // There are clients waiting to receive thumbnails so, in case
4037 // this is an activity that someone is waiting for, add it
4038 // to the pending list so we can correctly update the clients.
4039 mCancelledThumbnails.add(r);
4040 }
4041
4042 // Get rid of any pending idle timeouts.
4043 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4044 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4045 }
4046
4047 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4048 if (r.state != ActivityState.DESTROYED) {
4049 mHistory.remove(r);
4050 r.inHistory = false;
4051 r.state = ActivityState.DESTROYED;
4052 mWindowManager.removeAppToken(r);
4053 if (VALIDATE_TOKENS) {
4054 mWindowManager.validateAppTokens(mHistory);
4055 }
4056 cleanUpActivityServicesLocked(r);
4057 removeActivityUriPermissionsLocked(r);
4058 }
4059 }
4060
4061 /**
4062 * Destroy the current CLIENT SIDE instance of an activity. This may be
4063 * called both when actually finishing an activity, or when performing
4064 * a configuration switch where we destroy the current client-side object
4065 * but then create a new client-side object for this same HistoryRecord.
4066 */
4067 private final boolean destroyActivityLocked(HistoryRecord r,
4068 boolean removeFromApp) {
4069 if (DEBUG_SWITCH) Log.v(
4070 TAG, "Removing activity: token=" + r
4071 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4072 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4073 System.identityHashCode(r),
4074 r.task.taskId, r.shortComponentName);
4075
4076 boolean removedFromHistory = false;
4077
4078 cleanUpActivityLocked(r, false);
4079
4080 if (r.app != null) {
4081 if (removeFromApp) {
4082 int idx = r.app.activities.indexOf(r);
4083 if (idx >= 0) {
4084 r.app.activities.remove(idx);
4085 }
4086 if (r.persistent) {
4087 decPersistentCountLocked(r.app);
4088 }
4089 }
4090
4091 boolean skipDestroy = false;
4092
4093 try {
4094 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4095 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4096 r.configChangeFlags);
4097 } catch (Exception e) {
4098 // We can just ignore exceptions here... if the process
4099 // has crashed, our death notification will clean things
4100 // up.
4101 //Log.w(TAG, "Exception thrown during finish", e);
4102 if (r.finishing) {
4103 removeActivityFromHistoryLocked(r);
4104 removedFromHistory = true;
4105 skipDestroy = true;
4106 }
4107 }
4108
4109 r.app = null;
4110 r.nowVisible = false;
4111
4112 if (r.finishing && !skipDestroy) {
4113 r.state = ActivityState.DESTROYING;
4114 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4115 msg.obj = r;
4116 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4117 } else {
4118 r.state = ActivityState.DESTROYED;
4119 }
4120 } else {
4121 // remove this record from the history.
4122 if (r.finishing) {
4123 removeActivityFromHistoryLocked(r);
4124 removedFromHistory = true;
4125 } else {
4126 r.state = ActivityState.DESTROYED;
4127 }
4128 }
4129
4130 r.configChangeFlags = 0;
4131
4132 if (!mLRUActivities.remove(r)) {
4133 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4134 }
4135
4136 return removedFromHistory;
4137 }
4138
4139 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4140 ProcessRecord app)
4141 {
4142 int i = list.size();
4143 if (localLOGV) Log.v(
4144 TAG, "Removing app " + app + " from list " + list
4145 + " with " + i + " entries");
4146 while (i > 0) {
4147 i--;
4148 HistoryRecord r = (HistoryRecord)list.get(i);
4149 if (localLOGV) Log.v(
4150 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4151 if (r.app == app) {
4152 if (localLOGV) Log.v(TAG, "Removing this entry!");
4153 list.remove(i);
4154 }
4155 }
4156 }
4157
4158 /**
4159 * Main function for removing an existing process from the activity manager
4160 * as a result of that process going away. Clears out all connections
4161 * to the process.
4162 */
4163 private final void handleAppDiedLocked(ProcessRecord app,
4164 boolean restarting) {
4165 cleanUpApplicationRecordLocked(app, restarting, -1);
4166 if (!restarting) {
4167 mLRUProcesses.remove(app);
4168 }
4169
4170 // Just in case...
4171 if (mPausingActivity != null && mPausingActivity.app == app) {
4172 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4173 mPausingActivity = null;
4174 }
4175 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4176 mLastPausedActivity = null;
4177 }
4178
4179 // Remove this application's activities from active lists.
4180 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4181 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4182 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4183 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4184
4185 boolean atTop = true;
4186 boolean hasVisibleActivities = false;
4187
4188 // Clean out the history list.
4189 int i = mHistory.size();
4190 if (localLOGV) Log.v(
4191 TAG, "Removing app " + app + " from history with " + i + " entries");
4192 while (i > 0) {
4193 i--;
4194 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4195 if (localLOGV) Log.v(
4196 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4197 if (r.app == app) {
4198 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4199 if (localLOGV) Log.v(
4200 TAG, "Removing this entry! frozen=" + r.haveState
4201 + " finishing=" + r.finishing);
4202 mHistory.remove(i);
4203
4204 r.inHistory = false;
4205 mWindowManager.removeAppToken(r);
4206 if (VALIDATE_TOKENS) {
4207 mWindowManager.validateAppTokens(mHistory);
4208 }
4209 removeActivityUriPermissionsLocked(r);
4210
4211 } else {
4212 // We have the current state for this activity, so
4213 // it can be restarted later when needed.
4214 if (localLOGV) Log.v(
4215 TAG, "Keeping entry, setting app to null");
4216 if (r.visible) {
4217 hasVisibleActivities = true;
4218 }
4219 r.app = null;
4220 r.nowVisible = false;
4221 if (!r.haveState) {
4222 r.icicle = null;
4223 }
4224 }
4225
4226 cleanUpActivityLocked(r, true);
4227 r.state = ActivityState.STOPPED;
4228 }
4229 atTop = false;
4230 }
4231
4232 app.activities.clear();
4233
4234 if (app.instrumentationClass != null) {
4235 Log.w(TAG, "Crash of app " + app.processName
4236 + " running instrumentation " + app.instrumentationClass);
4237 Bundle info = new Bundle();
4238 info.putString("shortMsg", "Process crashed.");
4239 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4240 }
4241
4242 if (!restarting) {
4243 if (!resumeTopActivityLocked(null)) {
4244 // If there was nothing to resume, and we are not already
4245 // restarting this process, but there is a visible activity that
4246 // is hosted by the process... then make sure all visible
4247 // activities are running, taking care of restarting this
4248 // process.
4249 if (hasVisibleActivities) {
4250 ensureActivitiesVisibleLocked(null, 0);
4251 }
4252 }
4253 }
4254 }
4255
4256 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4257 IBinder threadBinder = thread.asBinder();
4258
4259 // Find the application record.
4260 int count = mLRUProcesses.size();
4261 int i;
4262 for (i=0; i<count; i++) {
4263 ProcessRecord rec = mLRUProcesses.get(i);
4264 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4265 return i;
4266 }
4267 }
4268 return -1;
4269 }
4270
4271 private final ProcessRecord getRecordForAppLocked(
4272 IApplicationThread thread) {
4273 if (thread == null) {
4274 return null;
4275 }
4276
4277 int appIndex = getLRURecordIndexForAppLocked(thread);
4278 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4279 }
4280
4281 private final void appDiedLocked(ProcessRecord app, int pid,
4282 IApplicationThread thread) {
4283
4284 mProcDeaths[0]++;
4285
4286 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4287 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4288 + ") has died.");
4289 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4290 if (localLOGV) Log.v(
4291 TAG, "Dying app: " + app + ", pid: " + pid
4292 + ", thread: " + thread.asBinder());
4293 boolean doLowMem = app.instrumentationClass == null;
4294 handleAppDiedLocked(app, false);
4295
4296 if (doLowMem) {
4297 // If there are no longer any background processes running,
4298 // and the app that died was not running instrumentation,
4299 // then tell everyone we are now low on memory.
4300 boolean haveBg = false;
4301 int count = mLRUProcesses.size();
4302 int i;
4303 for (i=0; i<count; i++) {
4304 ProcessRecord rec = mLRUProcesses.get(i);
4305 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4306 haveBg = true;
4307 break;
4308 }
4309 }
4310
4311 if (!haveBg) {
4312 Log.i(TAG, "Low Memory: No more background processes.");
4313 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4314 for (i=0; i<count; i++) {
4315 ProcessRecord rec = mLRUProcesses.get(i);
4316 if (rec.thread != null) {
4317 rec.lastRequestedGc = SystemClock.uptimeMillis();
4318 try {
4319 rec.thread.scheduleLowMemory();
4320 } catch (RemoteException e) {
4321 // Don't care if the process is gone.
4322 }
4323 }
4324 }
4325 }
4326 }
4327 } else if (Config.LOGD) {
4328 Log.d(TAG, "Received spurious death notification for thread "
4329 + thread.asBinder());
4330 }
4331 }
4332
4333 final String readFile(String filename) {
4334 try {
4335 FileInputStream fs = new FileInputStream(filename);
4336 byte[] inp = new byte[8192];
4337 int size = fs.read(inp);
4338 fs.close();
4339 return new String(inp, 0, 0, size);
4340 } catch (java.io.IOException e) {
4341 }
4342 return "";
4343 }
4344
4345 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4346 final String annotation) {
4347 if (app.notResponding || app.crashing) {
4348 return;
4349 }
4350
4351 // Log the ANR to the event log.
4352 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4353
4354 // If we are on a secure build and the application is not interesting to the user (it is
4355 // not visible or in the background), just kill it instead of displaying a dialog.
4356 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4357 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4358 Process.killProcess(app.pid);
4359 return;
4360 }
4361
4362 // DeviceMonitor.start();
4363
4364 String processInfo = null;
4365 if (MONITOR_CPU_USAGE) {
4366 updateCpuStatsNow();
4367 synchronized (mProcessStatsThread) {
4368 processInfo = mProcessStats.printCurrentState();
4369 }
4370 }
4371
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004372 StringBuilder info = mStringBuilder;
4373 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004374 info.append("ANR (application not responding) in process: ");
4375 info.append(app.processName);
4376 if (annotation != null) {
4377 info.append("\nAnnotation: ");
4378 info.append(annotation);
4379 }
4380 if (MONITOR_CPU_USAGE) {
4381 info.append("\nCPU usage:\n");
4382 info.append(processInfo);
4383 }
4384 Log.i(TAG, info.toString());
4385
4386 // The application is not responding. Dump as many thread traces as we can.
4387 boolean fileDump = prepareTraceFile(true);
4388 if (!fileDump) {
4389 // Dumping traces to the log, just dump the process that isn't responding so
4390 // we don't overflow the log
4391 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4392 } else {
4393 // Dumping traces to a file so dump all active processes we know about
4394 synchronized (this) {
4395 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4396 ProcessRecord r = mLRUProcesses.get(i);
4397 if (r.thread != null) {
4398 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4399 }
4400 }
4401 }
4402 }
4403
4404 if (mWatcher != null) {
4405 try {
4406 int res = mWatcher.appNotResponding(app.processName,
4407 app.pid, info.toString());
4408 if (res != 0) {
4409 if (res < 0) {
4410 // wait until the SIGQUIT has had a chance to process before killing the
4411 // process.
4412 try {
4413 wait(2000);
4414 } catch (InterruptedException e) {
4415 }
4416
4417 Process.killProcess(app.pid);
4418 return;
4419 }
4420 }
4421 } catch (RemoteException e) {
4422 mWatcher = null;
4423 }
4424 }
4425
4426 makeAppNotRespondingLocked(app,
4427 activity != null ? activity.shortComponentName : null,
4428 annotation != null ? "ANR " + annotation : "ANR",
4429 info.toString(), null);
4430 Message msg = Message.obtain();
4431 HashMap map = new HashMap();
4432 msg.what = SHOW_NOT_RESPONDING_MSG;
4433 msg.obj = map;
4434 map.put("app", app);
4435 if (activity != null) {
4436 map.put("activity", activity);
4437 }
4438
4439 mHandler.sendMessage(msg);
4440 return;
4441 }
4442
4443 /**
4444 * If a stack trace file has been configured, prepare the filesystem
4445 * by creating the directory if it doesn't exist and optionally
4446 * removing the old trace file.
4447 *
4448 * @param removeExisting If set, the existing trace file will be removed.
4449 * @return Returns true if the trace file preparations succeeded
4450 */
4451 public static boolean prepareTraceFile(boolean removeExisting) {
4452 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4453 boolean fileReady = false;
4454 if (!TextUtils.isEmpty(tracesPath)) {
4455 File f = new File(tracesPath);
4456 if (!f.exists()) {
4457 // Ensure the enclosing directory exists
4458 File dir = f.getParentFile();
4459 if (!dir.exists()) {
4460 fileReady = dir.mkdirs();
4461 FileUtils.setPermissions(dir.getAbsolutePath(),
4462 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4463 } else if (dir.isDirectory()) {
4464 fileReady = true;
4465 }
4466 } else if (removeExisting) {
4467 // Remove the previous traces file, so we don't fill the disk.
4468 // The VM will recreate it
4469 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4470 fileReady = f.delete();
4471 }
4472 }
4473
4474 return fileReady;
4475 }
4476
4477
4478 private final void decPersistentCountLocked(ProcessRecord app)
4479 {
4480 app.persistentActivities--;
4481 if (app.persistentActivities > 0) {
4482 // Still more of 'em...
4483 return;
4484 }
4485 if (app.persistent) {
4486 // Ah, but the application itself is persistent. Whatever!
4487 return;
4488 }
4489
4490 // App is no longer persistent... make sure it and the ones
4491 // following it in the LRU list have the correc oom_adj.
4492 updateOomAdjLocked();
4493 }
4494
4495 public void setPersistent(IBinder token, boolean isPersistent) {
4496 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4497 != PackageManager.PERMISSION_GRANTED) {
4498 String msg = "Permission Denial: setPersistent() from pid="
4499 + Binder.getCallingPid()
4500 + ", uid=" + Binder.getCallingUid()
4501 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4502 Log.w(TAG, msg);
4503 throw new SecurityException(msg);
4504 }
4505
4506 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004507 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 if (index < 0) {
4509 return;
4510 }
4511 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4512 ProcessRecord app = r.app;
4513
4514 if (localLOGV) Log.v(
4515 TAG, "Setting persistence " + isPersistent + ": " + r);
4516
4517 if (isPersistent) {
4518 if (r.persistent) {
4519 // Okay okay, I heard you already!
4520 if (localLOGV) Log.v(TAG, "Already persistent!");
4521 return;
4522 }
4523 r.persistent = true;
4524 app.persistentActivities++;
4525 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4526 if (app.persistentActivities > 1) {
4527 // We aren't the first...
4528 if (localLOGV) Log.v(TAG, "Not the first!");
4529 return;
4530 }
4531 if (app.persistent) {
4532 // This would be redundant.
4533 if (localLOGV) Log.v(TAG, "App is persistent!");
4534 return;
4535 }
4536
4537 // App is now persistent... make sure it and the ones
4538 // following it now have the correct oom_adj.
4539 final long origId = Binder.clearCallingIdentity();
4540 updateOomAdjLocked();
4541 Binder.restoreCallingIdentity(origId);
4542
4543 } else {
4544 if (!r.persistent) {
4545 // Okay okay, I heard you already!
4546 return;
4547 }
4548 r.persistent = false;
4549 final long origId = Binder.clearCallingIdentity();
4550 decPersistentCountLocked(app);
4551 Binder.restoreCallingIdentity(origId);
4552
4553 }
4554 }
4555 }
4556
4557 public boolean clearApplicationUserData(final String packageName,
4558 final IPackageDataObserver observer) {
4559 int uid = Binder.getCallingUid();
4560 int pid = Binder.getCallingPid();
4561 long callingId = Binder.clearCallingIdentity();
4562 try {
4563 IPackageManager pm = ActivityThread.getPackageManager();
4564 int pkgUid = -1;
4565 synchronized(this) {
4566 try {
4567 pkgUid = pm.getPackageUid(packageName);
4568 } catch (RemoteException e) {
4569 }
4570 if (pkgUid == -1) {
4571 Log.w(TAG, "Invalid packageName:" + packageName);
4572 return false;
4573 }
4574 if (uid == pkgUid || checkComponentPermission(
4575 android.Manifest.permission.CLEAR_APP_USER_DATA,
4576 pid, uid, -1)
4577 == PackageManager.PERMISSION_GRANTED) {
4578 restartPackageLocked(packageName, pkgUid);
4579 } else {
4580 throw new SecurityException(pid+" does not have permission:"+
4581 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4582 "for process:"+packageName);
4583 }
4584 }
4585
4586 try {
4587 //clear application user data
4588 pm.clearApplicationUserData(packageName, observer);
4589 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4590 Uri.fromParts("package", packageName, null));
4591 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4592 broadcastIntentLocked(null, null, intent,
4593 null, null, 0, null, null, null,
4594 false, false, MY_PID, Process.SYSTEM_UID);
4595 } catch (RemoteException e) {
4596 }
4597 } finally {
4598 Binder.restoreCallingIdentity(callingId);
4599 }
4600 return true;
4601 }
4602
4603 public void restartPackage(final String packageName) {
4604 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4605 != PackageManager.PERMISSION_GRANTED) {
4606 String msg = "Permission Denial: restartPackage() from pid="
4607 + Binder.getCallingPid()
4608 + ", uid=" + Binder.getCallingUid()
4609 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4610 Log.w(TAG, msg);
4611 throw new SecurityException(msg);
4612 }
4613
4614 long callingId = Binder.clearCallingIdentity();
4615 try {
4616 IPackageManager pm = ActivityThread.getPackageManager();
4617 int pkgUid = -1;
4618 synchronized(this) {
4619 try {
4620 pkgUid = pm.getPackageUid(packageName);
4621 } catch (RemoteException e) {
4622 }
4623 if (pkgUid == -1) {
4624 Log.w(TAG, "Invalid packageName: " + packageName);
4625 return;
4626 }
4627 restartPackageLocked(packageName, pkgUid);
4628 }
4629 } finally {
4630 Binder.restoreCallingIdentity(callingId);
4631 }
4632 }
4633
4634 private void restartPackageLocked(final String packageName, int uid) {
4635 uninstallPackageLocked(packageName, uid, false);
4636 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4637 Uri.fromParts("package", packageName, null));
4638 intent.putExtra(Intent.EXTRA_UID, uid);
4639 broadcastIntentLocked(null, null, intent,
4640 null, null, 0, null, null, null,
4641 false, false, MY_PID, Process.SYSTEM_UID);
4642 }
4643
4644 private final void uninstallPackageLocked(String name, int uid,
4645 boolean callerWillRestart) {
4646 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4647
4648 int i, N;
4649
4650 final String procNamePrefix = name + ":";
4651 if (uid < 0) {
4652 try {
4653 uid = ActivityThread.getPackageManager().getPackageUid(name);
4654 } catch (RemoteException e) {
4655 }
4656 }
4657
4658 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4659 while (badApps.hasNext()) {
4660 SparseArray<Long> ba = badApps.next();
4661 if (ba.get(uid) != null) {
4662 badApps.remove();
4663 }
4664 }
4665
4666 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4667
4668 // Remove all processes this package may have touched: all with the
4669 // same UID (except for the system or root user), and all whose name
4670 // matches the package name.
4671 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4672 final int NA = apps.size();
4673 for (int ia=0; ia<NA; ia++) {
4674 ProcessRecord app = apps.valueAt(ia);
4675 if (app.removed) {
4676 procs.add(app);
4677 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4678 || app.processName.equals(name)
4679 || app.processName.startsWith(procNamePrefix)) {
4680 app.removed = true;
4681 procs.add(app);
4682 }
4683 }
4684 }
4685
4686 N = procs.size();
4687 for (i=0; i<N; i++) {
4688 removeProcessLocked(procs.get(i), callerWillRestart);
4689 }
4690
4691 for (i=mHistory.size()-1; i>=0; i--) {
4692 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4693 if (r.packageName.equals(name)) {
4694 if (Config.LOGD) Log.d(
4695 TAG, " Force finishing activity "
4696 + r.intent.getComponent().flattenToShortString());
4697 if (r.app != null) {
4698 r.app.removed = true;
4699 }
4700 r.app = null;
4701 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4702 }
4703 }
4704
4705 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4706 for (ServiceRecord service : mServices.values()) {
4707 if (service.packageName.equals(name)) {
4708 if (service.app != null) {
4709 service.app.removed = true;
4710 }
4711 service.app = null;
4712 services.add(service);
4713 }
4714 }
4715
4716 N = services.size();
4717 for (i=0; i<N; i++) {
4718 bringDownServiceLocked(services.get(i), true);
4719 }
4720
4721 resumeTopActivityLocked(null);
4722 }
4723
4724 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4725 final String name = app.processName;
4726 final int uid = app.info.uid;
4727 if (Config.LOGD) Log.d(
4728 TAG, "Force removing process " + app + " (" + name
4729 + "/" + uid + ")");
4730
4731 mProcessNames.remove(name, uid);
4732 boolean needRestart = false;
4733 if (app.pid > 0 && app.pid != MY_PID) {
4734 int pid = app.pid;
4735 synchronized (mPidsSelfLocked) {
4736 mPidsSelfLocked.remove(pid);
4737 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4738 }
4739 handleAppDiedLocked(app, true);
4740 mLRUProcesses.remove(app);
4741 Process.killProcess(pid);
4742
4743 if (app.persistent) {
4744 if (!callerWillRestart) {
4745 addAppLocked(app.info);
4746 } else {
4747 needRestart = true;
4748 }
4749 }
4750 } else {
4751 mRemovedProcesses.add(app);
4752 }
4753
4754 return needRestart;
4755 }
4756
4757 private final void processStartTimedOutLocked(ProcessRecord app) {
4758 final int pid = app.pid;
4759 boolean gone = false;
4760 synchronized (mPidsSelfLocked) {
4761 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4762 if (knownApp != null && knownApp.thread == null) {
4763 mPidsSelfLocked.remove(pid);
4764 gone = true;
4765 }
4766 }
4767
4768 if (gone) {
4769 Log.w(TAG, "Process " + app + " failed to attach");
4770 mProcessNames.remove(app.processName, app.info.uid);
4771 Process.killProcess(pid);
4772 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4773 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4774 mPendingBroadcast = null;
4775 scheduleBroadcastsLocked();
4776 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004777 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4778 Log.w(TAG, "Unattached app died before backup, skipping");
4779 try {
4780 IBackupManager bm = IBackupManager.Stub.asInterface(
4781 ServiceManager.getService(Context.BACKUP_SERVICE));
4782 bm.agentDisconnected(app.info.packageName);
4783 } catch (RemoteException e) {
4784 // Can't happen; the backup manager is local
4785 }
4786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004787 } else {
4788 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4789 }
4790 }
4791
4792 private final boolean attachApplicationLocked(IApplicationThread thread,
4793 int pid) {
4794
4795 // Find the application record that is being attached... either via
4796 // the pid if we are running in multiple processes, or just pull the
4797 // next app record if we are emulating process with anonymous threads.
4798 ProcessRecord app;
4799 if (pid != MY_PID && pid >= 0) {
4800 synchronized (mPidsSelfLocked) {
4801 app = mPidsSelfLocked.get(pid);
4802 }
4803 } else if (mStartingProcesses.size() > 0) {
4804 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004805 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004806 } else {
4807 app = null;
4808 }
4809
4810 if (app == null) {
4811 Log.w(TAG, "No pending application record for pid " + pid
4812 + " (IApplicationThread " + thread + "); dropping process");
4813 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4814 if (pid > 0 && pid != MY_PID) {
4815 Process.killProcess(pid);
4816 } else {
4817 try {
4818 thread.scheduleExit();
4819 } catch (Exception e) {
4820 // Ignore exceptions.
4821 }
4822 }
4823 return false;
4824 }
4825
4826 // If this application record is still attached to a previous
4827 // process, clean it up now.
4828 if (app.thread != null) {
4829 handleAppDiedLocked(app, true);
4830 }
4831
4832 // Tell the process all about itself.
4833
4834 if (localLOGV) Log.v(
4835 TAG, "Binding process pid " + pid + " to record " + app);
4836
4837 String processName = app.processName;
4838 try {
4839 thread.asBinder().linkToDeath(new AppDeathRecipient(
4840 app, pid, thread), 0);
4841 } catch (RemoteException e) {
4842 app.resetPackageList();
4843 startProcessLocked(app, "link fail", processName);
4844 return false;
4845 }
4846
4847 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4848
4849 app.thread = thread;
4850 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004851 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004852 app.forcingToForeground = null;
4853 app.foregroundServices = false;
4854 app.debugging = false;
4855
4856 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4857
4858 List providers = generateApplicationProvidersLocked(app);
4859
4860 if (localLOGV) Log.v(
4861 TAG, "New app record " + app
4862 + " thread=" + thread.asBinder() + " pid=" + pid);
4863 try {
4864 int testMode = IApplicationThread.DEBUG_OFF;
4865 if (mDebugApp != null && mDebugApp.equals(processName)) {
4866 testMode = mWaitForDebugger
4867 ? IApplicationThread.DEBUG_WAIT
4868 : IApplicationThread.DEBUG_ON;
4869 app.debugging = true;
4870 if (mDebugTransient) {
4871 mDebugApp = mOrigDebugApp;
4872 mWaitForDebugger = mOrigWaitForDebugger;
4873 }
4874 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004875 // If the app is being launched for restore or full backup, set it up specially
4876 boolean isRestrictedBackupMode = false;
4877 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4878 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4879 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4880 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004881 ensurePackageDexOpt(app.instrumentationInfo != null
4882 ? app.instrumentationInfo.packageName
4883 : app.info.packageName);
4884 if (app.instrumentationClass != null) {
4885 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004886 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004887 thread.bindApplication(processName, app.instrumentationInfo != null
4888 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004889 app.instrumentationClass, app.instrumentationProfileFile,
4890 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004891 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004892 updateLRUListLocked(app, false);
4893 app.lastRequestedGc = SystemClock.uptimeMillis();
4894 } catch (Exception e) {
4895 // todo: Yikes! What should we do? For now we will try to
4896 // start another process, but that could easily get us in
4897 // an infinite loop of restarting processes...
4898 Log.w(TAG, "Exception thrown during bind!", e);
4899
4900 app.resetPackageList();
4901 startProcessLocked(app, "bind fail", processName);
4902 return false;
4903 }
4904
4905 // Remove this record from the list of starting applications.
4906 mPersistentStartingProcesses.remove(app);
4907 mProcessesOnHold.remove(app);
4908
4909 boolean badApp = false;
4910 boolean didSomething = false;
4911
4912 // See if the top visible activity is waiting to run in this process...
4913 HistoryRecord hr = topRunningActivityLocked(null);
4914 if (hr != null) {
4915 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4916 && processName.equals(hr.processName)) {
4917 try {
4918 if (realStartActivityLocked(hr, app, true, true)) {
4919 didSomething = true;
4920 }
4921 } catch (Exception e) {
4922 Log.w(TAG, "Exception in new application when starting activity "
4923 + hr.intent.getComponent().flattenToShortString(), e);
4924 badApp = true;
4925 }
4926 } else {
4927 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4928 }
4929 }
4930
4931 // Find any services that should be running in this process...
4932 if (!badApp && mPendingServices.size() > 0) {
4933 ServiceRecord sr = null;
4934 try {
4935 for (int i=0; i<mPendingServices.size(); i++) {
4936 sr = mPendingServices.get(i);
4937 if (app.info.uid != sr.appInfo.uid
4938 || !processName.equals(sr.processName)) {
4939 continue;
4940 }
4941
4942 mPendingServices.remove(i);
4943 i--;
4944 realStartServiceLocked(sr, app);
4945 didSomething = true;
4946 }
4947 } catch (Exception e) {
4948 Log.w(TAG, "Exception in new application when starting service "
4949 + sr.shortName, e);
4950 badApp = true;
4951 }
4952 }
4953
4954 // Check if the next broadcast receiver is in this process...
4955 BroadcastRecord br = mPendingBroadcast;
4956 if (!badApp && br != null && br.curApp == app) {
4957 try {
4958 mPendingBroadcast = null;
4959 processCurBroadcastLocked(br, app);
4960 didSomething = true;
4961 } catch (Exception e) {
4962 Log.w(TAG, "Exception in new application when starting receiver "
4963 + br.curComponent.flattenToShortString(), e);
4964 badApp = true;
4965 logBroadcastReceiverDiscard(br);
4966 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4967 br.resultExtras, br.resultAbort, true);
4968 scheduleBroadcastsLocked();
4969 }
4970 }
4971
Christopher Tate181fafa2009-05-14 11:12:14 -07004972 // Check whether the next backup agent is in this process...
4973 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4974 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004975 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07004976 try {
4977 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4978 } catch (Exception e) {
4979 Log.w(TAG, "Exception scheduling backup agent creation: ");
4980 e.printStackTrace();
4981 }
4982 }
4983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004984 if (badApp) {
4985 // todo: Also need to kill application to deal with all
4986 // kinds of exceptions.
4987 handleAppDiedLocked(app, false);
4988 return false;
4989 }
4990
4991 if (!didSomething) {
4992 updateOomAdjLocked();
4993 }
4994
4995 return true;
4996 }
4997
4998 public final void attachApplication(IApplicationThread thread) {
4999 synchronized (this) {
5000 int callingPid = Binder.getCallingPid();
5001 final long origId = Binder.clearCallingIdentity();
5002 attachApplicationLocked(thread, callingPid);
5003 Binder.restoreCallingIdentity(origId);
5004 }
5005 }
5006
5007 public final void activityIdle(IBinder token) {
5008 final long origId = Binder.clearCallingIdentity();
5009 activityIdleInternal(token, false);
5010 Binder.restoreCallingIdentity(origId);
5011 }
5012
5013 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5014 boolean remove) {
5015 int N = mStoppingActivities.size();
5016 if (N <= 0) return null;
5017
5018 ArrayList<HistoryRecord> stops = null;
5019
5020 final boolean nowVisible = mResumedActivity != null
5021 && mResumedActivity.nowVisible
5022 && !mResumedActivity.waitingVisible;
5023 for (int i=0; i<N; i++) {
5024 HistoryRecord s = mStoppingActivities.get(i);
5025 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5026 + nowVisible + " waitingVisible=" + s.waitingVisible
5027 + " finishing=" + s.finishing);
5028 if (s.waitingVisible && nowVisible) {
5029 mWaitingVisibleActivities.remove(s);
5030 s.waitingVisible = false;
5031 if (s.finishing) {
5032 // If this activity is finishing, it is sitting on top of
5033 // everyone else but we now know it is no longer needed...
5034 // so get rid of it. Otherwise, we need to go through the
5035 // normal flow and hide it once we determine that it is
5036 // hidden by the activities in front of it.
5037 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5038 mWindowManager.setAppVisibility(s, false);
5039 }
5040 }
5041 if (!s.waitingVisible && remove) {
5042 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5043 if (stops == null) {
5044 stops = new ArrayList<HistoryRecord>();
5045 }
5046 stops.add(s);
5047 mStoppingActivities.remove(i);
5048 N--;
5049 i--;
5050 }
5051 }
5052
5053 return stops;
5054 }
5055
5056 void enableScreenAfterBoot() {
5057 mWindowManager.enableScreenAfterBoot();
5058 }
5059
5060 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5061 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5062
5063 ArrayList<HistoryRecord> stops = null;
5064 ArrayList<HistoryRecord> finishes = null;
5065 ArrayList<HistoryRecord> thumbnails = null;
5066 int NS = 0;
5067 int NF = 0;
5068 int NT = 0;
5069 IApplicationThread sendThumbnail = null;
5070 boolean booting = false;
5071 boolean enableScreen = false;
5072
5073 synchronized (this) {
5074 if (token != null) {
5075 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5076 }
5077
5078 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005079 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005080 if (index >= 0) {
5081 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5082
5083 // No longer need to keep the device awake.
5084 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5085 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5086 mLaunchingActivity.release();
5087 }
5088
5089 // We are now idle. If someone is waiting for a thumbnail from
5090 // us, we can now deliver.
5091 r.idle = true;
5092 scheduleAppGcsLocked();
5093 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5094 sendThumbnail = r.app.thread;
5095 r.thumbnailNeeded = false;
5096 }
5097
5098 // If this activity is fullscreen, set up to hide those under it.
5099
5100 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5101 ensureActivitiesVisibleLocked(null, 0);
5102
5103 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5104 if (!mBooted && !fromTimeout) {
5105 mBooted = true;
5106 enableScreen = true;
5107 }
5108 }
5109
5110 // Atomically retrieve all of the other things to do.
5111 stops = processStoppingActivitiesLocked(true);
5112 NS = stops != null ? stops.size() : 0;
5113 if ((NF=mFinishingActivities.size()) > 0) {
5114 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5115 mFinishingActivities.clear();
5116 }
5117 if ((NT=mCancelledThumbnails.size()) > 0) {
5118 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5119 mCancelledThumbnails.clear();
5120 }
5121
5122 booting = mBooting;
5123 mBooting = false;
5124 }
5125
5126 int i;
5127
5128 // Send thumbnail if requested.
5129 if (sendThumbnail != null) {
5130 try {
5131 sendThumbnail.requestThumbnail(token);
5132 } catch (Exception e) {
5133 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5134 sendPendingThumbnail(null, token, null, null, true);
5135 }
5136 }
5137
5138 // Stop any activities that are scheduled to do so but have been
5139 // waiting for the next one to start.
5140 for (i=0; i<NS; i++) {
5141 HistoryRecord r = (HistoryRecord)stops.get(i);
5142 synchronized (this) {
5143 if (r.finishing) {
5144 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5145 } else {
5146 stopActivityLocked(r);
5147 }
5148 }
5149 }
5150
5151 // Finish any activities that are scheduled to do so but have been
5152 // waiting for the next one to start.
5153 for (i=0; i<NF; i++) {
5154 HistoryRecord r = (HistoryRecord)finishes.get(i);
5155 synchronized (this) {
5156 destroyActivityLocked(r, true);
5157 }
5158 }
5159
5160 // Report back to any thumbnail receivers.
5161 for (i=0; i<NT; i++) {
5162 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5163 sendPendingThumbnail(r, null, null, null, true);
5164 }
5165
5166 if (booting) {
5167 // Ensure that any processes we had put on hold are now started
5168 // up.
5169 final int NP = mProcessesOnHold.size();
5170 if (NP > 0) {
5171 ArrayList<ProcessRecord> procs =
5172 new ArrayList<ProcessRecord>(mProcessesOnHold);
5173 for (int ip=0; ip<NP; ip++) {
5174 this.startProcessLocked(procs.get(ip), "on-hold", null);
5175 }
5176 }
5177 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5178 // Tell anyone interested that we are done booting!
5179 synchronized (this) {
5180 broadcastIntentLocked(null, null,
5181 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5182 null, null, 0, null, null,
5183 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5184 false, false, MY_PID, Process.SYSTEM_UID);
5185 }
5186 }
5187 }
5188
5189 trimApplications();
5190 //dump();
5191 //mWindowManager.dump();
5192
5193 if (enableScreen) {
5194 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5195 SystemClock.uptimeMillis());
5196 enableScreenAfterBoot();
5197 }
5198 }
5199
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005200 final void ensureScreenEnabled() {
5201 boolean enableScreen;
5202 synchronized (this) {
5203 enableScreen = !mBooted;
5204 mBooted = true;
5205 }
5206
5207 if (enableScreen) {
5208 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5209 SystemClock.uptimeMillis());
5210 enableScreenAfterBoot();
5211 }
5212 }
5213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005214 public final void activityPaused(IBinder token, Bundle icicle) {
5215 // Refuse possible leaked file descriptors
5216 if (icicle != null && icicle.hasFileDescriptors()) {
5217 throw new IllegalArgumentException("File descriptors passed in Bundle");
5218 }
5219
5220 final long origId = Binder.clearCallingIdentity();
5221 activityPaused(token, icicle, false);
5222 Binder.restoreCallingIdentity(origId);
5223 }
5224
5225 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5226 if (DEBUG_PAUSE) Log.v(
5227 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5228 + ", timeout=" + timeout);
5229
5230 HistoryRecord r = null;
5231
5232 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005233 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005234 if (index >= 0) {
5235 r = (HistoryRecord)mHistory.get(index);
5236 if (!timeout) {
5237 r.icicle = icicle;
5238 r.haveState = true;
5239 }
5240 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5241 if (mPausingActivity == r) {
5242 r.state = ActivityState.PAUSED;
5243 completePauseLocked();
5244 } else {
5245 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5246 System.identityHashCode(r), r.shortComponentName,
5247 mPausingActivity != null
5248 ? mPausingActivity.shortComponentName : "(none)");
5249 }
5250 }
5251 }
5252 }
5253
5254 public final void activityStopped(IBinder token, Bitmap thumbnail,
5255 CharSequence description) {
5256 if (localLOGV) Log.v(
5257 TAG, "Activity stopped: token=" + token);
5258
5259 HistoryRecord r = null;
5260
5261 final long origId = Binder.clearCallingIdentity();
5262
5263 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005264 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265 if (index >= 0) {
5266 r = (HistoryRecord)mHistory.get(index);
5267 r.thumbnail = thumbnail;
5268 r.description = description;
5269 r.stopped = true;
5270 r.state = ActivityState.STOPPED;
5271 if (!r.finishing) {
5272 if (r.configDestroy) {
5273 destroyActivityLocked(r, true);
5274 resumeTopActivityLocked(null);
5275 }
5276 }
5277 }
5278 }
5279
5280 if (r != null) {
5281 sendPendingThumbnail(r, null, null, null, false);
5282 }
5283
5284 trimApplications();
5285
5286 Binder.restoreCallingIdentity(origId);
5287 }
5288
5289 public final void activityDestroyed(IBinder token) {
5290 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5291 synchronized (this) {
5292 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5293
Dianne Hackborn75b03852009-06-12 15:43:26 -07005294 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005295 if (index >= 0) {
5296 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5297 if (r.state == ActivityState.DESTROYING) {
5298 final long origId = Binder.clearCallingIdentity();
5299 removeActivityFromHistoryLocked(r);
5300 Binder.restoreCallingIdentity(origId);
5301 }
5302 }
5303 }
5304 }
5305
5306 public String getCallingPackage(IBinder token) {
5307 synchronized (this) {
5308 HistoryRecord r = getCallingRecordLocked(token);
5309 return r != null && r.app != null ? r.app.processName : null;
5310 }
5311 }
5312
5313 public ComponentName getCallingActivity(IBinder token) {
5314 synchronized (this) {
5315 HistoryRecord r = getCallingRecordLocked(token);
5316 return r != null ? r.intent.getComponent() : null;
5317 }
5318 }
5319
5320 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005321 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005322 if (index >= 0) {
5323 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5324 if (r != null) {
5325 return r.resultTo;
5326 }
5327 }
5328 return null;
5329 }
5330
5331 public ComponentName getActivityClassForToken(IBinder token) {
5332 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005333 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005334 if (index >= 0) {
5335 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5336 return r.intent.getComponent();
5337 }
5338 return null;
5339 }
5340 }
5341
5342 public String getPackageForToken(IBinder token) {
5343 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005344 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005345 if (index >= 0) {
5346 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5347 return r.packageName;
5348 }
5349 return null;
5350 }
5351 }
5352
5353 public IIntentSender getIntentSender(int type,
5354 String packageName, IBinder token, String resultWho,
5355 int requestCode, Intent intent, String resolvedType, int flags) {
5356 // Refuse possible leaked file descriptors
5357 if (intent != null && intent.hasFileDescriptors() == true) {
5358 throw new IllegalArgumentException("File descriptors passed in Intent");
5359 }
5360
5361 synchronized(this) {
5362 int callingUid = Binder.getCallingUid();
5363 try {
5364 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5365 Process.supportsProcesses()) {
5366 int uid = ActivityThread.getPackageManager()
5367 .getPackageUid(packageName);
5368 if (uid != Binder.getCallingUid()) {
5369 String msg = "Permission Denial: getIntentSender() from pid="
5370 + Binder.getCallingPid()
5371 + ", uid=" + Binder.getCallingUid()
5372 + ", (need uid=" + uid + ")"
5373 + " is not allowed to send as package " + packageName;
5374 Log.w(TAG, msg);
5375 throw new SecurityException(msg);
5376 }
5377 }
5378 } catch (RemoteException e) {
5379 throw new SecurityException(e);
5380 }
5381 HistoryRecord activity = null;
5382 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005383 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005384 if (index < 0) {
5385 return null;
5386 }
5387 activity = (HistoryRecord)mHistory.get(index);
5388 if (activity.finishing) {
5389 return null;
5390 }
5391 }
5392
5393 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5394 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5395 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5396 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5397 |PendingIntent.FLAG_UPDATE_CURRENT);
5398
5399 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5400 type, packageName, activity, resultWho,
5401 requestCode, intent, resolvedType, flags);
5402 WeakReference<PendingIntentRecord> ref;
5403 ref = mIntentSenderRecords.get(key);
5404 PendingIntentRecord rec = ref != null ? ref.get() : null;
5405 if (rec != null) {
5406 if (!cancelCurrent) {
5407 if (updateCurrent) {
5408 rec.key.requestIntent.replaceExtras(intent);
5409 }
5410 return rec;
5411 }
5412 rec.canceled = true;
5413 mIntentSenderRecords.remove(key);
5414 }
5415 if (noCreate) {
5416 return rec;
5417 }
5418 rec = new PendingIntentRecord(this, key, callingUid);
5419 mIntentSenderRecords.put(key, rec.ref);
5420 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5421 if (activity.pendingResults == null) {
5422 activity.pendingResults
5423 = new HashSet<WeakReference<PendingIntentRecord>>();
5424 }
5425 activity.pendingResults.add(rec.ref);
5426 }
5427 return rec;
5428 }
5429 }
5430
5431 public void cancelIntentSender(IIntentSender sender) {
5432 if (!(sender instanceof PendingIntentRecord)) {
5433 return;
5434 }
5435 synchronized(this) {
5436 PendingIntentRecord rec = (PendingIntentRecord)sender;
5437 try {
5438 int uid = ActivityThread.getPackageManager()
5439 .getPackageUid(rec.key.packageName);
5440 if (uid != Binder.getCallingUid()) {
5441 String msg = "Permission Denial: cancelIntentSender() from pid="
5442 + Binder.getCallingPid()
5443 + ", uid=" + Binder.getCallingUid()
5444 + " is not allowed to cancel packges "
5445 + rec.key.packageName;
5446 Log.w(TAG, msg);
5447 throw new SecurityException(msg);
5448 }
5449 } catch (RemoteException e) {
5450 throw new SecurityException(e);
5451 }
5452 cancelIntentSenderLocked(rec, true);
5453 }
5454 }
5455
5456 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5457 rec.canceled = true;
5458 mIntentSenderRecords.remove(rec.key);
5459 if (cleanActivity && rec.key.activity != null) {
5460 rec.key.activity.pendingResults.remove(rec.ref);
5461 }
5462 }
5463
5464 public String getPackageForIntentSender(IIntentSender pendingResult) {
5465 if (!(pendingResult instanceof PendingIntentRecord)) {
5466 return null;
5467 }
5468 synchronized(this) {
5469 try {
5470 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5471 return res.key.packageName;
5472 } catch (ClassCastException e) {
5473 }
5474 }
5475 return null;
5476 }
5477
5478 public void setProcessLimit(int max) {
5479 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5480 "setProcessLimit()");
5481 mProcessLimit = max;
5482 }
5483
5484 public int getProcessLimit() {
5485 return mProcessLimit;
5486 }
5487
5488 void foregroundTokenDied(ForegroundToken token) {
5489 synchronized (ActivityManagerService.this) {
5490 synchronized (mPidsSelfLocked) {
5491 ForegroundToken cur
5492 = mForegroundProcesses.get(token.pid);
5493 if (cur != token) {
5494 return;
5495 }
5496 mForegroundProcesses.remove(token.pid);
5497 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5498 if (pr == null) {
5499 return;
5500 }
5501 pr.forcingToForeground = null;
5502 pr.foregroundServices = false;
5503 }
5504 updateOomAdjLocked();
5505 }
5506 }
5507
5508 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5509 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5510 "setProcessForeground()");
5511 synchronized(this) {
5512 boolean changed = false;
5513
5514 synchronized (mPidsSelfLocked) {
5515 ProcessRecord pr = mPidsSelfLocked.get(pid);
5516 if (pr == null) {
5517 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5518 return;
5519 }
5520 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5521 if (oldToken != null) {
5522 oldToken.token.unlinkToDeath(oldToken, 0);
5523 mForegroundProcesses.remove(pid);
5524 pr.forcingToForeground = null;
5525 changed = true;
5526 }
5527 if (isForeground && token != null) {
5528 ForegroundToken newToken = new ForegroundToken() {
5529 public void binderDied() {
5530 foregroundTokenDied(this);
5531 }
5532 };
5533 newToken.pid = pid;
5534 newToken.token = token;
5535 try {
5536 token.linkToDeath(newToken, 0);
5537 mForegroundProcesses.put(pid, newToken);
5538 pr.forcingToForeground = token;
5539 changed = true;
5540 } catch (RemoteException e) {
5541 // If the process died while doing this, we will later
5542 // do the cleanup with the process death link.
5543 }
5544 }
5545 }
5546
5547 if (changed) {
5548 updateOomAdjLocked();
5549 }
5550 }
5551 }
5552
5553 // =========================================================
5554 // PERMISSIONS
5555 // =========================================================
5556
5557 static class PermissionController extends IPermissionController.Stub {
5558 ActivityManagerService mActivityManagerService;
5559 PermissionController(ActivityManagerService activityManagerService) {
5560 mActivityManagerService = activityManagerService;
5561 }
5562
5563 public boolean checkPermission(String permission, int pid, int uid) {
5564 return mActivityManagerService.checkPermission(permission, pid,
5565 uid) == PackageManager.PERMISSION_GRANTED;
5566 }
5567 }
5568
5569 /**
5570 * This can be called with or without the global lock held.
5571 */
5572 int checkComponentPermission(String permission, int pid, int uid,
5573 int reqUid) {
5574 // We might be performing an operation on behalf of an indirect binder
5575 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5576 // client identity accordingly before proceeding.
5577 Identity tlsIdentity = sCallerIdentity.get();
5578 if (tlsIdentity != null) {
5579 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5580 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5581 uid = tlsIdentity.uid;
5582 pid = tlsIdentity.pid;
5583 }
5584
5585 // Root, system server and our own process get to do everything.
5586 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5587 !Process.supportsProcesses()) {
5588 return PackageManager.PERMISSION_GRANTED;
5589 }
5590 // If the target requires a specific UID, always fail for others.
5591 if (reqUid >= 0 && uid != reqUid) {
5592 return PackageManager.PERMISSION_DENIED;
5593 }
5594 if (permission == null) {
5595 return PackageManager.PERMISSION_GRANTED;
5596 }
5597 try {
5598 return ActivityThread.getPackageManager()
5599 .checkUidPermission(permission, uid);
5600 } catch (RemoteException e) {
5601 // Should never happen, but if it does... deny!
5602 Log.e(TAG, "PackageManager is dead?!?", e);
5603 }
5604 return PackageManager.PERMISSION_DENIED;
5605 }
5606
5607 /**
5608 * As the only public entry point for permissions checking, this method
5609 * can enforce the semantic that requesting a check on a null global
5610 * permission is automatically denied. (Internally a null permission
5611 * string is used when calling {@link #checkComponentPermission} in cases
5612 * when only uid-based security is needed.)
5613 *
5614 * This can be called with or without the global lock held.
5615 */
5616 public int checkPermission(String permission, int pid, int uid) {
5617 if (permission == null) {
5618 return PackageManager.PERMISSION_DENIED;
5619 }
5620 return checkComponentPermission(permission, pid, uid, -1);
5621 }
5622
5623 /**
5624 * Binder IPC calls go through the public entry point.
5625 * This can be called with or without the global lock held.
5626 */
5627 int checkCallingPermission(String permission) {
5628 return checkPermission(permission,
5629 Binder.getCallingPid(),
5630 Binder.getCallingUid());
5631 }
5632
5633 /**
5634 * This can be called with or without the global lock held.
5635 */
5636 void enforceCallingPermission(String permission, String func) {
5637 if (checkCallingPermission(permission)
5638 == PackageManager.PERMISSION_GRANTED) {
5639 return;
5640 }
5641
5642 String msg = "Permission Denial: " + func + " from pid="
5643 + Binder.getCallingPid()
5644 + ", uid=" + Binder.getCallingUid()
5645 + " requires " + permission;
5646 Log.w(TAG, msg);
5647 throw new SecurityException(msg);
5648 }
5649
5650 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5651 ProviderInfo pi, int uid, int modeFlags) {
5652 try {
5653 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5654 if ((pi.readPermission != null) &&
5655 (pm.checkUidPermission(pi.readPermission, uid)
5656 != PackageManager.PERMISSION_GRANTED)) {
5657 return false;
5658 }
5659 }
5660 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5661 if ((pi.writePermission != null) &&
5662 (pm.checkUidPermission(pi.writePermission, uid)
5663 != PackageManager.PERMISSION_GRANTED)) {
5664 return false;
5665 }
5666 }
5667 return true;
5668 } catch (RemoteException e) {
5669 return false;
5670 }
5671 }
5672
5673 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5674 int modeFlags) {
5675 // Root gets to do everything.
5676 if (uid == 0 || !Process.supportsProcesses()) {
5677 return true;
5678 }
5679 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5680 if (perms == null) return false;
5681 UriPermission perm = perms.get(uri);
5682 if (perm == null) return false;
5683 return (modeFlags&perm.modeFlags) == modeFlags;
5684 }
5685
5686 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5687 // Another redirected-binder-call permissions check as in
5688 // {@link checkComponentPermission}.
5689 Identity tlsIdentity = sCallerIdentity.get();
5690 if (tlsIdentity != null) {
5691 uid = tlsIdentity.uid;
5692 pid = tlsIdentity.pid;
5693 }
5694
5695 // Our own process gets to do everything.
5696 if (pid == MY_PID) {
5697 return PackageManager.PERMISSION_GRANTED;
5698 }
5699 synchronized(this) {
5700 return checkUriPermissionLocked(uri, uid, modeFlags)
5701 ? PackageManager.PERMISSION_GRANTED
5702 : PackageManager.PERMISSION_DENIED;
5703 }
5704 }
5705
5706 private void grantUriPermissionLocked(int callingUid,
5707 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5708 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5709 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5710 if (modeFlags == 0) {
5711 return;
5712 }
5713
5714 final IPackageManager pm = ActivityThread.getPackageManager();
5715
5716 // If this is not a content: uri, we can't do anything with it.
5717 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5718 return;
5719 }
5720
5721 String name = uri.getAuthority();
5722 ProviderInfo pi = null;
5723 ContentProviderRecord cpr
5724 = (ContentProviderRecord)mProvidersByName.get(name);
5725 if (cpr != null) {
5726 pi = cpr.info;
5727 } else {
5728 try {
5729 pi = pm.resolveContentProvider(name,
5730 PackageManager.GET_URI_PERMISSION_PATTERNS);
5731 } catch (RemoteException ex) {
5732 }
5733 }
5734 if (pi == null) {
5735 Log.w(TAG, "No content provider found for: " + name);
5736 return;
5737 }
5738
5739 int targetUid;
5740 try {
5741 targetUid = pm.getPackageUid(targetPkg);
5742 if (targetUid < 0) {
5743 return;
5744 }
5745 } catch (RemoteException ex) {
5746 return;
5747 }
5748
5749 // First... does the target actually need this permission?
5750 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5751 // No need to grant the target this permission.
5752 return;
5753 }
5754
5755 // Second... maybe someone else has already granted the
5756 // permission?
5757 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5758 // No need to grant the target this permission.
5759 return;
5760 }
5761
5762 // Third... is the provider allowing granting of URI permissions?
5763 if (!pi.grantUriPermissions) {
5764 throw new SecurityException("Provider " + pi.packageName
5765 + "/" + pi.name
5766 + " does not allow granting of Uri permissions (uri "
5767 + uri + ")");
5768 }
5769 if (pi.uriPermissionPatterns != null) {
5770 final int N = pi.uriPermissionPatterns.length;
5771 boolean allowed = false;
5772 for (int i=0; i<N; i++) {
5773 if (pi.uriPermissionPatterns[i] != null
5774 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5775 allowed = true;
5776 break;
5777 }
5778 }
5779 if (!allowed) {
5780 throw new SecurityException("Provider " + pi.packageName
5781 + "/" + pi.name
5782 + " does not allow granting of permission to path of Uri "
5783 + uri);
5784 }
5785 }
5786
5787 // Fourth... does the caller itself have permission to access
5788 // this uri?
5789 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5790 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5791 throw new SecurityException("Uid " + callingUid
5792 + " does not have permission to uri " + uri);
5793 }
5794 }
5795
5796 // Okay! So here we are: the caller has the assumed permission
5797 // to the uri, and the target doesn't. Let's now give this to
5798 // the target.
5799
5800 HashMap<Uri, UriPermission> targetUris
5801 = mGrantedUriPermissions.get(targetUid);
5802 if (targetUris == null) {
5803 targetUris = new HashMap<Uri, UriPermission>();
5804 mGrantedUriPermissions.put(targetUid, targetUris);
5805 }
5806
5807 UriPermission perm = targetUris.get(uri);
5808 if (perm == null) {
5809 perm = new UriPermission(targetUid, uri);
5810 targetUris.put(uri, perm);
5811
5812 }
5813 perm.modeFlags |= modeFlags;
5814 if (activity == null) {
5815 perm.globalModeFlags |= modeFlags;
5816 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5817 perm.readActivities.add(activity);
5818 if (activity.readUriPermissions == null) {
5819 activity.readUriPermissions = new HashSet<UriPermission>();
5820 }
5821 activity.readUriPermissions.add(perm);
5822 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5823 perm.writeActivities.add(activity);
5824 if (activity.writeUriPermissions == null) {
5825 activity.writeUriPermissions = new HashSet<UriPermission>();
5826 }
5827 activity.writeUriPermissions.add(perm);
5828 }
5829 }
5830
5831 private void grantUriPermissionFromIntentLocked(int callingUid,
5832 String targetPkg, Intent intent, HistoryRecord activity) {
5833 if (intent == null) {
5834 return;
5835 }
5836 Uri data = intent.getData();
5837 if (data == null) {
5838 return;
5839 }
5840 grantUriPermissionLocked(callingUid, targetPkg, data,
5841 intent.getFlags(), activity);
5842 }
5843
5844 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5845 Uri uri, int modeFlags) {
5846 synchronized(this) {
5847 final ProcessRecord r = getRecordForAppLocked(caller);
5848 if (r == null) {
5849 throw new SecurityException("Unable to find app for caller "
5850 + caller
5851 + " when granting permission to uri " + uri);
5852 }
5853 if (targetPkg == null) {
5854 Log.w(TAG, "grantUriPermission: null target");
5855 return;
5856 }
5857 if (uri == null) {
5858 Log.w(TAG, "grantUriPermission: null uri");
5859 return;
5860 }
5861
5862 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5863 null);
5864 }
5865 }
5866
5867 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5868 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5869 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5870 HashMap<Uri, UriPermission> perms
5871 = mGrantedUriPermissions.get(perm.uid);
5872 if (perms != null) {
5873 perms.remove(perm.uri);
5874 if (perms.size() == 0) {
5875 mGrantedUriPermissions.remove(perm.uid);
5876 }
5877 }
5878 }
5879 }
5880
5881 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5882 if (activity.readUriPermissions != null) {
5883 for (UriPermission perm : activity.readUriPermissions) {
5884 perm.readActivities.remove(activity);
5885 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5886 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5887 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5888 removeUriPermissionIfNeededLocked(perm);
5889 }
5890 }
5891 }
5892 if (activity.writeUriPermissions != null) {
5893 for (UriPermission perm : activity.writeUriPermissions) {
5894 perm.writeActivities.remove(activity);
5895 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5896 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5897 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5898 removeUriPermissionIfNeededLocked(perm);
5899 }
5900 }
5901 }
5902 }
5903
5904 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5905 int modeFlags) {
5906 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5907 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5908 if (modeFlags == 0) {
5909 return;
5910 }
5911
5912 final IPackageManager pm = ActivityThread.getPackageManager();
5913
5914 final String authority = uri.getAuthority();
5915 ProviderInfo pi = null;
5916 ContentProviderRecord cpr
5917 = (ContentProviderRecord)mProvidersByName.get(authority);
5918 if (cpr != null) {
5919 pi = cpr.info;
5920 } else {
5921 try {
5922 pi = pm.resolveContentProvider(authority,
5923 PackageManager.GET_URI_PERMISSION_PATTERNS);
5924 } catch (RemoteException ex) {
5925 }
5926 }
5927 if (pi == null) {
5928 Log.w(TAG, "No content provider found for: " + authority);
5929 return;
5930 }
5931
5932 // Does the caller have this permission on the URI?
5933 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5934 // Right now, if you are not the original owner of the permission,
5935 // you are not allowed to revoke it.
5936 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5937 throw new SecurityException("Uid " + callingUid
5938 + " does not have permission to uri " + uri);
5939 //}
5940 }
5941
5942 // Go through all of the permissions and remove any that match.
5943 final List<String> SEGMENTS = uri.getPathSegments();
5944 if (SEGMENTS != null) {
5945 final int NS = SEGMENTS.size();
5946 int N = mGrantedUriPermissions.size();
5947 for (int i=0; i<N; i++) {
5948 HashMap<Uri, UriPermission> perms
5949 = mGrantedUriPermissions.valueAt(i);
5950 Iterator<UriPermission> it = perms.values().iterator();
5951 toploop:
5952 while (it.hasNext()) {
5953 UriPermission perm = it.next();
5954 Uri targetUri = perm.uri;
5955 if (!authority.equals(targetUri.getAuthority())) {
5956 continue;
5957 }
5958 List<String> targetSegments = targetUri.getPathSegments();
5959 if (targetSegments == null) {
5960 continue;
5961 }
5962 if (targetSegments.size() < NS) {
5963 continue;
5964 }
5965 for (int j=0; j<NS; j++) {
5966 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5967 continue toploop;
5968 }
5969 }
5970 perm.clearModes(modeFlags);
5971 if (perm.modeFlags == 0) {
5972 it.remove();
5973 }
5974 }
5975 if (perms.size() == 0) {
5976 mGrantedUriPermissions.remove(
5977 mGrantedUriPermissions.keyAt(i));
5978 N--;
5979 i--;
5980 }
5981 }
5982 }
5983 }
5984
5985 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5986 int modeFlags) {
5987 synchronized(this) {
5988 final ProcessRecord r = getRecordForAppLocked(caller);
5989 if (r == null) {
5990 throw new SecurityException("Unable to find app for caller "
5991 + caller
5992 + " when revoking permission to uri " + uri);
5993 }
5994 if (uri == null) {
5995 Log.w(TAG, "revokeUriPermission: null uri");
5996 return;
5997 }
5998
5999 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6000 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6001 if (modeFlags == 0) {
6002 return;
6003 }
6004
6005 final IPackageManager pm = ActivityThread.getPackageManager();
6006
6007 final String authority = uri.getAuthority();
6008 ProviderInfo pi = null;
6009 ContentProviderRecord cpr
6010 = (ContentProviderRecord)mProvidersByName.get(authority);
6011 if (cpr != null) {
6012 pi = cpr.info;
6013 } else {
6014 try {
6015 pi = pm.resolveContentProvider(authority,
6016 PackageManager.GET_URI_PERMISSION_PATTERNS);
6017 } catch (RemoteException ex) {
6018 }
6019 }
6020 if (pi == null) {
6021 Log.w(TAG, "No content provider found for: " + authority);
6022 return;
6023 }
6024
6025 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6026 }
6027 }
6028
6029 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6030 synchronized (this) {
6031 ProcessRecord app =
6032 who != null ? getRecordForAppLocked(who) : null;
6033 if (app == null) return;
6034
6035 Message msg = Message.obtain();
6036 msg.what = WAIT_FOR_DEBUGGER_MSG;
6037 msg.obj = app;
6038 msg.arg1 = waiting ? 1 : 0;
6039 mHandler.sendMessage(msg);
6040 }
6041 }
6042
6043 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6044 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006045 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006046 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006047 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006048 }
6049
6050 // =========================================================
6051 // TASK MANAGEMENT
6052 // =========================================================
6053
6054 public List getTasks(int maxNum, int flags,
6055 IThumbnailReceiver receiver) {
6056 ArrayList list = new ArrayList();
6057
6058 PendingThumbnailsRecord pending = null;
6059 IApplicationThread topThumbnail = null;
6060 HistoryRecord topRecord = null;
6061
6062 synchronized(this) {
6063 if (localLOGV) Log.v(
6064 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6065 + ", receiver=" + receiver);
6066
6067 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6068 != PackageManager.PERMISSION_GRANTED) {
6069 if (receiver != null) {
6070 // If the caller wants to wait for pending thumbnails,
6071 // it ain't gonna get them.
6072 try {
6073 receiver.finished();
6074 } catch (RemoteException ex) {
6075 }
6076 }
6077 String msg = "Permission Denial: getTasks() from pid="
6078 + Binder.getCallingPid()
6079 + ", uid=" + Binder.getCallingUid()
6080 + " requires " + android.Manifest.permission.GET_TASKS;
6081 Log.w(TAG, msg);
6082 throw new SecurityException(msg);
6083 }
6084
6085 int pos = mHistory.size()-1;
6086 HistoryRecord next =
6087 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6088 HistoryRecord top = null;
6089 CharSequence topDescription = null;
6090 TaskRecord curTask = null;
6091 int numActivities = 0;
6092 int numRunning = 0;
6093 while (pos >= 0 && maxNum > 0) {
6094 final HistoryRecord r = next;
6095 pos--;
6096 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6097
6098 // Initialize state for next task if needed.
6099 if (top == null ||
6100 (top.state == ActivityState.INITIALIZING
6101 && top.task == r.task)) {
6102 top = r;
6103 topDescription = r.description;
6104 curTask = r.task;
6105 numActivities = numRunning = 0;
6106 }
6107
6108 // Add 'r' into the current task.
6109 numActivities++;
6110 if (r.app != null && r.app.thread != null) {
6111 numRunning++;
6112 }
6113 if (topDescription == null) {
6114 topDescription = r.description;
6115 }
6116
6117 if (localLOGV) Log.v(
6118 TAG, r.intent.getComponent().flattenToShortString()
6119 + ": task=" + r.task);
6120
6121 // If the next one is a different task, generate a new
6122 // TaskInfo entry for what we have.
6123 if (next == null || next.task != curTask) {
6124 ActivityManager.RunningTaskInfo ci
6125 = new ActivityManager.RunningTaskInfo();
6126 ci.id = curTask.taskId;
6127 ci.baseActivity = r.intent.getComponent();
6128 ci.topActivity = top.intent.getComponent();
6129 ci.thumbnail = top.thumbnail;
6130 ci.description = topDescription;
6131 ci.numActivities = numActivities;
6132 ci.numRunning = numRunning;
6133 //System.out.println(
6134 // "#" + maxNum + ": " + " descr=" + ci.description);
6135 if (ci.thumbnail == null && receiver != null) {
6136 if (localLOGV) Log.v(
6137 TAG, "State=" + top.state + "Idle=" + top.idle
6138 + " app=" + top.app
6139 + " thr=" + (top.app != null ? top.app.thread : null));
6140 if (top.state == ActivityState.RESUMED
6141 || top.state == ActivityState.PAUSING) {
6142 if (top.idle && top.app != null
6143 && top.app.thread != null) {
6144 topRecord = top;
6145 topThumbnail = top.app.thread;
6146 } else {
6147 top.thumbnailNeeded = true;
6148 }
6149 }
6150 if (pending == null) {
6151 pending = new PendingThumbnailsRecord(receiver);
6152 }
6153 pending.pendingRecords.add(top);
6154 }
6155 list.add(ci);
6156 maxNum--;
6157 top = null;
6158 }
6159 }
6160
6161 if (pending != null) {
6162 mPendingThumbnails.add(pending);
6163 }
6164 }
6165
6166 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6167
6168 if (topThumbnail != null) {
6169 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6170 try {
6171 topThumbnail.requestThumbnail(topRecord);
6172 } catch (Exception e) {
6173 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6174 sendPendingThumbnail(null, topRecord, null, null, true);
6175 }
6176 }
6177
6178 if (pending == null && receiver != null) {
6179 // In this case all thumbnails were available and the client
6180 // is being asked to be told when the remaining ones come in...
6181 // which is unusually, since the top-most currently running
6182 // activity should never have a canned thumbnail! Oh well.
6183 try {
6184 receiver.finished();
6185 } catch (RemoteException ex) {
6186 }
6187 }
6188
6189 return list;
6190 }
6191
6192 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6193 int flags) {
6194 synchronized (this) {
6195 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6196 "getRecentTasks()");
6197
6198 final int N = mRecentTasks.size();
6199 ArrayList<ActivityManager.RecentTaskInfo> res
6200 = new ArrayList<ActivityManager.RecentTaskInfo>(
6201 maxNum < N ? maxNum : N);
6202 for (int i=0; i<N && maxNum > 0; i++) {
6203 TaskRecord tr = mRecentTasks.get(i);
6204 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6205 || (tr.intent == null)
6206 || ((tr.intent.getFlags()
6207 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6208 ActivityManager.RecentTaskInfo rti
6209 = new ActivityManager.RecentTaskInfo();
6210 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6211 rti.baseIntent = new Intent(
6212 tr.intent != null ? tr.intent : tr.affinityIntent);
6213 rti.origActivity = tr.origActivity;
6214 res.add(rti);
6215 maxNum--;
6216 }
6217 }
6218 return res;
6219 }
6220 }
6221
6222 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6223 int j;
6224 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6225 TaskRecord jt = startTask;
6226
6227 // First look backwards
6228 for (j=startIndex-1; j>=0; j--) {
6229 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6230 if (r.task != jt) {
6231 jt = r.task;
6232 if (affinity.equals(jt.affinity)) {
6233 return j;
6234 }
6235 }
6236 }
6237
6238 // Now look forwards
6239 final int N = mHistory.size();
6240 jt = startTask;
6241 for (j=startIndex+1; j<N; j++) {
6242 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6243 if (r.task != jt) {
6244 if (affinity.equals(jt.affinity)) {
6245 return j;
6246 }
6247 jt = r.task;
6248 }
6249 }
6250
6251 // Might it be at the top?
6252 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6253 return N-1;
6254 }
6255
6256 return -1;
6257 }
6258
6259 /**
6260 * Perform a reset of the given task, if needed as part of launching it.
6261 * Returns the new HistoryRecord at the top of the task.
6262 */
6263 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6264 HistoryRecord newActivity) {
6265 boolean forceReset = (newActivity.info.flags
6266 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6267 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6268 if ((newActivity.info.flags
6269 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6270 forceReset = true;
6271 }
6272 }
6273
6274 final TaskRecord task = taskTop.task;
6275
6276 // We are going to move through the history list so that we can look
6277 // at each activity 'target' with 'below' either the interesting
6278 // activity immediately below it in the stack or null.
6279 HistoryRecord target = null;
6280 int targetI = 0;
6281 int taskTopI = -1;
6282 int replyChainEnd = -1;
6283 int lastReparentPos = -1;
6284 for (int i=mHistory.size()-1; i>=-1; i--) {
6285 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6286
6287 if (below != null && below.finishing) {
6288 continue;
6289 }
6290 if (target == null) {
6291 target = below;
6292 targetI = i;
6293 // If we were in the middle of a reply chain before this
6294 // task, it doesn't appear like the root of the chain wants
6295 // anything interesting, so drop it.
6296 replyChainEnd = -1;
6297 continue;
6298 }
6299
6300 final int flags = target.info.flags;
6301
6302 final boolean finishOnTaskLaunch =
6303 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6304 final boolean allowTaskReparenting =
6305 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6306
6307 if (target.task == task) {
6308 // We are inside of the task being reset... we'll either
6309 // finish this activity, push it out for another task,
6310 // or leave it as-is. We only do this
6311 // for activities that are not the root of the task (since
6312 // if we finish the root, we may no longer have the task!).
6313 if (taskTopI < 0) {
6314 taskTopI = targetI;
6315 }
6316 if (below != null && below.task == task) {
6317 final boolean clearWhenTaskReset =
6318 (target.intent.getFlags()
6319 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006320 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006321 // If this activity is sending a reply to a previous
6322 // activity, we can't do anything with it now until
6323 // we reach the start of the reply chain.
6324 // XXX note that we are assuming the result is always
6325 // to the previous activity, which is almost always
6326 // the case but we really shouldn't count on.
6327 if (replyChainEnd < 0) {
6328 replyChainEnd = targetI;
6329 }
Ed Heyl73798232009-03-24 21:32:21 -07006330 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006331 && target.taskAffinity != null
6332 && !target.taskAffinity.equals(task.affinity)) {
6333 // If this activity has an affinity for another
6334 // task, then we need to move it out of here. We will
6335 // move it as far out of the way as possible, to the
6336 // bottom of the activity stack. This also keeps it
6337 // correctly ordered with any activities we previously
6338 // moved.
6339 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6340 if (target.taskAffinity != null
6341 && target.taskAffinity.equals(p.task.affinity)) {
6342 // If the activity currently at the bottom has the
6343 // same task affinity as the one we are moving,
6344 // then merge it into the same task.
6345 target.task = p.task;
6346 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6347 + " out to bottom task " + p.task);
6348 } else {
6349 mCurTask++;
6350 if (mCurTask <= 0) {
6351 mCurTask = 1;
6352 }
6353 target.task = new TaskRecord(mCurTask, target.info, null,
6354 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6355 target.task.affinityIntent = target.intent;
6356 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6357 + " out to new task " + target.task);
6358 }
6359 mWindowManager.setAppGroupId(target, task.taskId);
6360 if (replyChainEnd < 0) {
6361 replyChainEnd = targetI;
6362 }
6363 int dstPos = 0;
6364 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6365 p = (HistoryRecord)mHistory.get(srcPos);
6366 if (p.finishing) {
6367 continue;
6368 }
6369 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6370 + " out to target's task " + target.task);
6371 task.numActivities--;
6372 p.task = target.task;
6373 target.task.numActivities++;
6374 mHistory.remove(srcPos);
6375 mHistory.add(dstPos, p);
6376 mWindowManager.moveAppToken(dstPos, p);
6377 mWindowManager.setAppGroupId(p, p.task.taskId);
6378 dstPos++;
6379 if (VALIDATE_TOKENS) {
6380 mWindowManager.validateAppTokens(mHistory);
6381 }
6382 i++;
6383 }
6384 if (taskTop == p) {
6385 taskTop = below;
6386 }
6387 if (taskTopI == replyChainEnd) {
6388 taskTopI = -1;
6389 }
6390 replyChainEnd = -1;
6391 addRecentTask(target.task);
6392 } else if (forceReset || finishOnTaskLaunch
6393 || clearWhenTaskReset) {
6394 // If the activity should just be removed -- either
6395 // because it asks for it, or the task should be
6396 // cleared -- then finish it and anything that is
6397 // part of its reply chain.
6398 if (clearWhenTaskReset) {
6399 // In this case, we want to finish this activity
6400 // and everything above it, so be sneaky and pretend
6401 // like these are all in the reply chain.
6402 replyChainEnd = targetI+1;
6403 while (replyChainEnd < mHistory.size() &&
6404 ((HistoryRecord)mHistory.get(
6405 replyChainEnd)).task == task) {
6406 replyChainEnd++;
6407 }
6408 replyChainEnd--;
6409 } else if (replyChainEnd < 0) {
6410 replyChainEnd = targetI;
6411 }
6412 HistoryRecord p = null;
6413 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6414 p = (HistoryRecord)mHistory.get(srcPos);
6415 if (p.finishing) {
6416 continue;
6417 }
6418 if (finishActivityLocked(p, srcPos,
6419 Activity.RESULT_CANCELED, null, "reset")) {
6420 replyChainEnd--;
6421 srcPos--;
6422 }
6423 }
6424 if (taskTop == p) {
6425 taskTop = below;
6426 }
6427 if (taskTopI == replyChainEnd) {
6428 taskTopI = -1;
6429 }
6430 replyChainEnd = -1;
6431 } else {
6432 // If we were in the middle of a chain, well the
6433 // activity that started it all doesn't want anything
6434 // special, so leave it all as-is.
6435 replyChainEnd = -1;
6436 }
6437 } else {
6438 // Reached the bottom of the task -- any reply chain
6439 // should be left as-is.
6440 replyChainEnd = -1;
6441 }
6442
6443 } else if (target.resultTo != null) {
6444 // If this activity is sending a reply to a previous
6445 // activity, we can't do anything with it now until
6446 // we reach the start of the reply chain.
6447 // XXX note that we are assuming the result is always
6448 // to the previous activity, which is almost always
6449 // the case but we really shouldn't count on.
6450 if (replyChainEnd < 0) {
6451 replyChainEnd = targetI;
6452 }
6453
6454 } else if (taskTopI >= 0 && allowTaskReparenting
6455 && task.affinity != null
6456 && task.affinity.equals(target.taskAffinity)) {
6457 // We are inside of another task... if this activity has
6458 // an affinity for our task, then either remove it if we are
6459 // clearing or move it over to our task. Note that
6460 // we currently punt on the case where we are resetting a
6461 // task that is not at the top but who has activities above
6462 // with an affinity to it... this is really not a normal
6463 // case, and we will need to later pull that task to the front
6464 // and usually at that point we will do the reset and pick
6465 // up those remaining activities. (This only happens if
6466 // someone starts an activity in a new task from an activity
6467 // in a task that is not currently on top.)
6468 if (forceReset || finishOnTaskLaunch) {
6469 if (replyChainEnd < 0) {
6470 replyChainEnd = targetI;
6471 }
6472 HistoryRecord p = null;
6473 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6474 p = (HistoryRecord)mHistory.get(srcPos);
6475 if (p.finishing) {
6476 continue;
6477 }
6478 if (finishActivityLocked(p, srcPos,
6479 Activity.RESULT_CANCELED, null, "reset")) {
6480 taskTopI--;
6481 lastReparentPos--;
6482 replyChainEnd--;
6483 srcPos--;
6484 }
6485 }
6486 replyChainEnd = -1;
6487 } else {
6488 if (replyChainEnd < 0) {
6489 replyChainEnd = targetI;
6490 }
6491 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6492 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6493 if (p.finishing) {
6494 continue;
6495 }
6496 if (lastReparentPos < 0) {
6497 lastReparentPos = taskTopI;
6498 taskTop = p;
6499 } else {
6500 lastReparentPos--;
6501 }
6502 mHistory.remove(srcPos);
6503 p.task.numActivities--;
6504 p.task = task;
6505 mHistory.add(lastReparentPos, p);
6506 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6507 + " in to resetting task " + task);
6508 task.numActivities++;
6509 mWindowManager.moveAppToken(lastReparentPos, p);
6510 mWindowManager.setAppGroupId(p, p.task.taskId);
6511 if (VALIDATE_TOKENS) {
6512 mWindowManager.validateAppTokens(mHistory);
6513 }
6514 }
6515 replyChainEnd = -1;
6516
6517 // Now we've moved it in to place... but what if this is
6518 // a singleTop activity and we have put it on top of another
6519 // instance of the same activity? Then we drop the instance
6520 // below so it remains singleTop.
6521 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6522 for (int j=lastReparentPos-1; j>=0; j--) {
6523 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6524 if (p.finishing) {
6525 continue;
6526 }
6527 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6528 if (finishActivityLocked(p, j,
6529 Activity.RESULT_CANCELED, null, "replace")) {
6530 taskTopI--;
6531 lastReparentPos--;
6532 }
6533 }
6534 }
6535 }
6536 }
6537 }
6538
6539 target = below;
6540 targetI = i;
6541 }
6542
6543 return taskTop;
6544 }
6545
6546 /**
6547 * TODO: Add mWatcher hook
6548 */
6549 public void moveTaskToFront(int task) {
6550 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6551 "moveTaskToFront()");
6552
6553 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006554 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6555 Binder.getCallingUid(), "Task to front")) {
6556 return;
6557 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006558 final long origId = Binder.clearCallingIdentity();
6559 try {
6560 int N = mRecentTasks.size();
6561 for (int i=0; i<N; i++) {
6562 TaskRecord tr = mRecentTasks.get(i);
6563 if (tr.taskId == task) {
6564 moveTaskToFrontLocked(tr);
6565 return;
6566 }
6567 }
6568 for (int i=mHistory.size()-1; i>=0; i--) {
6569 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6570 if (hr.task.taskId == task) {
6571 moveTaskToFrontLocked(hr.task);
6572 return;
6573 }
6574 }
6575 } finally {
6576 Binder.restoreCallingIdentity(origId);
6577 }
6578 }
6579 }
6580
6581 private final void moveTaskToFrontLocked(TaskRecord tr) {
6582 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6583
6584 final int task = tr.taskId;
6585 int top = mHistory.size()-1;
6586
6587 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6588 // nothing to do!
6589 return;
6590 }
6591
6592 if (DEBUG_TRANSITION) Log.v(TAG,
6593 "Prepare to front transition: task=" + tr);
6594 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6595
6596 ArrayList moved = new ArrayList();
6597
6598 // Applying the affinities may have removed entries from the history,
6599 // so get the size again.
6600 top = mHistory.size()-1;
6601 int pos = top;
6602
6603 // Shift all activities with this task up to the top
6604 // of the stack, keeping them in the same internal order.
6605 while (pos >= 0) {
6606 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6607 if (localLOGV) Log.v(
6608 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6609 boolean first = true;
6610 if (r.task.taskId == task) {
6611 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6612 mHistory.remove(pos);
6613 mHistory.add(top, r);
6614 moved.add(0, r);
6615 top--;
6616 if (first) {
6617 addRecentTask(r.task);
6618 first = false;
6619 }
6620 }
6621 pos--;
6622 }
6623
6624 mWindowManager.moveAppTokensToTop(moved);
6625 if (VALIDATE_TOKENS) {
6626 mWindowManager.validateAppTokens(mHistory);
6627 }
6628
6629 finishTaskMove(task);
6630 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6631 }
6632
6633 private final void finishTaskMove(int task) {
6634 resumeTopActivityLocked(null);
6635 }
6636
6637 public void moveTaskToBack(int task) {
6638 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6639 "moveTaskToBack()");
6640
6641 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006642 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6643 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6644 Binder.getCallingUid(), "Task to back")) {
6645 return;
6646 }
6647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006648 final long origId = Binder.clearCallingIdentity();
6649 moveTaskToBackLocked(task);
6650 Binder.restoreCallingIdentity(origId);
6651 }
6652 }
6653
6654 /**
6655 * Moves an activity, and all of the other activities within the same task, to the bottom
6656 * of the history stack. The activity's order within the task is unchanged.
6657 *
6658 * @param token A reference to the activity we wish to move
6659 * @param nonRoot If false then this only works if the activity is the root
6660 * of a task; if true it will work for any activity in a task.
6661 * @return Returns true if the move completed, false if not.
6662 */
6663 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6664 synchronized(this) {
6665 final long origId = Binder.clearCallingIdentity();
6666 int taskId = getTaskForActivityLocked(token, !nonRoot);
6667 if (taskId >= 0) {
6668 return moveTaskToBackLocked(taskId);
6669 }
6670 Binder.restoreCallingIdentity(origId);
6671 }
6672 return false;
6673 }
6674
6675 /**
6676 * Worker method for rearranging history stack. Implements the function of moving all
6677 * activities for a specific task (gathering them if disjoint) into a single group at the
6678 * bottom of the stack.
6679 *
6680 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6681 * to premeptively cancel the move.
6682 *
6683 * @param task The taskId to collect and move to the bottom.
6684 * @return Returns true if the move completed, false if not.
6685 */
6686 private final boolean moveTaskToBackLocked(int task) {
6687 Log.i(TAG, "moveTaskToBack: " + task);
6688
6689 // If we have a watcher, preflight the move before committing to it. First check
6690 // for *other* available tasks, but if none are available, then try again allowing the
6691 // current task to be selected.
6692 if (mWatcher != null) {
6693 HistoryRecord next = topRunningActivityLocked(null, task);
6694 if (next == null) {
6695 next = topRunningActivityLocked(null, 0);
6696 }
6697 if (next != null) {
6698 // ask watcher if this is allowed
6699 boolean moveOK = true;
6700 try {
6701 moveOK = mWatcher.activityResuming(next.packageName);
6702 } catch (RemoteException e) {
6703 mWatcher = null;
6704 }
6705 if (!moveOK) {
6706 return false;
6707 }
6708 }
6709 }
6710
6711 ArrayList moved = new ArrayList();
6712
6713 if (DEBUG_TRANSITION) Log.v(TAG,
6714 "Prepare to back transition: task=" + task);
6715 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6716
6717 final int N = mHistory.size();
6718 int bottom = 0;
6719 int pos = 0;
6720
6721 // Shift all activities with this task down to the bottom
6722 // of the stack, keeping them in the same internal order.
6723 while (pos < N) {
6724 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6725 if (localLOGV) Log.v(
6726 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6727 if (r.task.taskId == task) {
6728 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6729 mHistory.remove(pos);
6730 mHistory.add(bottom, r);
6731 moved.add(r);
6732 bottom++;
6733 }
6734 pos++;
6735 }
6736
6737 mWindowManager.moveAppTokensToBottom(moved);
6738 if (VALIDATE_TOKENS) {
6739 mWindowManager.validateAppTokens(mHistory);
6740 }
6741
6742 finishTaskMove(task);
6743 return true;
6744 }
6745
6746 public void moveTaskBackwards(int task) {
6747 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6748 "moveTaskBackwards()");
6749
6750 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006751 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6752 Binder.getCallingUid(), "Task backwards")) {
6753 return;
6754 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006755 final long origId = Binder.clearCallingIdentity();
6756 moveTaskBackwardsLocked(task);
6757 Binder.restoreCallingIdentity(origId);
6758 }
6759 }
6760
6761 private final void moveTaskBackwardsLocked(int task) {
6762 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6763 }
6764
6765 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6766 synchronized(this) {
6767 return getTaskForActivityLocked(token, onlyRoot);
6768 }
6769 }
6770
6771 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6772 final int N = mHistory.size();
6773 TaskRecord lastTask = null;
6774 for (int i=0; i<N; i++) {
6775 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6776 if (r == token) {
6777 if (!onlyRoot || lastTask != r.task) {
6778 return r.task.taskId;
6779 }
6780 return -1;
6781 }
6782 lastTask = r.task;
6783 }
6784
6785 return -1;
6786 }
6787
6788 /**
6789 * Returns the top activity in any existing task matching the given
6790 * Intent. Returns null if no such task is found.
6791 */
6792 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6793 ComponentName cls = intent.getComponent();
6794 if (info.targetActivity != null) {
6795 cls = new ComponentName(info.packageName, info.targetActivity);
6796 }
6797
6798 TaskRecord cp = null;
6799
6800 final int N = mHistory.size();
6801 for (int i=(N-1); i>=0; i--) {
6802 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6803 if (!r.finishing && r.task != cp
6804 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6805 cp = r.task;
6806 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6807 // + "/aff=" + r.task.affinity + " to new cls="
6808 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6809 if (r.task.affinity != null) {
6810 if (r.task.affinity.equals(info.taskAffinity)) {
6811 //Log.i(TAG, "Found matching affinity!");
6812 return r;
6813 }
6814 } else if (r.task.intent != null
6815 && r.task.intent.getComponent().equals(cls)) {
6816 //Log.i(TAG, "Found matching class!");
6817 //dump();
6818 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6819 return r;
6820 } else if (r.task.affinityIntent != null
6821 && r.task.affinityIntent.getComponent().equals(cls)) {
6822 //Log.i(TAG, "Found matching class!");
6823 //dump();
6824 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6825 return r;
6826 }
6827 }
6828 }
6829
6830 return null;
6831 }
6832
6833 /**
6834 * Returns the first activity (starting from the top of the stack) that
6835 * is the same as the given activity. Returns null if no such activity
6836 * is found.
6837 */
6838 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6839 ComponentName cls = intent.getComponent();
6840 if (info.targetActivity != null) {
6841 cls = new ComponentName(info.packageName, info.targetActivity);
6842 }
6843
6844 final int N = mHistory.size();
6845 for (int i=(N-1); i>=0; i--) {
6846 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6847 if (!r.finishing) {
6848 if (r.intent.getComponent().equals(cls)) {
6849 //Log.i(TAG, "Found matching class!");
6850 //dump();
6851 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6852 return r;
6853 }
6854 }
6855 }
6856
6857 return null;
6858 }
6859
6860 public void finishOtherInstances(IBinder token, ComponentName className) {
6861 synchronized(this) {
6862 final long origId = Binder.clearCallingIdentity();
6863
6864 int N = mHistory.size();
6865 TaskRecord lastTask = null;
6866 for (int i=0; i<N; i++) {
6867 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6868 if (r.realActivity.equals(className)
6869 && r != token && lastTask != r.task) {
6870 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6871 null, "others")) {
6872 i--;
6873 N--;
6874 }
6875 }
6876 lastTask = r.task;
6877 }
6878
6879 Binder.restoreCallingIdentity(origId);
6880 }
6881 }
6882
6883 // =========================================================
6884 // THUMBNAILS
6885 // =========================================================
6886
6887 public void reportThumbnail(IBinder token,
6888 Bitmap thumbnail, CharSequence description) {
6889 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6890 final long origId = Binder.clearCallingIdentity();
6891 sendPendingThumbnail(null, token, thumbnail, description, true);
6892 Binder.restoreCallingIdentity(origId);
6893 }
6894
6895 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6896 Bitmap thumbnail, CharSequence description, boolean always) {
6897 TaskRecord task = null;
6898 ArrayList receivers = null;
6899
6900 //System.out.println("Send pending thumbnail: " + r);
6901
6902 synchronized(this) {
6903 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006904 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006905 if (index < 0) {
6906 return;
6907 }
6908 r = (HistoryRecord)mHistory.get(index);
6909 }
6910 if (thumbnail == null) {
6911 thumbnail = r.thumbnail;
6912 description = r.description;
6913 }
6914 if (thumbnail == null && !always) {
6915 // If there is no thumbnail, and this entry is not actually
6916 // going away, then abort for now and pick up the next
6917 // thumbnail we get.
6918 return;
6919 }
6920 task = r.task;
6921
6922 int N = mPendingThumbnails.size();
6923 int i=0;
6924 while (i<N) {
6925 PendingThumbnailsRecord pr =
6926 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6927 //System.out.println("Looking in " + pr.pendingRecords);
6928 if (pr.pendingRecords.remove(r)) {
6929 if (receivers == null) {
6930 receivers = new ArrayList();
6931 }
6932 receivers.add(pr);
6933 if (pr.pendingRecords.size() == 0) {
6934 pr.finished = true;
6935 mPendingThumbnails.remove(i);
6936 N--;
6937 continue;
6938 }
6939 }
6940 i++;
6941 }
6942 }
6943
6944 if (receivers != null) {
6945 final int N = receivers.size();
6946 for (int i=0; i<N; i++) {
6947 try {
6948 PendingThumbnailsRecord pr =
6949 (PendingThumbnailsRecord)receivers.get(i);
6950 pr.receiver.newThumbnail(
6951 task != null ? task.taskId : -1, thumbnail, description);
6952 if (pr.finished) {
6953 pr.receiver.finished();
6954 }
6955 } catch (Exception e) {
6956 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6957 }
6958 }
6959 }
6960 }
6961
6962 // =========================================================
6963 // CONTENT PROVIDERS
6964 // =========================================================
6965
6966 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6967 List providers = null;
6968 try {
6969 providers = ActivityThread.getPackageManager().
6970 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006971 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006972 } catch (RemoteException ex) {
6973 }
6974 if (providers != null) {
6975 final int N = providers.size();
6976 for (int i=0; i<N; i++) {
6977 ProviderInfo cpi =
6978 (ProviderInfo)providers.get(i);
6979 ContentProviderRecord cpr =
6980 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6981 if (cpr == null) {
6982 cpr = new ContentProviderRecord(cpi, app.info);
6983 mProvidersByClass.put(cpi.name, cpr);
6984 }
6985 app.pubProviders.put(cpi.name, cpr);
6986 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07006987 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006988 }
6989 }
6990 return providers;
6991 }
6992
6993 private final String checkContentProviderPermissionLocked(
6994 ProviderInfo cpi, ProcessRecord r, int mode) {
6995 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6996 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6997 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6998 cpi.exported ? -1 : cpi.applicationInfo.uid)
6999 == PackageManager.PERMISSION_GRANTED
7000 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7001 return null;
7002 }
7003 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7004 cpi.exported ? -1 : cpi.applicationInfo.uid)
7005 == PackageManager.PERMISSION_GRANTED) {
7006 return null;
7007 }
7008 String msg = "Permission Denial: opening provider " + cpi.name
7009 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7010 + ", uid=" + callingUid + ") requires "
7011 + cpi.readPermission + " or " + cpi.writePermission;
7012 Log.w(TAG, msg);
7013 return msg;
7014 }
7015
7016 private final ContentProviderHolder getContentProviderImpl(
7017 IApplicationThread caller, String name) {
7018 ContentProviderRecord cpr;
7019 ProviderInfo cpi = null;
7020
7021 synchronized(this) {
7022 ProcessRecord r = null;
7023 if (caller != null) {
7024 r = getRecordForAppLocked(caller);
7025 if (r == null) {
7026 throw new SecurityException(
7027 "Unable to find app for caller " + caller
7028 + " (pid=" + Binder.getCallingPid()
7029 + ") when getting content provider " + name);
7030 }
7031 }
7032
7033 // First check if this content provider has been published...
7034 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7035 if (cpr != null) {
7036 cpi = cpr.info;
7037 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7038 return new ContentProviderHolder(cpi,
7039 cpi.readPermission != null
7040 ? cpi.readPermission : cpi.writePermission);
7041 }
7042
7043 if (r != null && cpr.canRunHere(r)) {
7044 // This provider has been published or is in the process
7045 // of being published... but it is also allowed to run
7046 // in the caller's process, so don't make a connection
7047 // and just let the caller instantiate its own instance.
7048 if (cpr.provider != null) {
7049 // don't give caller the provider object, it needs
7050 // to make its own.
7051 cpr = new ContentProviderRecord(cpr);
7052 }
7053 return cpr;
7054 }
7055
7056 final long origId = Binder.clearCallingIdentity();
7057
7058 // In this case the provider is a single instance, so we can
7059 // return it right away.
7060 if (r != null) {
7061 r.conProviders.add(cpr);
7062 cpr.clients.add(r);
7063 } else {
7064 cpr.externals++;
7065 }
7066
7067 if (cpr.app != null) {
7068 updateOomAdjLocked(cpr.app);
7069 }
7070
7071 Binder.restoreCallingIdentity(origId);
7072
7073 } else {
7074 try {
7075 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007076 resolveContentProvider(name,
7077 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007078 } catch (RemoteException ex) {
7079 }
7080 if (cpi == null) {
7081 return null;
7082 }
7083
7084 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7085 return new ContentProviderHolder(cpi,
7086 cpi.readPermission != null
7087 ? cpi.readPermission : cpi.writePermission);
7088 }
7089
7090 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7091 final boolean firstClass = cpr == null;
7092 if (firstClass) {
7093 try {
7094 ApplicationInfo ai =
7095 ActivityThread.getPackageManager().
7096 getApplicationInfo(
7097 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007098 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007099 if (ai == null) {
7100 Log.w(TAG, "No package info for content provider "
7101 + cpi.name);
7102 return null;
7103 }
7104 cpr = new ContentProviderRecord(cpi, ai);
7105 } catch (RemoteException ex) {
7106 // pm is in same process, this will never happen.
7107 }
7108 }
7109
7110 if (r != null && cpr.canRunHere(r)) {
7111 // If this is a multiprocess provider, then just return its
7112 // info and allow the caller to instantiate it. Only do
7113 // this if the provider is the same user as the caller's
7114 // process, or can run as root (so can be in any process).
7115 return cpr;
7116 }
7117
7118 if (false) {
7119 RuntimeException e = new RuntimeException("foo");
7120 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7121 // + " pruid " + ai.uid + "): " + cpi.className, e);
7122 }
7123
7124 // This is single process, and our app is now connecting to it.
7125 // See if we are already in the process of launching this
7126 // provider.
7127 final int N = mLaunchingProviders.size();
7128 int i;
7129 for (i=0; i<N; i++) {
7130 if (mLaunchingProviders.get(i) == cpr) {
7131 break;
7132 }
7133 if (false) {
7134 final ContentProviderRecord rec =
7135 (ContentProviderRecord)mLaunchingProviders.get(i);
7136 if (rec.info.name.equals(cpr.info.name)) {
7137 cpr = rec;
7138 break;
7139 }
7140 }
7141 }
7142
7143 // If the provider is not already being launched, then get it
7144 // started.
7145 if (i >= N) {
7146 final long origId = Binder.clearCallingIdentity();
7147 ProcessRecord proc = startProcessLocked(cpi.processName,
7148 cpr.appInfo, false, 0, "content provider",
7149 new ComponentName(cpi.applicationInfo.packageName,
7150 cpi.name));
7151 if (proc == null) {
7152 Log.w(TAG, "Unable to launch app "
7153 + cpi.applicationInfo.packageName + "/"
7154 + cpi.applicationInfo.uid + " for provider "
7155 + name + ": process is bad");
7156 return null;
7157 }
7158 cpr.launchingApp = proc;
7159 mLaunchingProviders.add(cpr);
7160 Binder.restoreCallingIdentity(origId);
7161 }
7162
7163 // Make sure the provider is published (the same provider class
7164 // may be published under multiple names).
7165 if (firstClass) {
7166 mProvidersByClass.put(cpi.name, cpr);
7167 }
7168 mProvidersByName.put(name, cpr);
7169
7170 if (r != null) {
7171 r.conProviders.add(cpr);
7172 cpr.clients.add(r);
7173 } else {
7174 cpr.externals++;
7175 }
7176 }
7177 }
7178
7179 // Wait for the provider to be published...
7180 synchronized (cpr) {
7181 while (cpr.provider == null) {
7182 if (cpr.launchingApp == null) {
7183 Log.w(TAG, "Unable to launch app "
7184 + cpi.applicationInfo.packageName + "/"
7185 + cpi.applicationInfo.uid + " for provider "
7186 + name + ": launching app became null");
7187 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7188 cpi.applicationInfo.packageName,
7189 cpi.applicationInfo.uid, name);
7190 return null;
7191 }
7192 try {
7193 cpr.wait();
7194 } catch (InterruptedException ex) {
7195 }
7196 }
7197 }
7198 return cpr;
7199 }
7200
7201 public final ContentProviderHolder getContentProvider(
7202 IApplicationThread caller, String name) {
7203 if (caller == null) {
7204 String msg = "null IApplicationThread when getting content provider "
7205 + name;
7206 Log.w(TAG, msg);
7207 throw new SecurityException(msg);
7208 }
7209
7210 return getContentProviderImpl(caller, name);
7211 }
7212
7213 private ContentProviderHolder getContentProviderExternal(String name) {
7214 return getContentProviderImpl(null, name);
7215 }
7216
7217 /**
7218 * Drop a content provider from a ProcessRecord's bookkeeping
7219 * @param cpr
7220 */
7221 public void removeContentProvider(IApplicationThread caller, String name) {
7222 synchronized (this) {
7223 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7224 if(cpr == null) {
7225 //remove from mProvidersByClass
7226 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7227 return;
7228 }
7229 final ProcessRecord r = getRecordForAppLocked(caller);
7230 if (r == null) {
7231 throw new SecurityException(
7232 "Unable to find app for caller " + caller +
7233 " when removing content provider " + name);
7234 }
7235 //update content provider record entry info
7236 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7237 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7238 r.info.processName+" from process "+localCpr.appInfo.processName);
7239 if(localCpr.appInfo.processName == r.info.processName) {
7240 //should not happen. taken care of as a local provider
7241 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7242 return;
7243 } else {
7244 localCpr.clients.remove(r);
7245 r.conProviders.remove(localCpr);
7246 }
7247 updateOomAdjLocked();
7248 }
7249 }
7250
7251 private void removeContentProviderExternal(String name) {
7252 synchronized (this) {
7253 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7254 if(cpr == null) {
7255 //remove from mProvidersByClass
7256 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7257 return;
7258 }
7259
7260 //update content provider record entry info
7261 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7262 localCpr.externals--;
7263 if (localCpr.externals < 0) {
7264 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7265 }
7266 updateOomAdjLocked();
7267 }
7268 }
7269
7270 public final void publishContentProviders(IApplicationThread caller,
7271 List<ContentProviderHolder> providers) {
7272 if (providers == null) {
7273 return;
7274 }
7275
7276 synchronized(this) {
7277 final ProcessRecord r = getRecordForAppLocked(caller);
7278 if (r == null) {
7279 throw new SecurityException(
7280 "Unable to find app for caller " + caller
7281 + " (pid=" + Binder.getCallingPid()
7282 + ") when publishing content providers");
7283 }
7284
7285 final long origId = Binder.clearCallingIdentity();
7286
7287 final int N = providers.size();
7288 for (int i=0; i<N; i++) {
7289 ContentProviderHolder src = providers.get(i);
7290 if (src == null || src.info == null || src.provider == null) {
7291 continue;
7292 }
7293 ContentProviderRecord dst =
7294 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7295 if (dst != null) {
7296 mProvidersByClass.put(dst.info.name, dst);
7297 String names[] = dst.info.authority.split(";");
7298 for (int j = 0; j < names.length; j++) {
7299 mProvidersByName.put(names[j], dst);
7300 }
7301
7302 int NL = mLaunchingProviders.size();
7303 int j;
7304 for (j=0; j<NL; j++) {
7305 if (mLaunchingProviders.get(j) == dst) {
7306 mLaunchingProviders.remove(j);
7307 j--;
7308 NL--;
7309 }
7310 }
7311 synchronized (dst) {
7312 dst.provider = src.provider;
7313 dst.app = r;
7314 dst.notifyAll();
7315 }
7316 updateOomAdjLocked(r);
7317 }
7318 }
7319
7320 Binder.restoreCallingIdentity(origId);
7321 }
7322 }
7323
7324 public static final void installSystemProviders() {
7325 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7326 List providers = mSelf.generateApplicationProvidersLocked(app);
7327 mSystemThread.installSystemProviders(providers);
7328 }
7329
7330 // =========================================================
7331 // GLOBAL MANAGEMENT
7332 // =========================================================
7333
7334 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7335 ApplicationInfo info, String customProcess) {
7336 String proc = customProcess != null ? customProcess : info.processName;
7337 BatteryStatsImpl.Uid.Proc ps = null;
7338 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7339 synchronized (stats) {
7340 ps = stats.getProcessStatsLocked(info.uid, proc);
7341 }
7342 return new ProcessRecord(ps, thread, info, proc);
7343 }
7344
7345 final ProcessRecord addAppLocked(ApplicationInfo info) {
7346 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7347
7348 if (app == null) {
7349 app = newProcessRecordLocked(null, info, null);
7350 mProcessNames.put(info.processName, info.uid, app);
7351 updateLRUListLocked(app, true);
7352 }
7353
7354 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7355 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7356 app.persistent = true;
7357 app.maxAdj = CORE_SERVER_ADJ;
7358 }
7359 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7360 mPersistentStartingProcesses.add(app);
7361 startProcessLocked(app, "added application", app.processName);
7362 }
7363
7364 return app;
7365 }
7366
7367 public void unhandledBack() {
7368 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7369 "unhandledBack()");
7370
7371 synchronized(this) {
7372 int count = mHistory.size();
7373 if (Config.LOGD) Log.d(
7374 TAG, "Performing unhandledBack(): stack size = " + count);
7375 if (count > 1) {
7376 final long origId = Binder.clearCallingIdentity();
7377 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7378 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7379 Binder.restoreCallingIdentity(origId);
7380 }
7381 }
7382 }
7383
7384 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7385 String name = uri.getAuthority();
7386 ContentProviderHolder cph = getContentProviderExternal(name);
7387 ParcelFileDescriptor pfd = null;
7388 if (cph != null) {
7389 // We record the binder invoker's uid in thread-local storage before
7390 // going to the content provider to open the file. Later, in the code
7391 // that handles all permissions checks, we look for this uid and use
7392 // that rather than the Activity Manager's own uid. The effect is that
7393 // we do the check against the caller's permissions even though it looks
7394 // to the content provider like the Activity Manager itself is making
7395 // the request.
7396 sCallerIdentity.set(new Identity(
7397 Binder.getCallingPid(), Binder.getCallingUid()));
7398 try {
7399 pfd = cph.provider.openFile(uri, "r");
7400 } catch (FileNotFoundException e) {
7401 // do nothing; pfd will be returned null
7402 } finally {
7403 // Ensure that whatever happens, we clean up the identity state
7404 sCallerIdentity.remove();
7405 }
7406
7407 // We've got the fd now, so we're done with the provider.
7408 removeContentProviderExternal(name);
7409 } else {
7410 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7411 }
7412 return pfd;
7413 }
7414
7415 public void goingToSleep() {
7416 synchronized(this) {
7417 mSleeping = true;
7418 mWindowManager.setEventDispatching(false);
7419
7420 if (mResumedActivity != null) {
7421 pauseIfSleepingLocked();
7422 } else {
7423 Log.w(TAG, "goingToSleep with no resumed activity!");
7424 }
7425 }
7426 }
7427
Dianne Hackborn55280a92009-05-07 15:53:46 -07007428 public boolean shutdown(int timeout) {
7429 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7430 != PackageManager.PERMISSION_GRANTED) {
7431 throw new SecurityException("Requires permission "
7432 + android.Manifest.permission.SHUTDOWN);
7433 }
7434
7435 boolean timedout = false;
7436
7437 synchronized(this) {
7438 mShuttingDown = true;
7439 mWindowManager.setEventDispatching(false);
7440
7441 if (mResumedActivity != null) {
7442 pauseIfSleepingLocked();
7443 final long endTime = System.currentTimeMillis() + timeout;
7444 while (mResumedActivity != null || mPausingActivity != null) {
7445 long delay = endTime - System.currentTimeMillis();
7446 if (delay <= 0) {
7447 Log.w(TAG, "Activity manager shutdown timed out");
7448 timedout = true;
7449 break;
7450 }
7451 try {
7452 this.wait();
7453 } catch (InterruptedException e) {
7454 }
7455 }
7456 }
7457 }
7458
7459 mUsageStatsService.shutdown();
7460 mBatteryStatsService.shutdown();
7461
7462 return timedout;
7463 }
7464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007465 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007466 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007467 if (!mGoingToSleep.isHeld()) {
7468 mGoingToSleep.acquire();
7469 if (mLaunchingActivity.isHeld()) {
7470 mLaunchingActivity.release();
7471 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7472 }
7473 }
7474
7475 // If we are not currently pausing an activity, get the current
7476 // one to pause. If we are pausing one, we will just let that stuff
7477 // run and release the wake lock when all done.
7478 if (mPausingActivity == null) {
7479 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7480 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7481 startPausingLocked(false, true);
7482 }
7483 }
7484 }
7485
7486 public void wakingUp() {
7487 synchronized(this) {
7488 if (mGoingToSleep.isHeld()) {
7489 mGoingToSleep.release();
7490 }
7491 mWindowManager.setEventDispatching(true);
7492 mSleeping = false;
7493 resumeTopActivityLocked(null);
7494 }
7495 }
7496
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007497 public void stopAppSwitches() {
7498 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7499 != PackageManager.PERMISSION_GRANTED) {
7500 throw new SecurityException("Requires permission "
7501 + android.Manifest.permission.STOP_APP_SWITCHES);
7502 }
7503
7504 synchronized(this) {
7505 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7506 + APP_SWITCH_DELAY_TIME;
7507 mDidAppSwitch = false;
7508 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7509 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7510 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7511 }
7512 }
7513
7514 public void resumeAppSwitches() {
7515 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7516 != PackageManager.PERMISSION_GRANTED) {
7517 throw new SecurityException("Requires permission "
7518 + android.Manifest.permission.STOP_APP_SWITCHES);
7519 }
7520
7521 synchronized(this) {
7522 // Note that we don't execute any pending app switches... we will
7523 // let those wait until either the timeout, or the next start
7524 // activity request.
7525 mAppSwitchesAllowedTime = 0;
7526 }
7527 }
7528
7529 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7530 String name) {
7531 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7532 return true;
7533 }
7534
7535 final int perm = checkComponentPermission(
7536 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7537 callingUid, -1);
7538 if (perm == PackageManager.PERMISSION_GRANTED) {
7539 return true;
7540 }
7541
7542 Log.w(TAG, name + " request from " + callingUid + " stopped");
7543 return false;
7544 }
7545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007546 public void setDebugApp(String packageName, boolean waitForDebugger,
7547 boolean persistent) {
7548 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7549 "setDebugApp()");
7550
7551 // Note that this is not really thread safe if there are multiple
7552 // callers into it at the same time, but that's not a situation we
7553 // care about.
7554 if (persistent) {
7555 final ContentResolver resolver = mContext.getContentResolver();
7556 Settings.System.putString(
7557 resolver, Settings.System.DEBUG_APP,
7558 packageName);
7559 Settings.System.putInt(
7560 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7561 waitForDebugger ? 1 : 0);
7562 }
7563
7564 synchronized (this) {
7565 if (!persistent) {
7566 mOrigDebugApp = mDebugApp;
7567 mOrigWaitForDebugger = mWaitForDebugger;
7568 }
7569 mDebugApp = packageName;
7570 mWaitForDebugger = waitForDebugger;
7571 mDebugTransient = !persistent;
7572 if (packageName != null) {
7573 final long origId = Binder.clearCallingIdentity();
7574 uninstallPackageLocked(packageName, -1, false);
7575 Binder.restoreCallingIdentity(origId);
7576 }
7577 }
7578 }
7579
7580 public void setAlwaysFinish(boolean enabled) {
7581 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7582 "setAlwaysFinish()");
7583
7584 Settings.System.putInt(
7585 mContext.getContentResolver(),
7586 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7587
7588 synchronized (this) {
7589 mAlwaysFinishActivities = enabled;
7590 }
7591 }
7592
7593 public void setActivityWatcher(IActivityWatcher watcher) {
7594 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7595 "setActivityWatcher()");
7596 synchronized (this) {
7597 mWatcher = watcher;
7598 }
7599 }
7600
7601 public final void enterSafeMode() {
7602 synchronized(this) {
7603 // It only makes sense to do this before the system is ready
7604 // and started launching other packages.
7605 if (!mSystemReady) {
7606 try {
7607 ActivityThread.getPackageManager().enterSafeMode();
7608 } catch (RemoteException e) {
7609 }
7610
7611 View v = LayoutInflater.from(mContext).inflate(
7612 com.android.internal.R.layout.safe_mode, null);
7613 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7614 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7615 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7616 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7617 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7618 lp.format = v.getBackground().getOpacity();
7619 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7620 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7621 ((WindowManager)mContext.getSystemService(
7622 Context.WINDOW_SERVICE)).addView(v, lp);
7623 }
7624 }
7625 }
7626
7627 public void noteWakeupAlarm(IIntentSender sender) {
7628 if (!(sender instanceof PendingIntentRecord)) {
7629 return;
7630 }
7631 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7632 synchronized (stats) {
7633 if (mBatteryStatsService.isOnBattery()) {
7634 mBatteryStatsService.enforceCallingPermission();
7635 PendingIntentRecord rec = (PendingIntentRecord)sender;
7636 int MY_UID = Binder.getCallingUid();
7637 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7638 BatteryStatsImpl.Uid.Pkg pkg =
7639 stats.getPackageStatsLocked(uid, rec.key.packageName);
7640 pkg.incWakeupsLocked();
7641 }
7642 }
7643 }
7644
7645 public boolean killPidsForMemory(int[] pids) {
7646 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7647 throw new SecurityException("killPidsForMemory only available to the system");
7648 }
7649
7650 // XXX Note: don't acquire main activity lock here, because the window
7651 // manager calls in with its locks held.
7652
7653 boolean killed = false;
7654 synchronized (mPidsSelfLocked) {
7655 int[] types = new int[pids.length];
7656 int worstType = 0;
7657 for (int i=0; i<pids.length; i++) {
7658 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7659 if (proc != null) {
7660 int type = proc.setAdj;
7661 types[i] = type;
7662 if (type > worstType) {
7663 worstType = type;
7664 }
7665 }
7666 }
7667
7668 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7669 // then constrain it so we will kill all hidden procs.
7670 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7671 worstType = HIDDEN_APP_MIN_ADJ;
7672 }
7673 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7674 for (int i=0; i<pids.length; i++) {
7675 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7676 if (proc == null) {
7677 continue;
7678 }
7679 int adj = proc.setAdj;
7680 if (adj >= worstType) {
7681 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7682 + adj + ")");
7683 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7684 proc.processName, adj);
7685 killed = true;
7686 Process.killProcess(pids[i]);
7687 }
7688 }
7689 }
7690 return killed;
7691 }
7692
7693 public void reportPss(IApplicationThread caller, int pss) {
7694 Watchdog.PssRequestor req;
7695 String name;
7696 ProcessRecord callerApp;
7697 synchronized (this) {
7698 if (caller == null) {
7699 return;
7700 }
7701 callerApp = getRecordForAppLocked(caller);
7702 if (callerApp == null) {
7703 return;
7704 }
7705 callerApp.lastPss = pss;
7706 req = callerApp;
7707 name = callerApp.processName;
7708 }
7709 Watchdog.getInstance().reportPss(req, name, pss);
7710 if (!callerApp.persistent) {
7711 removeRequestedPss(callerApp);
7712 }
7713 }
7714
7715 public void requestPss(Runnable completeCallback) {
7716 ArrayList<ProcessRecord> procs;
7717 synchronized (this) {
7718 mRequestPssCallback = completeCallback;
7719 mRequestPssList.clear();
7720 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7721 ProcessRecord proc = mLRUProcesses.get(i);
7722 if (!proc.persistent) {
7723 mRequestPssList.add(proc);
7724 }
7725 }
7726 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7727 }
7728
7729 int oldPri = Process.getThreadPriority(Process.myTid());
7730 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7731 for (int i=procs.size()-1; i>=0; i--) {
7732 ProcessRecord proc = procs.get(i);
7733 proc.lastPss = 0;
7734 proc.requestPss();
7735 }
7736 Process.setThreadPriority(oldPri);
7737 }
7738
7739 void removeRequestedPss(ProcessRecord proc) {
7740 Runnable callback = null;
7741 synchronized (this) {
7742 if (mRequestPssList.remove(proc)) {
7743 if (mRequestPssList.size() == 0) {
7744 callback = mRequestPssCallback;
7745 mRequestPssCallback = null;
7746 }
7747 }
7748 }
7749
7750 if (callback != null) {
7751 callback.run();
7752 }
7753 }
7754
7755 public void collectPss(Watchdog.PssStats stats) {
7756 stats.mEmptyPss = 0;
7757 stats.mEmptyCount = 0;
7758 stats.mBackgroundPss = 0;
7759 stats.mBackgroundCount = 0;
7760 stats.mServicePss = 0;
7761 stats.mServiceCount = 0;
7762 stats.mVisiblePss = 0;
7763 stats.mVisibleCount = 0;
7764 stats.mForegroundPss = 0;
7765 stats.mForegroundCount = 0;
7766 stats.mNoPssCount = 0;
7767 synchronized (this) {
7768 int i;
7769 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7770 ? mProcDeaths.length : stats.mProcDeaths.length;
7771 int aggr = 0;
7772 for (i=0; i<NPD; i++) {
7773 aggr += mProcDeaths[i];
7774 stats.mProcDeaths[i] = aggr;
7775 }
7776 while (i<stats.mProcDeaths.length) {
7777 stats.mProcDeaths[i] = 0;
7778 i++;
7779 }
7780
7781 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7782 ProcessRecord proc = mLRUProcesses.get(i);
7783 if (proc.persistent) {
7784 continue;
7785 }
7786 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7787 if (proc.lastPss == 0) {
7788 stats.mNoPssCount++;
7789 continue;
7790 }
7791 if (proc.setAdj == EMPTY_APP_ADJ) {
7792 stats.mEmptyPss += proc.lastPss;
7793 stats.mEmptyCount++;
7794 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7795 stats.mEmptyPss += proc.lastPss;
7796 stats.mEmptyCount++;
7797 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7798 stats.mBackgroundPss += proc.lastPss;
7799 stats.mBackgroundCount++;
7800 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7801 stats.mVisiblePss += proc.lastPss;
7802 stats.mVisibleCount++;
7803 } else {
7804 stats.mForegroundPss += proc.lastPss;
7805 stats.mForegroundCount++;
7806 }
7807 }
7808 }
7809 }
7810
7811 public final void startRunning(String pkg, String cls, String action,
7812 String data) {
7813 synchronized(this) {
7814 if (mStartRunning) {
7815 return;
7816 }
7817 mStartRunning = true;
7818 mTopComponent = pkg != null && cls != null
7819 ? new ComponentName(pkg, cls) : null;
7820 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7821 mTopData = data;
7822 if (!mSystemReady) {
7823 return;
7824 }
7825 }
7826
7827 systemReady();
7828 }
7829
7830 private void retrieveSettings() {
7831 final ContentResolver resolver = mContext.getContentResolver();
7832 String debugApp = Settings.System.getString(
7833 resolver, Settings.System.DEBUG_APP);
7834 boolean waitForDebugger = Settings.System.getInt(
7835 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7836 boolean alwaysFinishActivities = Settings.System.getInt(
7837 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7838
7839 Configuration configuration = new Configuration();
7840 Settings.System.getConfiguration(resolver, configuration);
7841
7842 synchronized (this) {
7843 mDebugApp = mOrigDebugApp = debugApp;
7844 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7845 mAlwaysFinishActivities = alwaysFinishActivities;
7846 // This happens before any activities are started, so we can
7847 // change mConfiguration in-place.
7848 mConfiguration.updateFrom(configuration);
7849 }
7850 }
7851
7852 public boolean testIsSystemReady() {
7853 // no need to synchronize(this) just to read & return the value
7854 return mSystemReady;
7855 }
7856
7857 public void systemReady() {
7858 // In the simulator, startRunning will never have been called, which
7859 // normally sets a few crucial variables. Do it here instead.
7860 if (!Process.supportsProcesses()) {
7861 mStartRunning = true;
7862 mTopAction = Intent.ACTION_MAIN;
7863 }
7864
7865 synchronized(this) {
7866 if (mSystemReady) {
7867 return;
7868 }
7869 mSystemReady = true;
7870 if (!mStartRunning) {
7871 return;
7872 }
7873 }
7874
7875 if (Config.LOGD) Log.d(TAG, "Start running!");
7876 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7877 SystemClock.uptimeMillis());
7878
7879 synchronized(this) {
7880 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7881 ResolveInfo ri = mContext.getPackageManager()
7882 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007883 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007884 CharSequence errorMsg = null;
7885 if (ri != null) {
7886 ActivityInfo ai = ri.activityInfo;
7887 ApplicationInfo app = ai.applicationInfo;
7888 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7889 mTopAction = Intent.ACTION_FACTORY_TEST;
7890 mTopData = null;
7891 mTopComponent = new ComponentName(app.packageName,
7892 ai.name);
7893 } else {
7894 errorMsg = mContext.getResources().getText(
7895 com.android.internal.R.string.factorytest_not_system);
7896 }
7897 } else {
7898 errorMsg = mContext.getResources().getText(
7899 com.android.internal.R.string.factorytest_no_action);
7900 }
7901 if (errorMsg != null) {
7902 mTopAction = null;
7903 mTopData = null;
7904 mTopComponent = null;
7905 Message msg = Message.obtain();
7906 msg.what = SHOW_FACTORY_ERROR_MSG;
7907 msg.getData().putCharSequence("msg", errorMsg);
7908 mHandler.sendMessage(msg);
7909 }
7910 }
7911 }
7912
7913 retrieveSettings();
7914
7915 synchronized (this) {
7916 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7917 try {
7918 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007919 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007920 if (apps != null) {
7921 int N = apps.size();
7922 int i;
7923 for (i=0; i<N; i++) {
7924 ApplicationInfo info
7925 = (ApplicationInfo)apps.get(i);
7926 if (info != null &&
7927 !info.packageName.equals("android")) {
7928 addAppLocked(info);
7929 }
7930 }
7931 }
7932 } catch (RemoteException ex) {
7933 // pm is in same process, this will never happen.
7934 }
7935 }
7936
7937 try {
7938 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7939 Message msg = Message.obtain();
7940 msg.what = SHOW_UID_ERROR_MSG;
7941 mHandler.sendMessage(msg);
7942 }
7943 } catch (RemoteException e) {
7944 }
7945
7946 // Start up initial activity.
7947 mBooting = true;
7948 resumeTopActivityLocked(null);
7949 }
7950 }
7951
7952 boolean makeAppCrashingLocked(ProcessRecord app,
7953 String tag, String shortMsg, String longMsg, byte[] crashData) {
7954 app.crashing = true;
7955 app.crashingReport = generateProcessError(app,
7956 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7957 startAppProblemLocked(app);
7958 app.stopFreezingAllLocked();
7959 return handleAppCrashLocked(app);
7960 }
7961
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007962 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7963 IPackageManager pm = ActivityThread.getPackageManager();
7964 try {
7965 // was an installer package name specified when this app was
7966 // installed?
7967 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7968 if (installerPackageName == null) {
7969 return null;
7970 }
7971
7972 // is there an Activity in this package that handles ACTION_APP_ERROR?
7973 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07007974 intent.setPackage(installerPackageName);
7975 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007976 if (info == null || info.activityInfo == null) {
7977 return null;
7978 }
7979
7980 return new ComponentName(installerPackageName, info.activityInfo.name);
7981 } catch (RemoteException e) {
7982 // will return null and no error report will be delivered
7983 }
7984 return null;
7985 }
7986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007987 void makeAppNotRespondingLocked(ProcessRecord app,
7988 String tag, String shortMsg, String longMsg, byte[] crashData) {
7989 app.notResponding = true;
7990 app.notRespondingReport = generateProcessError(app,
7991 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7992 crashData);
7993 startAppProblemLocked(app);
7994 app.stopFreezingAllLocked();
7995 }
7996
7997 /**
7998 * Generate a process error record, suitable for attachment to a ProcessRecord.
7999 *
8000 * @param app The ProcessRecord in which the error occurred.
8001 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8002 * ActivityManager.AppErrorStateInfo
8003 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8004 * @param shortMsg Short message describing the crash.
8005 * @param longMsg Long message describing the crash.
8006 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8007 *
8008 * @return Returns a fully-formed AppErrorStateInfo record.
8009 */
8010 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8011 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8012 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8013
8014 report.condition = condition;
8015 report.processName = app.processName;
8016 report.pid = app.pid;
8017 report.uid = app.info.uid;
8018 report.tag = tag;
8019 report.shortMsg = shortMsg;
8020 report.longMsg = longMsg;
8021 report.crashData = crashData;
8022
8023 return report;
8024 }
8025
8026 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8027 boolean crashed) {
8028 synchronized (this) {
8029 app.crashing = false;
8030 app.crashingReport = null;
8031 app.notResponding = false;
8032 app.notRespondingReport = null;
8033 if (app.anrDialog == fromDialog) {
8034 app.anrDialog = null;
8035 }
8036 if (app.waitDialog == fromDialog) {
8037 app.waitDialog = null;
8038 }
8039 if (app.pid > 0 && app.pid != MY_PID) {
8040 if (crashed) {
8041 handleAppCrashLocked(app);
8042 }
8043 Log.i(ActivityManagerService.TAG, "Killing process "
8044 + app.processName
8045 + " (pid=" + app.pid + ") at user's request");
8046 Process.killProcess(app.pid);
8047 }
8048
8049 }
8050 }
8051
8052 boolean handleAppCrashLocked(ProcessRecord app) {
8053 long now = SystemClock.uptimeMillis();
8054
8055 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8056 app.info.uid);
8057 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8058 // This process loses!
8059 Log.w(TAG, "Process " + app.info.processName
8060 + " has crashed too many times: killing!");
8061 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8062 app.info.processName, app.info.uid);
8063 killServicesLocked(app, false);
8064 for (int i=mHistory.size()-1; i>=0; i--) {
8065 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8066 if (r.app == app) {
8067 if (Config.LOGD) Log.d(
8068 TAG, " Force finishing activity "
8069 + r.intent.getComponent().flattenToShortString());
8070 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8071 }
8072 }
8073 if (!app.persistent) {
8074 // We don't want to start this process again until the user
8075 // explicitly does so... but for persistent process, we really
8076 // need to keep it running. If a persistent process is actually
8077 // repeatedly crashing, then badness for everyone.
8078 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8079 app.info.processName);
8080 mBadProcesses.put(app.info.processName, app.info.uid, now);
8081 app.bad = true;
8082 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8083 app.removed = true;
8084 removeProcessLocked(app, false);
8085 return false;
8086 }
8087 }
8088
8089 // Bump up the crash count of any services currently running in the proc.
8090 if (app.services.size() != 0) {
8091 // Any services running in the application need to be placed
8092 // back in the pending list.
8093 Iterator it = app.services.iterator();
8094 while (it.hasNext()) {
8095 ServiceRecord sr = (ServiceRecord)it.next();
8096 sr.crashCount++;
8097 }
8098 }
8099
8100 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8101 return true;
8102 }
8103
8104 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008105 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008106 skipCurrentReceiverLocked(app);
8107 }
8108
8109 void skipCurrentReceiverLocked(ProcessRecord app) {
8110 boolean reschedule = false;
8111 BroadcastRecord r = app.curReceiver;
8112 if (r != null) {
8113 // The current broadcast is waiting for this app's receiver
8114 // to be finished. Looks like that's not going to happen, so
8115 // let the broadcast continue.
8116 logBroadcastReceiverDiscard(r);
8117 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8118 r.resultExtras, r.resultAbort, true);
8119 reschedule = true;
8120 }
8121 r = mPendingBroadcast;
8122 if (r != null && r.curApp == app) {
8123 if (DEBUG_BROADCAST) Log.v(TAG,
8124 "skip & discard pending app " + r);
8125 logBroadcastReceiverDiscard(r);
8126 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8127 r.resultExtras, r.resultAbort, true);
8128 reschedule = true;
8129 }
8130 if (reschedule) {
8131 scheduleBroadcastsLocked();
8132 }
8133 }
8134
8135 public int handleApplicationError(IBinder app, int flags,
8136 String tag, String shortMsg, String longMsg, byte[] crashData) {
8137 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008138 ProcessRecord r = null;
8139 synchronized (this) {
8140 if (app != null) {
8141 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8142 final int NA = apps.size();
8143 for (int ia=0; ia<NA; ia++) {
8144 ProcessRecord p = apps.valueAt(ia);
8145 if (p.thread != null && p.thread.asBinder() == app) {
8146 r = p;
8147 break;
8148 }
8149 }
8150 }
8151 }
8152
8153 if (r != null) {
8154 // The application has crashed. Send the SIGQUIT to the process so
8155 // that it can dump its state.
8156 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8157 //Log.i(TAG, "Current system threads:");
8158 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8159 }
8160
8161 if (mWatcher != null) {
8162 try {
8163 String name = r != null ? r.processName : null;
8164 int pid = r != null ? r.pid : Binder.getCallingPid();
8165 if (!mWatcher.appCrashed(name, pid,
8166 shortMsg, longMsg, crashData)) {
8167 Log.w(TAG, "Force-killing crashed app " + name
8168 + " at watcher's request");
8169 Process.killProcess(pid);
8170 return 0;
8171 }
8172 } catch (RemoteException e) {
8173 mWatcher = null;
8174 }
8175 }
8176
8177 final long origId = Binder.clearCallingIdentity();
8178
8179 // If this process is running instrumentation, finish it.
8180 if (r != null && r.instrumentationClass != null) {
8181 Log.w(TAG, "Error in app " + r.processName
8182 + " running instrumentation " + r.instrumentationClass + ":");
8183 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8184 if (longMsg != null) Log.w(TAG, " " + longMsg);
8185 Bundle info = new Bundle();
8186 info.putString("shortMsg", shortMsg);
8187 info.putString("longMsg", longMsg);
8188 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8189 Binder.restoreCallingIdentity(origId);
8190 return 0;
8191 }
8192
8193 if (r != null) {
8194 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8195 return 0;
8196 }
8197 } else {
8198 Log.w(TAG, "Some application object " + app + " tag " + tag
8199 + " has crashed, but I don't know who it is.");
8200 Log.w(TAG, "ShortMsg:" + shortMsg);
8201 Log.w(TAG, "LongMsg:" + longMsg);
8202 Binder.restoreCallingIdentity(origId);
8203 return 0;
8204 }
8205
8206 Message msg = Message.obtain();
8207 msg.what = SHOW_ERROR_MSG;
8208 HashMap data = new HashMap();
8209 data.put("result", result);
8210 data.put("app", r);
8211 data.put("flags", flags);
8212 data.put("shortMsg", shortMsg);
8213 data.put("longMsg", longMsg);
8214 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8215 // For system processes, submit crash data to the server.
8216 data.put("crashData", crashData);
8217 }
8218 msg.obj = data;
8219 mHandler.sendMessage(msg);
8220
8221 Binder.restoreCallingIdentity(origId);
8222 }
8223
8224 int res = result.get();
8225
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008226 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008227 synchronized (this) {
8228 if (r != null) {
8229 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8230 SystemClock.uptimeMillis());
8231 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008232 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8233 appErrorIntent = createAppErrorIntentLocked(r);
8234 res = AppErrorDialog.FORCE_QUIT;
8235 }
8236 }
8237
8238 if (appErrorIntent != null) {
8239 try {
8240 mContext.startActivity(appErrorIntent);
8241 } catch (ActivityNotFoundException e) {
8242 Log.w(TAG, "bug report receiver dissappeared", e);
8243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008244 }
8245
8246 return res;
8247 }
8248
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008249 Intent createAppErrorIntentLocked(ProcessRecord r) {
8250 ApplicationErrorReport report = createAppErrorReportLocked(r);
8251 if (report == null) {
8252 return null;
8253 }
8254 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8255 result.setComponent(r.errorReportReceiver);
8256 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8257 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8258 return result;
8259 }
8260
8261 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8262 if (r.errorReportReceiver == null) {
8263 return null;
8264 }
8265
8266 if (!r.crashing && !r.notResponding) {
8267 return null;
8268 }
8269
8270 try {
8271 ApplicationErrorReport report = new ApplicationErrorReport();
8272 report.packageName = r.info.packageName;
8273 report.installerPackageName = r.errorReportReceiver.getPackageName();
8274 report.processName = r.processName;
8275
8276 if (r.crashing) {
8277 report.type = ApplicationErrorReport.TYPE_CRASH;
8278 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8279
8280 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8281 r.crashingReport.crashData);
8282 DataInputStream dataStream = new DataInputStream(byteStream);
8283 CrashData crashData = new CrashData(dataStream);
8284 ThrowableData throwData = crashData.getThrowableData();
8285
8286 report.time = crashData.getTime();
8287 report.crashInfo.stackTrace = throwData.toString();
8288
Jacek Surazskif829a782009-06-11 22:47:02 +02008289 // Extract the source of the exception, useful for report
8290 // clustering. Also extract the "deepest" non-null exception
8291 // message.
8292 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008293 while (throwData.getCause() != null) {
8294 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008295 String msg = throwData.getMessage();
8296 if (msg != null && msg.length() > 0) {
8297 exceptionMessage = msg;
8298 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008299 }
8300 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008301 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008302 report.crashInfo.exceptionClassName = throwData.getType();
8303 report.crashInfo.throwFileName = trace.getFileName();
8304 report.crashInfo.throwClassName = trace.getClassName();
8305 report.crashInfo.throwMethodName = trace.getMethodName();
8306 } else if (r.notResponding) {
8307 report.type = ApplicationErrorReport.TYPE_ANR;
8308 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8309
8310 report.anrInfo.activity = r.notRespondingReport.tag;
8311 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8312 report.anrInfo.info = r.notRespondingReport.longMsg;
8313 }
8314
8315 return report;
8316 } catch (IOException e) {
8317 // we don't send it
8318 }
8319
8320 return null;
8321 }
8322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008323 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8324 // assume our apps are happy - lazy create the list
8325 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8326
8327 synchronized (this) {
8328
8329 // iterate across all processes
8330 final int N = mLRUProcesses.size();
8331 for (int i = 0; i < N; i++) {
8332 ProcessRecord app = mLRUProcesses.get(i);
8333 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8334 // This one's in trouble, so we'll generate a report for it
8335 // crashes are higher priority (in case there's a crash *and* an anr)
8336 ActivityManager.ProcessErrorStateInfo report = null;
8337 if (app.crashing) {
8338 report = app.crashingReport;
8339 } else if (app.notResponding) {
8340 report = app.notRespondingReport;
8341 }
8342
8343 if (report != null) {
8344 if (errList == null) {
8345 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8346 }
8347 errList.add(report);
8348 } else {
8349 Log.w(TAG, "Missing app error report, app = " + app.processName +
8350 " crashing = " + app.crashing +
8351 " notResponding = " + app.notResponding);
8352 }
8353 }
8354 }
8355 }
8356
8357 return errList;
8358 }
8359
8360 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8361 // Lazy instantiation of list
8362 List<ActivityManager.RunningAppProcessInfo> runList = null;
8363 synchronized (this) {
8364 // Iterate across all processes
8365 final int N = mLRUProcesses.size();
8366 for (int i = 0; i < N; i++) {
8367 ProcessRecord app = mLRUProcesses.get(i);
8368 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8369 // Generate process state info for running application
8370 ActivityManager.RunningAppProcessInfo currApp =
8371 new ActivityManager.RunningAppProcessInfo(app.processName,
8372 app.pid, app.getPackageList());
8373 int adj = app.curAdj;
8374 if (adj >= CONTENT_PROVIDER_ADJ) {
8375 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8376 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8377 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008378 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8379 } else if (adj >= HOME_APP_ADJ) {
8380 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8381 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008382 } else if (adj >= SECONDARY_SERVER_ADJ) {
8383 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8384 } else if (adj >= VISIBLE_APP_ADJ) {
8385 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8386 } else {
8387 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8388 }
8389 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8390 // + " lru=" + currApp.lru);
8391 if (runList == null) {
8392 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8393 }
8394 runList.add(currApp);
8395 }
8396 }
8397 }
8398 return runList;
8399 }
8400
8401 @Override
8402 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8403 synchronized (this) {
8404 if (checkCallingPermission(android.Manifest.permission.DUMP)
8405 != PackageManager.PERMISSION_GRANTED) {
8406 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8407 + Binder.getCallingPid()
8408 + ", uid=" + Binder.getCallingUid()
8409 + " without permission "
8410 + android.Manifest.permission.DUMP);
8411 return;
8412 }
8413 if (args.length != 0 && "service".equals(args[0])) {
8414 dumpService(fd, pw, args);
8415 return;
8416 }
8417 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008418 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008419 pw.println(" ");
8420 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008421 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008422 if (mWaitingVisibleActivities.size() > 0) {
8423 pw.println(" ");
8424 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008425 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008426 }
8427 if (mStoppingActivities.size() > 0) {
8428 pw.println(" ");
8429 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008430 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008431 }
8432 if (mFinishingActivities.size() > 0) {
8433 pw.println(" ");
8434 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008435 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008436 }
8437
8438 pw.println(" ");
8439 pw.println(" mPausingActivity: " + mPausingActivity);
8440 pw.println(" mResumedActivity: " + mResumedActivity);
8441 pw.println(" mFocusedActivity: " + mFocusedActivity);
8442 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8443
8444 if (mRecentTasks.size() > 0) {
8445 pw.println(" ");
8446 pw.println("Recent tasks in Current Activity Manager State:");
8447
8448 final int N = mRecentTasks.size();
8449 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008450 TaskRecord tr = mRecentTasks.get(i);
8451 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8452 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008453 mRecentTasks.get(i).dump(pw, " ");
8454 }
8455 }
8456
8457 pw.println(" ");
8458 pw.println(" mCurTask: " + mCurTask);
8459
8460 pw.println(" ");
8461 pw.println("Processes in Current Activity Manager State:");
8462
8463 boolean needSep = false;
8464 int numPers = 0;
8465
8466 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8467 final int NA = procs.size();
8468 for (int ia=0; ia<NA; ia++) {
8469 if (!needSep) {
8470 pw.println(" All known processes:");
8471 needSep = true;
8472 }
8473 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008474 pw.print(r.persistent ? " *PERS*" : " *APP*");
8475 pw.print(" UID "); pw.print(procs.keyAt(ia));
8476 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008477 r.dump(pw, " ");
8478 if (r.persistent) {
8479 numPers++;
8480 }
8481 }
8482 }
8483
8484 if (mLRUProcesses.size() > 0) {
8485 if (needSep) pw.println(" ");
8486 needSep = true;
8487 pw.println(" Running processes (most recent first):");
8488 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008489 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008490 needSep = true;
8491 }
8492
8493 synchronized (mPidsSelfLocked) {
8494 if (mPidsSelfLocked.size() > 0) {
8495 if (needSep) pw.println(" ");
8496 needSep = true;
8497 pw.println(" PID mappings:");
8498 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008499 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8500 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008501 }
8502 }
8503 }
8504
8505 if (mForegroundProcesses.size() > 0) {
8506 if (needSep) pw.println(" ");
8507 needSep = true;
8508 pw.println(" Foreground Processes:");
8509 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008510 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8511 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008512 }
8513 }
8514
8515 if (mPersistentStartingProcesses.size() > 0) {
8516 if (needSep) pw.println(" ");
8517 needSep = true;
8518 pw.println(" Persisent processes that are starting:");
8519 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008520 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008521 }
8522
8523 if (mStartingProcesses.size() > 0) {
8524 if (needSep) pw.println(" ");
8525 needSep = true;
8526 pw.println(" Processes that are starting:");
8527 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008528 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008529 }
8530
8531 if (mRemovedProcesses.size() > 0) {
8532 if (needSep) pw.println(" ");
8533 needSep = true;
8534 pw.println(" Processes that are being removed:");
8535 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008536 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008537 }
8538
8539 if (mProcessesOnHold.size() > 0) {
8540 if (needSep) pw.println(" ");
8541 needSep = true;
8542 pw.println(" Processes that are on old until the system is ready:");
8543 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008544 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008545 }
8546
8547 if (mProcessCrashTimes.getMap().size() > 0) {
8548 if (needSep) pw.println(" ");
8549 needSep = true;
8550 pw.println(" Time since processes crashed:");
8551 long now = SystemClock.uptimeMillis();
8552 for (Map.Entry<String, SparseArray<Long>> procs
8553 : mProcessCrashTimes.getMap().entrySet()) {
8554 SparseArray<Long> uids = procs.getValue();
8555 final int N = uids.size();
8556 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008557 pw.print(" Process "); pw.print(procs.getKey());
8558 pw.print(" uid "); pw.print(uids.keyAt(i));
8559 pw.print(": last crashed ");
8560 pw.print((now-uids.valueAt(i)));
8561 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008562 }
8563 }
8564 }
8565
8566 if (mBadProcesses.getMap().size() > 0) {
8567 if (needSep) pw.println(" ");
8568 needSep = true;
8569 pw.println(" Bad processes:");
8570 for (Map.Entry<String, SparseArray<Long>> procs
8571 : mBadProcesses.getMap().entrySet()) {
8572 SparseArray<Long> uids = procs.getValue();
8573 final int N = uids.size();
8574 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008575 pw.print(" Bad process "); pw.print(procs.getKey());
8576 pw.print(" uid "); pw.print(uids.keyAt(i));
8577 pw.print(": crashed at time ");
8578 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008579 }
8580 }
8581 }
8582
8583 pw.println(" ");
8584 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008585 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008586 pw.println(" mConfiguration: " + mConfiguration);
8587 pw.println(" mStartRunning=" + mStartRunning
8588 + " mSystemReady=" + mSystemReady
8589 + " mBooting=" + mBooting
8590 + " mBooted=" + mBooted
8591 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008592 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008593 pw.println(" mGoingToSleep=" + mGoingToSleep);
8594 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8595 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8596 + " mDebugTransient=" + mDebugTransient
8597 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8598 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8599 + " mWatcher=" + mWatcher);
8600 }
8601 }
8602
8603 /**
8604 * There are three ways to call this:
8605 * - no service specified: dump all the services
8606 * - a flattened component name that matched an existing service was specified as the
8607 * first arg: dump that one service
8608 * - the first arg isn't the flattened component name of an existing service:
8609 * dump all services whose component contains the first arg as a substring
8610 */
8611 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8612 String[] newArgs;
8613 String componentNameString;
8614 ServiceRecord r;
8615 if (args.length == 1) {
8616 componentNameString = null;
8617 newArgs = EMPTY_STRING_ARRAY;
8618 r = null;
8619 } else {
8620 componentNameString = args[1];
8621 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8622 r = componentName != null ? mServices.get(componentName) : null;
8623 newArgs = new String[args.length - 2];
8624 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8625 }
8626
8627 if (r != null) {
8628 dumpService(fd, pw, r, newArgs);
8629 } else {
8630 for (ServiceRecord r1 : mServices.values()) {
8631 if (componentNameString == null
8632 || r1.name.flattenToString().contains(componentNameString)) {
8633 dumpService(fd, pw, r1, newArgs);
8634 }
8635 }
8636 }
8637 }
8638
8639 /**
8640 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8641 * there is a thread associated with the service.
8642 */
8643 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8644 pw.println(" Service " + r.name.flattenToString());
8645 if (r.app != null && r.app.thread != null) {
8646 try {
8647 // flush anything that is already in the PrintWriter since the thread is going
8648 // to write to the file descriptor directly
8649 pw.flush();
8650 r.app.thread.dumpService(fd, r, args);
8651 pw.print("\n");
8652 } catch (RemoteException e) {
8653 pw.println("got a RemoteException while dumping the service");
8654 }
8655 }
8656 }
8657
8658 void dumpBroadcasts(PrintWriter pw) {
8659 synchronized (this) {
8660 if (checkCallingPermission(android.Manifest.permission.DUMP)
8661 != PackageManager.PERMISSION_GRANTED) {
8662 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8663 + Binder.getCallingPid()
8664 + ", uid=" + Binder.getCallingUid()
8665 + " without permission "
8666 + android.Manifest.permission.DUMP);
8667 return;
8668 }
8669 pw.println("Broadcasts in Current Activity Manager State:");
8670
8671 if (mRegisteredReceivers.size() > 0) {
8672 pw.println(" ");
8673 pw.println(" Registered Receivers:");
8674 Iterator it = mRegisteredReceivers.values().iterator();
8675 while (it.hasNext()) {
8676 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008677 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008678 r.dump(pw, " ");
8679 }
8680 }
8681
8682 pw.println(" ");
8683 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008684 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008685
8686 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8687 || mPendingBroadcast != null) {
8688 if (mParallelBroadcasts.size() > 0) {
8689 pw.println(" ");
8690 pw.println(" Active broadcasts:");
8691 }
8692 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8693 pw.println(" Broadcast #" + i + ":");
8694 mParallelBroadcasts.get(i).dump(pw, " ");
8695 }
8696 if (mOrderedBroadcasts.size() > 0) {
8697 pw.println(" ");
8698 pw.println(" Active serialized broadcasts:");
8699 }
8700 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8701 pw.println(" Serialized Broadcast #" + i + ":");
8702 mOrderedBroadcasts.get(i).dump(pw, " ");
8703 }
8704 pw.println(" ");
8705 pw.println(" Pending broadcast:");
8706 if (mPendingBroadcast != null) {
8707 mPendingBroadcast.dump(pw, " ");
8708 } else {
8709 pw.println(" (null)");
8710 }
8711 }
8712
8713 pw.println(" ");
8714 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8715 if (mStickyBroadcasts != null) {
8716 pw.println(" ");
8717 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008718 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008719 for (Map.Entry<String, ArrayList<Intent>> ent
8720 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008721 pw.print(" * Sticky action "); pw.print(ent.getKey());
8722 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008723 ArrayList<Intent> intents = ent.getValue();
8724 final int N = intents.size();
8725 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008726 sb.setLength(0);
8727 sb.append(" Intent: ");
8728 intents.get(i).toShortString(sb, true, false);
8729 pw.println(sb.toString());
8730 Bundle bundle = intents.get(i).getExtras();
8731 if (bundle != null) {
8732 pw.print(" ");
8733 pw.println(bundle.toString());
8734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008735 }
8736 }
8737 }
8738
8739 pw.println(" ");
8740 pw.println(" mHandler:");
8741 mHandler.dump(new PrintWriterPrinter(pw), " ");
8742 }
8743 }
8744
8745 void dumpServices(PrintWriter pw) {
8746 synchronized (this) {
8747 if (checkCallingPermission(android.Manifest.permission.DUMP)
8748 != PackageManager.PERMISSION_GRANTED) {
8749 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8750 + Binder.getCallingPid()
8751 + ", uid=" + Binder.getCallingUid()
8752 + " without permission "
8753 + android.Manifest.permission.DUMP);
8754 return;
8755 }
8756 pw.println("Services in Current Activity Manager State:");
8757
8758 boolean needSep = false;
8759
8760 if (mServices.size() > 0) {
8761 pw.println(" Active services:");
8762 Iterator<ServiceRecord> it = mServices.values().iterator();
8763 while (it.hasNext()) {
8764 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008765 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008766 r.dump(pw, " ");
8767 }
8768 needSep = true;
8769 }
8770
8771 if (mPendingServices.size() > 0) {
8772 if (needSep) pw.println(" ");
8773 pw.println(" Pending services:");
8774 for (int i=0; i<mPendingServices.size(); i++) {
8775 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008776 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008777 r.dump(pw, " ");
8778 }
8779 needSep = true;
8780 }
8781
8782 if (mRestartingServices.size() > 0) {
8783 if (needSep) pw.println(" ");
8784 pw.println(" Restarting services:");
8785 for (int i=0; i<mRestartingServices.size(); i++) {
8786 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008787 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008788 r.dump(pw, " ");
8789 }
8790 needSep = true;
8791 }
8792
8793 if (mStoppingServices.size() > 0) {
8794 if (needSep) pw.println(" ");
8795 pw.println(" Stopping services:");
8796 for (int i=0; i<mStoppingServices.size(); i++) {
8797 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008798 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008799 r.dump(pw, " ");
8800 }
8801 needSep = true;
8802 }
8803
8804 if (mServiceConnections.size() > 0) {
8805 if (needSep) pw.println(" ");
8806 pw.println(" Connection bindings to services:");
8807 Iterator<ConnectionRecord> it
8808 = mServiceConnections.values().iterator();
8809 while (it.hasNext()) {
8810 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008811 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008812 r.dump(pw, " ");
8813 }
8814 }
8815 }
8816 }
8817
8818 void dumpProviders(PrintWriter pw) {
8819 synchronized (this) {
8820 if (checkCallingPermission(android.Manifest.permission.DUMP)
8821 != PackageManager.PERMISSION_GRANTED) {
8822 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8823 + Binder.getCallingPid()
8824 + ", uid=" + Binder.getCallingUid()
8825 + " without permission "
8826 + android.Manifest.permission.DUMP);
8827 return;
8828 }
8829
8830 pw.println("Content Providers in Current Activity Manager State:");
8831
8832 boolean needSep = false;
8833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008834 if (mProvidersByClass.size() > 0) {
8835 if (needSep) pw.println(" ");
8836 pw.println(" Published content providers (by class):");
8837 Iterator it = mProvidersByClass.entrySet().iterator();
8838 while (it.hasNext()) {
8839 Map.Entry e = (Map.Entry)it.next();
8840 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008841 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008842 r.dump(pw, " ");
8843 }
8844 needSep = true;
8845 }
8846
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008847 if (mProvidersByName.size() > 0) {
8848 pw.println(" ");
8849 pw.println(" Authority to provider mappings:");
8850 Iterator it = mProvidersByName.entrySet().iterator();
8851 while (it.hasNext()) {
8852 Map.Entry e = (Map.Entry)it.next();
8853 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8854 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8855 pw.println(r);
8856 }
8857 needSep = true;
8858 }
8859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008860 if (mLaunchingProviders.size() > 0) {
8861 if (needSep) pw.println(" ");
8862 pw.println(" Launching content providers:");
8863 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008864 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8865 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008866 }
8867 needSep = true;
8868 }
8869
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008870 if (mGrantedUriPermissions.size() > 0) {
8871 pw.println();
8872 pw.println("Granted Uri Permissions:");
8873 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8874 int uid = mGrantedUriPermissions.keyAt(i);
8875 HashMap<Uri, UriPermission> perms
8876 = mGrantedUriPermissions.valueAt(i);
8877 pw.print(" * UID "); pw.print(uid);
8878 pw.println(" holds:");
8879 for (UriPermission perm : perms.values()) {
8880 pw.print(" "); pw.println(perm);
8881 perm.dump(pw, " ");
8882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008883 }
8884 }
8885 }
8886 }
8887
8888 void dumpSenders(PrintWriter pw) {
8889 synchronized (this) {
8890 if (checkCallingPermission(android.Manifest.permission.DUMP)
8891 != PackageManager.PERMISSION_GRANTED) {
8892 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8893 + Binder.getCallingPid()
8894 + ", uid=" + Binder.getCallingUid()
8895 + " without permission "
8896 + android.Manifest.permission.DUMP);
8897 return;
8898 }
8899
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008900 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008901
8902 if (this.mIntentSenderRecords.size() > 0) {
8903 Iterator<WeakReference<PendingIntentRecord>> it
8904 = mIntentSenderRecords.values().iterator();
8905 while (it.hasNext()) {
8906 WeakReference<PendingIntentRecord> ref = it.next();
8907 PendingIntentRecord rec = ref != null ? ref.get(): null;
8908 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008909 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008910 rec.dump(pw, " ");
8911 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008912 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008913 }
8914 }
8915 }
8916 }
8917 }
8918
8919 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008920 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008921 TaskRecord lastTask = null;
8922 for (int i=list.size()-1; i>=0; i--) {
8923 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008924 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008925 if (lastTask != r.task) {
8926 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008927 pw.print(prefix);
8928 pw.print(full ? "* " : " ");
8929 pw.println(lastTask);
8930 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008931 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008932 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008933 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008934 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8935 pw.print(" #"); pw.print(i); pw.print(": ");
8936 pw.println(r);
8937 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008938 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008939 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008940 }
8941 }
8942
8943 private static final int dumpProcessList(PrintWriter pw, List list,
8944 String prefix, String normalLabel, String persistentLabel,
8945 boolean inclOomAdj) {
8946 int numPers = 0;
8947 for (int i=list.size()-1; i>=0; i--) {
8948 ProcessRecord r = (ProcessRecord)list.get(i);
8949 if (false) {
8950 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8951 + " #" + i + ":");
8952 r.dump(pw, prefix + " ");
8953 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008954 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008955 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008956 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008957 } else {
8958 pw.println(String.format("%s%s #%2d: %s",
8959 prefix, (r.persistent ? persistentLabel : normalLabel),
8960 i, r.toString()));
8961 }
8962 if (r.persistent) {
8963 numPers++;
8964 }
8965 }
8966 return numPers;
8967 }
8968
8969 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8970 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008971 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 long uptime = SystemClock.uptimeMillis();
8973 long realtime = SystemClock.elapsedRealtime();
8974
8975 if (isCheckinRequest) {
8976 // short checkin version
8977 pw.println(uptime + "," + realtime);
8978 pw.flush();
8979 } else {
8980 pw.println("Applications Memory Usage (kB):");
8981 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8982 }
8983 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8984 ProcessRecord r = (ProcessRecord)list.get(i);
8985 if (r.thread != null) {
8986 if (!isCheckinRequest) {
8987 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8988 pw.flush();
8989 }
8990 try {
8991 r.thread.asBinder().dump(fd, args);
8992 } catch (RemoteException e) {
8993 if (!isCheckinRequest) {
8994 pw.println("Got RemoteException!");
8995 pw.flush();
8996 }
8997 }
8998 }
8999 }
9000 }
9001
9002 /**
9003 * Searches array of arguments for the specified string
9004 * @param args array of argument strings
9005 * @param value value to search for
9006 * @return true if the value is contained in the array
9007 */
9008 private static boolean scanArgs(String[] args, String value) {
9009 if (args != null) {
9010 for (String arg : args) {
9011 if (value.equals(arg)) {
9012 return true;
9013 }
9014 }
9015 }
9016 return false;
9017 }
9018
Dianne Hackborn75b03852009-06-12 15:43:26 -07009019 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009020 int count = mHistory.size();
9021
9022 // convert the token to an entry in the history.
9023 HistoryRecord r = null;
9024 int index = -1;
9025 for (int i=count-1; i>=0; i--) {
9026 Object o = mHistory.get(i);
9027 if (o == token) {
9028 r = (HistoryRecord)o;
9029 index = i;
9030 break;
9031 }
9032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009033
9034 return index;
9035 }
9036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009037 private final void killServicesLocked(ProcessRecord app,
9038 boolean allowRestart) {
9039 // Report disconnected services.
9040 if (false) {
9041 // XXX we are letting the client link to the service for
9042 // death notifications.
9043 if (app.services.size() > 0) {
9044 Iterator it = app.services.iterator();
9045 while (it.hasNext()) {
9046 ServiceRecord r = (ServiceRecord)it.next();
9047 if (r.connections.size() > 0) {
9048 Iterator<ConnectionRecord> jt
9049 = r.connections.values().iterator();
9050 while (jt.hasNext()) {
9051 ConnectionRecord c = jt.next();
9052 if (c.binding.client != app) {
9053 try {
9054 //c.conn.connected(r.className, null);
9055 } catch (Exception e) {
9056 // todo: this should be asynchronous!
9057 Log.w(TAG, "Exception thrown disconnected servce "
9058 + r.shortName
9059 + " from app " + app.processName, e);
9060 }
9061 }
9062 }
9063 }
9064 }
9065 }
9066 }
9067
9068 // Clean up any connections this application has to other services.
9069 if (app.connections.size() > 0) {
9070 Iterator<ConnectionRecord> it = app.connections.iterator();
9071 while (it.hasNext()) {
9072 ConnectionRecord r = it.next();
9073 removeConnectionLocked(r, app, null);
9074 }
9075 }
9076 app.connections.clear();
9077
9078 if (app.services.size() != 0) {
9079 // Any services running in the application need to be placed
9080 // back in the pending list.
9081 Iterator it = app.services.iterator();
9082 while (it.hasNext()) {
9083 ServiceRecord sr = (ServiceRecord)it.next();
9084 synchronized (sr.stats.getBatteryStats()) {
9085 sr.stats.stopLaunchedLocked();
9086 }
9087 sr.app = null;
9088 sr.executeNesting = 0;
9089 mStoppingServices.remove(sr);
9090 if (sr.bindings.size() > 0) {
9091 Iterator<IntentBindRecord> bindings
9092 = sr.bindings.values().iterator();
9093 while (bindings.hasNext()) {
9094 IntentBindRecord b = bindings.next();
9095 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9096 + ": shouldUnbind=" + b.hasBound);
9097 b.binder = null;
9098 b.requested = b.received = b.hasBound = false;
9099 }
9100 }
9101
9102 if (sr.crashCount >= 2) {
9103 Log.w(TAG, "Service crashed " + sr.crashCount
9104 + " times, stopping: " + sr);
9105 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9106 sr.crashCount, sr.shortName, app.pid);
9107 bringDownServiceLocked(sr, true);
9108 } else if (!allowRestart) {
9109 bringDownServiceLocked(sr, true);
9110 } else {
9111 scheduleServiceRestartLocked(sr);
9112 }
9113 }
9114
9115 if (!allowRestart) {
9116 app.services.clear();
9117 }
9118 }
9119
9120 app.executingServices.clear();
9121 }
9122
9123 private final void removeDyingProviderLocked(ProcessRecord proc,
9124 ContentProviderRecord cpr) {
9125 synchronized (cpr) {
9126 cpr.launchingApp = null;
9127 cpr.notifyAll();
9128 }
9129
9130 mProvidersByClass.remove(cpr.info.name);
9131 String names[] = cpr.info.authority.split(";");
9132 for (int j = 0; j < names.length; j++) {
9133 mProvidersByName.remove(names[j]);
9134 }
9135
9136 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9137 while (cit.hasNext()) {
9138 ProcessRecord capp = cit.next();
9139 if (!capp.persistent && capp.thread != null
9140 && capp.pid != 0
9141 && capp.pid != MY_PID) {
9142 Log.i(TAG, "Killing app " + capp.processName
9143 + " (pid " + capp.pid
9144 + ") because provider " + cpr.info.name
9145 + " is in dying process " + proc.processName);
9146 Process.killProcess(capp.pid);
9147 }
9148 }
9149
9150 mLaunchingProviders.remove(cpr);
9151 }
9152
9153 /**
9154 * Main code for cleaning up a process when it has gone away. This is
9155 * called both as a result of the process dying, or directly when stopping
9156 * a process when running in single process mode.
9157 */
9158 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9159 boolean restarting, int index) {
9160 if (index >= 0) {
9161 mLRUProcesses.remove(index);
9162 }
9163
9164 // Dismiss any open dialogs.
9165 if (app.crashDialog != null) {
9166 app.crashDialog.dismiss();
9167 app.crashDialog = null;
9168 }
9169 if (app.anrDialog != null) {
9170 app.anrDialog.dismiss();
9171 app.anrDialog = null;
9172 }
9173 if (app.waitDialog != null) {
9174 app.waitDialog.dismiss();
9175 app.waitDialog = null;
9176 }
9177
9178 app.crashing = false;
9179 app.notResponding = false;
9180
9181 app.resetPackageList();
9182 app.thread = null;
9183 app.forcingToForeground = null;
9184 app.foregroundServices = false;
9185
9186 killServicesLocked(app, true);
9187
9188 boolean restart = false;
9189
9190 int NL = mLaunchingProviders.size();
9191
9192 // Remove published content providers.
9193 if (!app.pubProviders.isEmpty()) {
9194 Iterator it = app.pubProviders.values().iterator();
9195 while (it.hasNext()) {
9196 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9197 cpr.provider = null;
9198 cpr.app = null;
9199
9200 // See if someone is waiting for this provider... in which
9201 // case we don't remove it, but just let it restart.
9202 int i = 0;
9203 if (!app.bad) {
9204 for (; i<NL; i++) {
9205 if (mLaunchingProviders.get(i) == cpr) {
9206 restart = true;
9207 break;
9208 }
9209 }
9210 } else {
9211 i = NL;
9212 }
9213
9214 if (i >= NL) {
9215 removeDyingProviderLocked(app, cpr);
9216 NL = mLaunchingProviders.size();
9217 }
9218 }
9219 app.pubProviders.clear();
9220 }
9221
9222 // Look through the content providers we are waiting to have launched,
9223 // and if any run in this process then either schedule a restart of
9224 // the process or kill the client waiting for it if this process has
9225 // gone bad.
9226 for (int i=0; i<NL; i++) {
9227 ContentProviderRecord cpr = (ContentProviderRecord)
9228 mLaunchingProviders.get(i);
9229 if (cpr.launchingApp == app) {
9230 if (!app.bad) {
9231 restart = true;
9232 } else {
9233 removeDyingProviderLocked(app, cpr);
9234 NL = mLaunchingProviders.size();
9235 }
9236 }
9237 }
9238
9239 // Unregister from connected content providers.
9240 if (!app.conProviders.isEmpty()) {
9241 Iterator it = app.conProviders.iterator();
9242 while (it.hasNext()) {
9243 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9244 cpr.clients.remove(app);
9245 }
9246 app.conProviders.clear();
9247 }
9248
9249 skipCurrentReceiverLocked(app);
9250
9251 // Unregister any receivers.
9252 if (app.receivers.size() > 0) {
9253 Iterator<ReceiverList> it = app.receivers.iterator();
9254 while (it.hasNext()) {
9255 removeReceiverLocked(it.next());
9256 }
9257 app.receivers.clear();
9258 }
9259
Christopher Tate181fafa2009-05-14 11:12:14 -07009260 // If the app is undergoing backup, tell the backup manager about it
9261 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9262 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9263 try {
9264 IBackupManager bm = IBackupManager.Stub.asInterface(
9265 ServiceManager.getService(Context.BACKUP_SERVICE));
9266 bm.agentDisconnected(app.info.packageName);
9267 } catch (RemoteException e) {
9268 // can't happen; backup manager is local
9269 }
9270 }
9271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009272 // If the caller is restarting this app, then leave it in its
9273 // current lists and let the caller take care of it.
9274 if (restarting) {
9275 return;
9276 }
9277
9278 if (!app.persistent) {
9279 if (DEBUG_PROCESSES) Log.v(TAG,
9280 "Removing non-persistent process during cleanup: " + app);
9281 mProcessNames.remove(app.processName, app.info.uid);
9282 } else if (!app.removed) {
9283 // This app is persistent, so we need to keep its record around.
9284 // If it is not already on the pending app list, add it there
9285 // and start a new process for it.
9286 app.thread = null;
9287 app.forcingToForeground = null;
9288 app.foregroundServices = false;
9289 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9290 mPersistentStartingProcesses.add(app);
9291 restart = true;
9292 }
9293 }
9294 mProcessesOnHold.remove(app);
9295
The Android Open Source Project4df24232009-03-05 14:34:35 -08009296 if (app == mHomeProcess) {
9297 mHomeProcess = null;
9298 }
9299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009300 if (restart) {
9301 // We have components that still need to be running in the
9302 // process, so re-launch it.
9303 mProcessNames.put(app.processName, app.info.uid, app);
9304 startProcessLocked(app, "restart", app.processName);
9305 } else if (app.pid > 0 && app.pid != MY_PID) {
9306 // Goodbye!
9307 synchronized (mPidsSelfLocked) {
9308 mPidsSelfLocked.remove(app.pid);
9309 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9310 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009311 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009312 }
9313 }
9314
9315 // =========================================================
9316 // SERVICES
9317 // =========================================================
9318
9319 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9320 ActivityManager.RunningServiceInfo info =
9321 new ActivityManager.RunningServiceInfo();
9322 info.service = r.name;
9323 if (r.app != null) {
9324 info.pid = r.app.pid;
9325 }
9326 info.process = r.processName;
9327 info.foreground = r.isForeground;
9328 info.activeSince = r.createTime;
9329 info.started = r.startRequested;
9330 info.clientCount = r.connections.size();
9331 info.crashCount = r.crashCount;
9332 info.lastActivityTime = r.lastActivity;
9333 return info;
9334 }
9335
9336 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9337 int flags) {
9338 synchronized (this) {
9339 ArrayList<ActivityManager.RunningServiceInfo> res
9340 = new ArrayList<ActivityManager.RunningServiceInfo>();
9341
9342 if (mServices.size() > 0) {
9343 Iterator<ServiceRecord> it = mServices.values().iterator();
9344 while (it.hasNext() && res.size() < maxNum) {
9345 res.add(makeRunningServiceInfoLocked(it.next()));
9346 }
9347 }
9348
9349 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9350 ServiceRecord r = mRestartingServices.get(i);
9351 ActivityManager.RunningServiceInfo info =
9352 makeRunningServiceInfoLocked(r);
9353 info.restarting = r.nextRestartTime;
9354 res.add(info);
9355 }
9356
9357 return res;
9358 }
9359 }
9360
9361 private final ServiceRecord findServiceLocked(ComponentName name,
9362 IBinder token) {
9363 ServiceRecord r = mServices.get(name);
9364 return r == token ? r : null;
9365 }
9366
9367 private final class ServiceLookupResult {
9368 final ServiceRecord record;
9369 final String permission;
9370
9371 ServiceLookupResult(ServiceRecord _record, String _permission) {
9372 record = _record;
9373 permission = _permission;
9374 }
9375 };
9376
9377 private ServiceLookupResult findServiceLocked(Intent service,
9378 String resolvedType) {
9379 ServiceRecord r = null;
9380 if (service.getComponent() != null) {
9381 r = mServices.get(service.getComponent());
9382 }
9383 if (r == null) {
9384 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9385 r = mServicesByIntent.get(filter);
9386 }
9387
9388 if (r == null) {
9389 try {
9390 ResolveInfo rInfo =
9391 ActivityThread.getPackageManager().resolveService(
9392 service, resolvedType, 0);
9393 ServiceInfo sInfo =
9394 rInfo != null ? rInfo.serviceInfo : null;
9395 if (sInfo == null) {
9396 return null;
9397 }
9398
9399 ComponentName name = new ComponentName(
9400 sInfo.applicationInfo.packageName, sInfo.name);
9401 r = mServices.get(name);
9402 } catch (RemoteException ex) {
9403 // pm is in same process, this will never happen.
9404 }
9405 }
9406 if (r != null) {
9407 int callingPid = Binder.getCallingPid();
9408 int callingUid = Binder.getCallingUid();
9409 if (checkComponentPermission(r.permission,
9410 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9411 != PackageManager.PERMISSION_GRANTED) {
9412 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9413 + " from pid=" + callingPid
9414 + ", uid=" + callingUid
9415 + " requires " + r.permission);
9416 return new ServiceLookupResult(null, r.permission);
9417 }
9418 return new ServiceLookupResult(r, null);
9419 }
9420 return null;
9421 }
9422
9423 private class ServiceRestarter implements Runnable {
9424 private ServiceRecord mService;
9425
9426 void setService(ServiceRecord service) {
9427 mService = service;
9428 }
9429
9430 public void run() {
9431 synchronized(ActivityManagerService.this) {
9432 performServiceRestartLocked(mService);
9433 }
9434 }
9435 }
9436
9437 private ServiceLookupResult retrieveServiceLocked(Intent service,
9438 String resolvedType, int callingPid, int callingUid) {
9439 ServiceRecord r = null;
9440 if (service.getComponent() != null) {
9441 r = mServices.get(service.getComponent());
9442 }
9443 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9444 r = mServicesByIntent.get(filter);
9445 if (r == null) {
9446 try {
9447 ResolveInfo rInfo =
9448 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009449 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009450 ServiceInfo sInfo =
9451 rInfo != null ? rInfo.serviceInfo : null;
9452 if (sInfo == null) {
9453 Log.w(TAG, "Unable to start service " + service +
9454 ": not found");
9455 return null;
9456 }
9457
9458 ComponentName name = new ComponentName(
9459 sInfo.applicationInfo.packageName, sInfo.name);
9460 r = mServices.get(name);
9461 if (r == null) {
9462 filter = new Intent.FilterComparison(service.cloneFilter());
9463 ServiceRestarter res = new ServiceRestarter();
9464 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9465 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9466 synchronized (stats) {
9467 ss = stats.getServiceStatsLocked(
9468 sInfo.applicationInfo.uid, sInfo.packageName,
9469 sInfo.name);
9470 }
9471 r = new ServiceRecord(ss, name, filter, sInfo, res);
9472 res.setService(r);
9473 mServices.put(name, r);
9474 mServicesByIntent.put(filter, r);
9475
9476 // Make sure this component isn't in the pending list.
9477 int N = mPendingServices.size();
9478 for (int i=0; i<N; i++) {
9479 ServiceRecord pr = mPendingServices.get(i);
9480 if (pr.name.equals(name)) {
9481 mPendingServices.remove(i);
9482 i--;
9483 N--;
9484 }
9485 }
9486 }
9487 } catch (RemoteException ex) {
9488 // pm is in same process, this will never happen.
9489 }
9490 }
9491 if (r != null) {
9492 if (checkComponentPermission(r.permission,
9493 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9494 != PackageManager.PERMISSION_GRANTED) {
9495 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9496 + " from pid=" + Binder.getCallingPid()
9497 + ", uid=" + Binder.getCallingUid()
9498 + " requires " + r.permission);
9499 return new ServiceLookupResult(null, r.permission);
9500 }
9501 return new ServiceLookupResult(r, null);
9502 }
9503 return null;
9504 }
9505
9506 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9507 long now = SystemClock.uptimeMillis();
9508 if (r.executeNesting == 0 && r.app != null) {
9509 if (r.app.executingServices.size() == 0) {
9510 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9511 msg.obj = r.app;
9512 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9513 }
9514 r.app.executingServices.add(r);
9515 }
9516 r.executeNesting++;
9517 r.executingStart = now;
9518 }
9519
9520 private final void sendServiceArgsLocked(ServiceRecord r,
9521 boolean oomAdjusted) {
9522 final int N = r.startArgs.size();
9523 if (N == 0) {
9524 return;
9525 }
9526
9527 final int BASEID = r.lastStartId - N + 1;
9528 int i = 0;
9529 while (i < N) {
9530 try {
9531 Intent args = r.startArgs.get(i);
9532 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9533 + r.name + " " + r.intent + " args=" + args);
9534 bumpServiceExecutingLocked(r);
9535 if (!oomAdjusted) {
9536 oomAdjusted = true;
9537 updateOomAdjLocked(r.app);
9538 }
9539 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9540 i++;
9541 } catch (Exception e) {
9542 break;
9543 }
9544 }
9545 if (i == N) {
9546 r.startArgs.clear();
9547 } else {
9548 while (i > 0) {
9549 r.startArgs.remove(0);
9550 i--;
9551 }
9552 }
9553 }
9554
9555 private final boolean requestServiceBindingLocked(ServiceRecord r,
9556 IntentBindRecord i, boolean rebind) {
9557 if (r.app == null || r.app.thread == null) {
9558 // If service is not currently running, can't yet bind.
9559 return false;
9560 }
9561 if ((!i.requested || rebind) && i.apps.size() > 0) {
9562 try {
9563 bumpServiceExecutingLocked(r);
9564 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9565 + ": shouldUnbind=" + i.hasBound);
9566 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9567 if (!rebind) {
9568 i.requested = true;
9569 }
9570 i.hasBound = true;
9571 i.doRebind = false;
9572 } catch (RemoteException e) {
9573 return false;
9574 }
9575 }
9576 return true;
9577 }
9578
9579 private final void requestServiceBindingsLocked(ServiceRecord r) {
9580 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9581 while (bindings.hasNext()) {
9582 IntentBindRecord i = bindings.next();
9583 if (!requestServiceBindingLocked(r, i, false)) {
9584 break;
9585 }
9586 }
9587 }
9588
9589 private final void realStartServiceLocked(ServiceRecord r,
9590 ProcessRecord app) throws RemoteException {
9591 if (app.thread == null) {
9592 throw new RemoteException();
9593 }
9594
9595 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009596 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009597
9598 app.services.add(r);
9599 bumpServiceExecutingLocked(r);
9600 updateLRUListLocked(app, true);
9601
9602 boolean created = false;
9603 try {
9604 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9605 + r.name + " " + r.intent);
9606 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9607 System.identityHashCode(r), r.shortName,
9608 r.intent.getIntent().toString(), r.app.pid);
9609 synchronized (r.stats.getBatteryStats()) {
9610 r.stats.startLaunchedLocked();
9611 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009612 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009613 app.thread.scheduleCreateService(r, r.serviceInfo);
9614 created = true;
9615 } finally {
9616 if (!created) {
9617 app.services.remove(r);
9618 scheduleServiceRestartLocked(r);
9619 }
9620 }
9621
9622 requestServiceBindingsLocked(r);
9623 sendServiceArgsLocked(r, true);
9624 }
9625
9626 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9627 r.totalRestartCount++;
9628 if (r.restartDelay == 0) {
9629 r.restartCount++;
9630 r.restartDelay = SERVICE_RESTART_DURATION;
9631 } else {
9632 // If it has been a "reasonably long time" since the service
9633 // was started, then reset our restart duration back to
9634 // the beginning, so we don't infinitely increase the duration
9635 // on a service that just occasionally gets killed (which is
9636 // a normal case, due to process being killed to reclaim memory).
9637 long now = SystemClock.uptimeMillis();
9638 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9639 r.restartCount = 1;
9640 r.restartDelay = SERVICE_RESTART_DURATION;
9641 } else {
9642 r.restartDelay *= 2;
9643 }
9644 }
9645 if (!mRestartingServices.contains(r)) {
9646 mRestartingServices.add(r);
9647 }
9648 mHandler.removeCallbacks(r.restarter);
9649 mHandler.postDelayed(r.restarter, r.restartDelay);
9650 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9651 Log.w(TAG, "Scheduling restart of crashed service "
9652 + r.shortName + " in " + r.restartDelay + "ms");
9653 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9654 r.shortName, r.restartDelay);
9655
9656 Message msg = Message.obtain();
9657 msg.what = SERVICE_ERROR_MSG;
9658 msg.obj = r;
9659 mHandler.sendMessage(msg);
9660 }
9661
9662 final void performServiceRestartLocked(ServiceRecord r) {
9663 if (!mRestartingServices.contains(r)) {
9664 return;
9665 }
9666 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9667 }
9668
9669 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9670 if (r.restartDelay == 0) {
9671 return false;
9672 }
9673 r.resetRestartCounter();
9674 mRestartingServices.remove(r);
9675 mHandler.removeCallbacks(r.restarter);
9676 return true;
9677 }
9678
9679 private final boolean bringUpServiceLocked(ServiceRecord r,
9680 int intentFlags, boolean whileRestarting) {
9681 //Log.i(TAG, "Bring up service:");
9682 //r.dump(" ");
9683
9684 if (r.app != null) {
9685 sendServiceArgsLocked(r, false);
9686 return true;
9687 }
9688
9689 if (!whileRestarting && r.restartDelay > 0) {
9690 // If waiting for a restart, then do nothing.
9691 return true;
9692 }
9693
9694 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9695 + " " + r.intent);
9696
9697 final String appName = r.processName;
9698 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9699 if (app != null && app.thread != null) {
9700 try {
9701 realStartServiceLocked(r, app);
9702 return true;
9703 } catch (RemoteException e) {
9704 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9705 }
9706
9707 // If a dead object exception was thrown -- fall through to
9708 // restart the application.
9709 }
9710
9711 if (!mPendingServices.contains(r)) {
9712 // Not running -- get it started, and enqueue this service record
9713 // to be executed when the app comes up.
9714 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9715 "service", r.name) == null) {
9716 Log.w(TAG, "Unable to launch app "
9717 + r.appInfo.packageName + "/"
9718 + r.appInfo.uid + " for service "
9719 + r.intent.getIntent() + ": process is bad");
9720 bringDownServiceLocked(r, true);
9721 return false;
9722 }
9723 mPendingServices.add(r);
9724 }
9725 return true;
9726 }
9727
9728 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9729 //Log.i(TAG, "Bring down service:");
9730 //r.dump(" ");
9731
9732 // Does it still need to run?
9733 if (!force && r.startRequested) {
9734 return;
9735 }
9736 if (r.connections.size() > 0) {
9737 if (!force) {
9738 // XXX should probably keep a count of the number of auto-create
9739 // connections directly in the service.
9740 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9741 while (it.hasNext()) {
9742 ConnectionRecord cr = it.next();
9743 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9744 return;
9745 }
9746 }
9747 }
9748
9749 // Report to all of the connections that the service is no longer
9750 // available.
9751 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9752 while (it.hasNext()) {
9753 ConnectionRecord c = it.next();
9754 try {
9755 // todo: shouldn't be a synchronous call!
9756 c.conn.connected(r.name, null);
9757 } catch (Exception e) {
9758 Log.w(TAG, "Failure disconnecting service " + r.name +
9759 " to connection " + c.conn.asBinder() +
9760 " (in " + c.binding.client.processName + ")", e);
9761 }
9762 }
9763 }
9764
9765 // Tell the service that it has been unbound.
9766 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9767 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9768 while (it.hasNext()) {
9769 IntentBindRecord ibr = it.next();
9770 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9771 + ": hasBound=" + ibr.hasBound);
9772 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9773 try {
9774 bumpServiceExecutingLocked(r);
9775 updateOomAdjLocked(r.app);
9776 ibr.hasBound = false;
9777 r.app.thread.scheduleUnbindService(r,
9778 ibr.intent.getIntent());
9779 } catch (Exception e) {
9780 Log.w(TAG, "Exception when unbinding service "
9781 + r.shortName, e);
9782 serviceDoneExecutingLocked(r, true);
9783 }
9784 }
9785 }
9786 }
9787
9788 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9789 + " " + r.intent);
9790 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9791 System.identityHashCode(r), r.shortName,
9792 (r.app != null) ? r.app.pid : -1);
9793
9794 mServices.remove(r.name);
9795 mServicesByIntent.remove(r.intent);
9796 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9797 r.totalRestartCount = 0;
9798 unscheduleServiceRestartLocked(r);
9799
9800 // Also make sure it is not on the pending list.
9801 int N = mPendingServices.size();
9802 for (int i=0; i<N; i++) {
9803 if (mPendingServices.get(i) == r) {
9804 mPendingServices.remove(i);
9805 if (DEBUG_SERVICE) Log.v(
9806 TAG, "Removed pending service: " + r.shortName);
9807 i--;
9808 N--;
9809 }
9810 }
9811
9812 if (r.app != null) {
9813 synchronized (r.stats.getBatteryStats()) {
9814 r.stats.stopLaunchedLocked();
9815 }
9816 r.app.services.remove(r);
9817 if (r.app.thread != null) {
9818 updateServiceForegroundLocked(r.app, false);
9819 try {
9820 Log.i(TAG, "Stopping service: " + r.shortName);
9821 bumpServiceExecutingLocked(r);
9822 mStoppingServices.add(r);
9823 updateOomAdjLocked(r.app);
9824 r.app.thread.scheduleStopService(r);
9825 } catch (Exception e) {
9826 Log.w(TAG, "Exception when stopping service "
9827 + r.shortName, e);
9828 serviceDoneExecutingLocked(r, true);
9829 }
9830 } else {
9831 if (DEBUG_SERVICE) Log.v(
9832 TAG, "Removed service that has no process: " + r.shortName);
9833 }
9834 } else {
9835 if (DEBUG_SERVICE) Log.v(
9836 TAG, "Removed service that is not running: " + r.shortName);
9837 }
9838 }
9839
9840 ComponentName startServiceLocked(IApplicationThread caller,
9841 Intent service, String resolvedType,
9842 int callingPid, int callingUid) {
9843 synchronized(this) {
9844 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9845 + " type=" + resolvedType + " args=" + service.getExtras());
9846
9847 if (caller != null) {
9848 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9849 if (callerApp == null) {
9850 throw new SecurityException(
9851 "Unable to find app for caller " + caller
9852 + " (pid=" + Binder.getCallingPid()
9853 + ") when starting service " + service);
9854 }
9855 }
9856
9857 ServiceLookupResult res =
9858 retrieveServiceLocked(service, resolvedType,
9859 callingPid, callingUid);
9860 if (res == null) {
9861 return null;
9862 }
9863 if (res.record == null) {
9864 return new ComponentName("!", res.permission != null
9865 ? res.permission : "private to package");
9866 }
9867 ServiceRecord r = res.record;
9868 if (unscheduleServiceRestartLocked(r)) {
9869 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9870 + r.shortName);
9871 }
9872 r.startRequested = true;
9873 r.startArgs.add(service);
9874 r.lastStartId++;
9875 if (r.lastStartId < 1) {
9876 r.lastStartId = 1;
9877 }
9878 r.lastActivity = SystemClock.uptimeMillis();
9879 synchronized (r.stats.getBatteryStats()) {
9880 r.stats.startRunningLocked();
9881 }
9882 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9883 return new ComponentName("!", "Service process is bad");
9884 }
9885 return r.name;
9886 }
9887 }
9888
9889 public ComponentName startService(IApplicationThread caller, Intent service,
9890 String resolvedType) {
9891 // Refuse possible leaked file descriptors
9892 if (service != null && service.hasFileDescriptors() == true) {
9893 throw new IllegalArgumentException("File descriptors passed in Intent");
9894 }
9895
9896 synchronized(this) {
9897 final int callingPid = Binder.getCallingPid();
9898 final int callingUid = Binder.getCallingUid();
9899 final long origId = Binder.clearCallingIdentity();
9900 ComponentName res = startServiceLocked(caller, service,
9901 resolvedType, callingPid, callingUid);
9902 Binder.restoreCallingIdentity(origId);
9903 return res;
9904 }
9905 }
9906
9907 ComponentName startServiceInPackage(int uid,
9908 Intent service, String resolvedType) {
9909 synchronized(this) {
9910 final long origId = Binder.clearCallingIdentity();
9911 ComponentName res = startServiceLocked(null, service,
9912 resolvedType, -1, uid);
9913 Binder.restoreCallingIdentity(origId);
9914 return res;
9915 }
9916 }
9917
9918 public int stopService(IApplicationThread caller, Intent service,
9919 String resolvedType) {
9920 // Refuse possible leaked file descriptors
9921 if (service != null && service.hasFileDescriptors() == true) {
9922 throw new IllegalArgumentException("File descriptors passed in Intent");
9923 }
9924
9925 synchronized(this) {
9926 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9927 + " type=" + resolvedType);
9928
9929 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9930 if (caller != null && callerApp == null) {
9931 throw new SecurityException(
9932 "Unable to find app for caller " + caller
9933 + " (pid=" + Binder.getCallingPid()
9934 + ") when stopping service " + service);
9935 }
9936
9937 // If this service is active, make sure it is stopped.
9938 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9939 if (r != null) {
9940 if (r.record != null) {
9941 synchronized (r.record.stats.getBatteryStats()) {
9942 r.record.stats.stopRunningLocked();
9943 }
9944 r.record.startRequested = false;
9945 final long origId = Binder.clearCallingIdentity();
9946 bringDownServiceLocked(r.record, false);
9947 Binder.restoreCallingIdentity(origId);
9948 return 1;
9949 }
9950 return -1;
9951 }
9952 }
9953
9954 return 0;
9955 }
9956
9957 public IBinder peekService(Intent service, String resolvedType) {
9958 // Refuse possible leaked file descriptors
9959 if (service != null && service.hasFileDescriptors() == true) {
9960 throw new IllegalArgumentException("File descriptors passed in Intent");
9961 }
9962
9963 IBinder ret = null;
9964
9965 synchronized(this) {
9966 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9967
9968 if (r != null) {
9969 // r.record is null if findServiceLocked() failed the caller permission check
9970 if (r.record == null) {
9971 throw new SecurityException(
9972 "Permission Denial: Accessing service " + r.record.name
9973 + " from pid=" + Binder.getCallingPid()
9974 + ", uid=" + Binder.getCallingUid()
9975 + " requires " + r.permission);
9976 }
9977 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9978 if (ib != null) {
9979 ret = ib.binder;
9980 }
9981 }
9982 }
9983
9984 return ret;
9985 }
9986
9987 public boolean stopServiceToken(ComponentName className, IBinder token,
9988 int startId) {
9989 synchronized(this) {
9990 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9991 + " " + token + " startId=" + startId);
9992 ServiceRecord r = findServiceLocked(className, token);
9993 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9994 synchronized (r.stats.getBatteryStats()) {
9995 r.stats.stopRunningLocked();
9996 r.startRequested = false;
9997 }
9998 final long origId = Binder.clearCallingIdentity();
9999 bringDownServiceLocked(r, false);
10000 Binder.restoreCallingIdentity(origId);
10001 return true;
10002 }
10003 }
10004 return false;
10005 }
10006
10007 public void setServiceForeground(ComponentName className, IBinder token,
10008 boolean isForeground) {
10009 synchronized(this) {
10010 ServiceRecord r = findServiceLocked(className, token);
10011 if (r != null) {
10012 if (r.isForeground != isForeground) {
10013 final long origId = Binder.clearCallingIdentity();
10014 r.isForeground = isForeground;
10015 if (r.app != null) {
10016 updateServiceForegroundLocked(r.app, true);
10017 }
10018 Binder.restoreCallingIdentity(origId);
10019 }
10020 }
10021 }
10022 }
10023
10024 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10025 boolean anyForeground = false;
10026 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10027 if (sr.isForeground) {
10028 anyForeground = true;
10029 break;
10030 }
10031 }
10032 if (anyForeground != proc.foregroundServices) {
10033 proc.foregroundServices = anyForeground;
10034 if (oomAdj) {
10035 updateOomAdjLocked();
10036 }
10037 }
10038 }
10039
10040 public int bindService(IApplicationThread caller, IBinder token,
10041 Intent service, String resolvedType,
10042 IServiceConnection connection, int flags) {
10043 // Refuse possible leaked file descriptors
10044 if (service != null && service.hasFileDescriptors() == true) {
10045 throw new IllegalArgumentException("File descriptors passed in Intent");
10046 }
10047
10048 synchronized(this) {
10049 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10050 + " type=" + resolvedType + " conn=" + connection.asBinder()
10051 + " flags=0x" + Integer.toHexString(flags));
10052 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10053 if (callerApp == null) {
10054 throw new SecurityException(
10055 "Unable to find app for caller " + caller
10056 + " (pid=" + Binder.getCallingPid()
10057 + ") when binding service " + service);
10058 }
10059
10060 HistoryRecord activity = null;
10061 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010062 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010063 if (aindex < 0) {
10064 Log.w(TAG, "Binding with unknown activity: " + token);
10065 return 0;
10066 }
10067 activity = (HistoryRecord)mHistory.get(aindex);
10068 }
10069
10070 ServiceLookupResult res =
10071 retrieveServiceLocked(service, resolvedType,
10072 Binder.getCallingPid(), Binder.getCallingUid());
10073 if (res == null) {
10074 return 0;
10075 }
10076 if (res.record == null) {
10077 return -1;
10078 }
10079 ServiceRecord s = res.record;
10080
10081 final long origId = Binder.clearCallingIdentity();
10082
10083 if (unscheduleServiceRestartLocked(s)) {
10084 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10085 + s.shortName);
10086 }
10087
10088 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10089 ConnectionRecord c = new ConnectionRecord(b, activity,
10090 connection, flags);
10091
10092 IBinder binder = connection.asBinder();
10093 s.connections.put(binder, c);
10094 b.connections.add(c);
10095 if (activity != null) {
10096 if (activity.connections == null) {
10097 activity.connections = new HashSet<ConnectionRecord>();
10098 }
10099 activity.connections.add(c);
10100 }
10101 b.client.connections.add(c);
10102 mServiceConnections.put(binder, c);
10103
10104 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10105 s.lastActivity = SystemClock.uptimeMillis();
10106 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10107 return 0;
10108 }
10109 }
10110
10111 if (s.app != null) {
10112 // This could have made the service more important.
10113 updateOomAdjLocked(s.app);
10114 }
10115
10116 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10117 + ": received=" + b.intent.received
10118 + " apps=" + b.intent.apps.size()
10119 + " doRebind=" + b.intent.doRebind);
10120
10121 if (s.app != null && b.intent.received) {
10122 // Service is already running, so we can immediately
10123 // publish the connection.
10124 try {
10125 c.conn.connected(s.name, b.intent.binder);
10126 } catch (Exception e) {
10127 Log.w(TAG, "Failure sending service " + s.shortName
10128 + " to connection " + c.conn.asBinder()
10129 + " (in " + c.binding.client.processName + ")", e);
10130 }
10131
10132 // If this is the first app connected back to this binding,
10133 // and the service had previously asked to be told when
10134 // rebound, then do so.
10135 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10136 requestServiceBindingLocked(s, b.intent, true);
10137 }
10138 } else if (!b.intent.requested) {
10139 requestServiceBindingLocked(s, b.intent, false);
10140 }
10141
10142 Binder.restoreCallingIdentity(origId);
10143 }
10144
10145 return 1;
10146 }
10147
10148 private void removeConnectionLocked(
10149 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10150 IBinder binder = c.conn.asBinder();
10151 AppBindRecord b = c.binding;
10152 ServiceRecord s = b.service;
10153 s.connections.remove(binder);
10154 b.connections.remove(c);
10155 if (c.activity != null && c.activity != skipAct) {
10156 if (c.activity.connections != null) {
10157 c.activity.connections.remove(c);
10158 }
10159 }
10160 if (b.client != skipApp) {
10161 b.client.connections.remove(c);
10162 }
10163 mServiceConnections.remove(binder);
10164
10165 if (b.connections.size() == 0) {
10166 b.intent.apps.remove(b.client);
10167 }
10168
10169 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10170 + ": shouldUnbind=" + b.intent.hasBound);
10171 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10172 && b.intent.hasBound) {
10173 try {
10174 bumpServiceExecutingLocked(s);
10175 updateOomAdjLocked(s.app);
10176 b.intent.hasBound = false;
10177 // Assume the client doesn't want to know about a rebind;
10178 // we will deal with that later if it asks for one.
10179 b.intent.doRebind = false;
10180 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10181 } catch (Exception e) {
10182 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10183 serviceDoneExecutingLocked(s, true);
10184 }
10185 }
10186
10187 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10188 bringDownServiceLocked(s, false);
10189 }
10190 }
10191
10192 public boolean unbindService(IServiceConnection connection) {
10193 synchronized (this) {
10194 IBinder binder = connection.asBinder();
10195 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10196 ConnectionRecord r = mServiceConnections.get(binder);
10197 if (r == null) {
10198 Log.w(TAG, "Unbind failed: could not find connection for "
10199 + connection.asBinder());
10200 return false;
10201 }
10202
10203 final long origId = Binder.clearCallingIdentity();
10204
10205 removeConnectionLocked(r, null, null);
10206
10207 if (r.binding.service.app != null) {
10208 // This could have made the service less important.
10209 updateOomAdjLocked(r.binding.service.app);
10210 }
10211
10212 Binder.restoreCallingIdentity(origId);
10213 }
10214
10215 return true;
10216 }
10217
10218 public void publishService(IBinder token, Intent intent, IBinder service) {
10219 // Refuse possible leaked file descriptors
10220 if (intent != null && intent.hasFileDescriptors() == true) {
10221 throw new IllegalArgumentException("File descriptors passed in Intent");
10222 }
10223
10224 synchronized(this) {
10225 if (!(token instanceof ServiceRecord)) {
10226 throw new IllegalArgumentException("Invalid service token");
10227 }
10228 ServiceRecord r = (ServiceRecord)token;
10229
10230 final long origId = Binder.clearCallingIdentity();
10231
10232 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10233 + " " + intent + ": " + service);
10234 if (r != null) {
10235 Intent.FilterComparison filter
10236 = new Intent.FilterComparison(intent);
10237 IntentBindRecord b = r.bindings.get(filter);
10238 if (b != null && !b.received) {
10239 b.binder = service;
10240 b.requested = true;
10241 b.received = true;
10242 if (r.connections.size() > 0) {
10243 Iterator<ConnectionRecord> it
10244 = r.connections.values().iterator();
10245 while (it.hasNext()) {
10246 ConnectionRecord c = it.next();
10247 if (!filter.equals(c.binding.intent.intent)) {
10248 if (DEBUG_SERVICE) Log.v(
10249 TAG, "Not publishing to: " + c);
10250 if (DEBUG_SERVICE) Log.v(
10251 TAG, "Bound intent: " + c.binding.intent.intent);
10252 if (DEBUG_SERVICE) Log.v(
10253 TAG, "Published intent: " + intent);
10254 continue;
10255 }
10256 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10257 try {
10258 c.conn.connected(r.name, service);
10259 } catch (Exception e) {
10260 Log.w(TAG, "Failure sending service " + r.name +
10261 " to connection " + c.conn.asBinder() +
10262 " (in " + c.binding.client.processName + ")", e);
10263 }
10264 }
10265 }
10266 }
10267
10268 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10269
10270 Binder.restoreCallingIdentity(origId);
10271 }
10272 }
10273 }
10274
10275 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10276 // Refuse possible leaked file descriptors
10277 if (intent != null && intent.hasFileDescriptors() == true) {
10278 throw new IllegalArgumentException("File descriptors passed in Intent");
10279 }
10280
10281 synchronized(this) {
10282 if (!(token instanceof ServiceRecord)) {
10283 throw new IllegalArgumentException("Invalid service token");
10284 }
10285 ServiceRecord r = (ServiceRecord)token;
10286
10287 final long origId = Binder.clearCallingIdentity();
10288
10289 if (r != null) {
10290 Intent.FilterComparison filter
10291 = new Intent.FilterComparison(intent);
10292 IntentBindRecord b = r.bindings.get(filter);
10293 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10294 + " at " + b + ": apps="
10295 + (b != null ? b.apps.size() : 0));
10296 if (b != null) {
10297 if (b.apps.size() > 0) {
10298 // Applications have already bound since the last
10299 // unbind, so just rebind right here.
10300 requestServiceBindingLocked(r, b, true);
10301 } else {
10302 // Note to tell the service the next time there is
10303 // a new client.
10304 b.doRebind = true;
10305 }
10306 }
10307
10308 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10309
10310 Binder.restoreCallingIdentity(origId);
10311 }
10312 }
10313 }
10314
10315 public void serviceDoneExecuting(IBinder token) {
10316 synchronized(this) {
10317 if (!(token instanceof ServiceRecord)) {
10318 throw new IllegalArgumentException("Invalid service token");
10319 }
10320 ServiceRecord r = (ServiceRecord)token;
10321 boolean inStopping = mStoppingServices.contains(token);
10322 if (r != null) {
10323 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10324 + ": nesting=" + r.executeNesting
10325 + ", inStopping=" + inStopping);
10326 if (r != token) {
10327 Log.w(TAG, "Done executing service " + r.name
10328 + " with incorrect token: given " + token
10329 + ", expected " + r);
10330 return;
10331 }
10332
10333 final long origId = Binder.clearCallingIdentity();
10334 serviceDoneExecutingLocked(r, inStopping);
10335 Binder.restoreCallingIdentity(origId);
10336 } else {
10337 Log.w(TAG, "Done executing unknown service " + r.name
10338 + " with token " + token);
10339 }
10340 }
10341 }
10342
10343 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10344 r.executeNesting--;
10345 if (r.executeNesting <= 0 && r.app != null) {
10346 r.app.executingServices.remove(r);
10347 if (r.app.executingServices.size() == 0) {
10348 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10349 }
10350 if (inStopping) {
10351 mStoppingServices.remove(r);
10352 }
10353 updateOomAdjLocked(r.app);
10354 }
10355 }
10356
10357 void serviceTimeout(ProcessRecord proc) {
10358 synchronized(this) {
10359 if (proc.executingServices.size() == 0 || proc.thread == null) {
10360 return;
10361 }
10362 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10363 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10364 ServiceRecord timeout = null;
10365 long nextTime = 0;
10366 while (it.hasNext()) {
10367 ServiceRecord sr = it.next();
10368 if (sr.executingStart < maxTime) {
10369 timeout = sr;
10370 break;
10371 }
10372 if (sr.executingStart > nextTime) {
10373 nextTime = sr.executingStart;
10374 }
10375 }
10376 if (timeout != null && mLRUProcesses.contains(proc)) {
10377 Log.w(TAG, "Timeout executing service: " + timeout);
10378 appNotRespondingLocked(proc, null, "Executing service "
10379 + timeout.name);
10380 } else {
10381 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10382 msg.obj = proc;
10383 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10384 }
10385 }
10386 }
10387
10388 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010389 // BACKUP AND RESTORE
10390 // =========================================================
10391
10392 // Cause the target app to be launched if necessary and its backup agent
10393 // instantiated. The backup agent will invoke backupAgentCreated() on the
10394 // activity manager to announce its creation.
10395 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10396 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10397 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10398
10399 synchronized(this) {
10400 // !!! TODO: currently no check here that we're already bound
10401 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10402 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10403 synchronized (stats) {
10404 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10405 }
10406
10407 BackupRecord r = new BackupRecord(ss, app, backupMode);
10408 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10409 // startProcessLocked() returns existing proc's record if it's already running
10410 ProcessRecord proc = startProcessLocked(app.processName, app,
10411 false, 0, "backup", hostingName);
10412 if (proc == null) {
10413 Log.e(TAG, "Unable to start backup agent process " + r);
10414 return false;
10415 }
10416
10417 r.app = proc;
10418 mBackupTarget = r;
10419 mBackupAppName = app.packageName;
10420
Christopher Tate6fa95972009-06-05 18:43:55 -070010421 // Try not to kill the process during backup
10422 updateOomAdjLocked(proc);
10423
Christopher Tate181fafa2009-05-14 11:12:14 -070010424 // If the process is already attached, schedule the creation of the backup agent now.
10425 // If it is not yet live, this will be done when it attaches to the framework.
10426 if (proc.thread != null) {
10427 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10428 try {
10429 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10430 } catch (RemoteException e) {
10431 // !!! TODO: notify the backup manager that we crashed, or rely on
10432 // death notices, or...?
10433 }
10434 } else {
10435 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10436 }
10437 // Invariants: at this point, the target app process exists and the application
10438 // is either already running or in the process of coming up. mBackupTarget and
10439 // mBackupAppName describe the app, so that when it binds back to the AM we
10440 // know that it's scheduled for a backup-agent operation.
10441 }
10442
10443 return true;
10444 }
10445
10446 // A backup agent has just come up
10447 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10448 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10449 + " = " + agent);
10450
10451 synchronized(this) {
10452 if (!agentPackageName.equals(mBackupAppName)) {
10453 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10454 return;
10455 }
10456
Christopher Tate043dadc2009-06-02 16:11:00 -070010457 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010458 try {
10459 IBackupManager bm = IBackupManager.Stub.asInterface(
10460 ServiceManager.getService(Context.BACKUP_SERVICE));
10461 bm.agentConnected(agentPackageName, agent);
10462 } catch (RemoteException e) {
10463 // can't happen; the backup manager service is local
10464 } catch (Exception e) {
10465 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10466 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010467 } finally {
10468 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010469 }
10470 }
10471 }
10472
10473 // done with this agent
10474 public void unbindBackupAgent(ApplicationInfo appInfo) {
10475 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
10476
10477 synchronized(this) {
10478 if (!mBackupAppName.equals(appInfo.packageName)) {
10479 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10480 return;
10481 }
10482
Christopher Tate6fa95972009-06-05 18:43:55 -070010483 ProcessRecord proc = mBackupTarget.app;
10484 mBackupTarget = null;
10485 mBackupAppName = null;
10486
10487 // Not backing this app up any more; reset its OOM adjustment
10488 updateOomAdjLocked(proc);
10489
Christopher Tatec7b31e32009-06-10 15:49:30 -070010490 // If the app crashed during backup, 'thread' will be null here
10491 if (proc.thread != null) {
10492 try {
10493 proc.thread.scheduleDestroyBackupAgent(appInfo);
10494 } catch (Exception e) {
10495 Log.e(TAG, "Exception when unbinding backup agent:");
10496 e.printStackTrace();
10497 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010498 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010499 }
10500 }
10501 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010502 // BROADCASTS
10503 // =========================================================
10504
10505 private final List getStickies(String action, IntentFilter filter,
10506 List cur) {
10507 final ContentResolver resolver = mContext.getContentResolver();
10508 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10509 if (list == null) {
10510 return cur;
10511 }
10512 int N = list.size();
10513 for (int i=0; i<N; i++) {
10514 Intent intent = list.get(i);
10515 if (filter.match(resolver, intent, true, TAG) >= 0) {
10516 if (cur == null) {
10517 cur = new ArrayList<Intent>();
10518 }
10519 cur.add(intent);
10520 }
10521 }
10522 return cur;
10523 }
10524
10525 private final void scheduleBroadcastsLocked() {
10526 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10527 + mBroadcastsScheduled);
10528
10529 if (mBroadcastsScheduled) {
10530 return;
10531 }
10532 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10533 mBroadcastsScheduled = true;
10534 }
10535
10536 public Intent registerReceiver(IApplicationThread caller,
10537 IIntentReceiver receiver, IntentFilter filter, String permission) {
10538 synchronized(this) {
10539 ProcessRecord callerApp = null;
10540 if (caller != null) {
10541 callerApp = getRecordForAppLocked(caller);
10542 if (callerApp == null) {
10543 throw new SecurityException(
10544 "Unable to find app for caller " + caller
10545 + " (pid=" + Binder.getCallingPid()
10546 + ") when registering receiver " + receiver);
10547 }
10548 }
10549
10550 List allSticky = null;
10551
10552 // Look for any matching sticky broadcasts...
10553 Iterator actions = filter.actionsIterator();
10554 if (actions != null) {
10555 while (actions.hasNext()) {
10556 String action = (String)actions.next();
10557 allSticky = getStickies(action, filter, allSticky);
10558 }
10559 } else {
10560 allSticky = getStickies(null, filter, allSticky);
10561 }
10562
10563 // The first sticky in the list is returned directly back to
10564 // the client.
10565 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10566
10567 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10568 + ": " + sticky);
10569
10570 if (receiver == null) {
10571 return sticky;
10572 }
10573
10574 ReceiverList rl
10575 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10576 if (rl == null) {
10577 rl = new ReceiverList(this, callerApp,
10578 Binder.getCallingPid(),
10579 Binder.getCallingUid(), receiver);
10580 if (rl.app != null) {
10581 rl.app.receivers.add(rl);
10582 } else {
10583 try {
10584 receiver.asBinder().linkToDeath(rl, 0);
10585 } catch (RemoteException e) {
10586 return sticky;
10587 }
10588 rl.linkedToDeath = true;
10589 }
10590 mRegisteredReceivers.put(receiver.asBinder(), rl);
10591 }
10592 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10593 rl.add(bf);
10594 if (!bf.debugCheck()) {
10595 Log.w(TAG, "==> For Dynamic broadast");
10596 }
10597 mReceiverResolver.addFilter(bf);
10598
10599 // Enqueue broadcasts for all existing stickies that match
10600 // this filter.
10601 if (allSticky != null) {
10602 ArrayList receivers = new ArrayList();
10603 receivers.add(bf);
10604
10605 int N = allSticky.size();
10606 for (int i=0; i<N; i++) {
10607 Intent intent = (Intent)allSticky.get(i);
10608 BroadcastRecord r = new BroadcastRecord(intent, null,
10609 null, -1, -1, null, receivers, null, 0, null, null,
10610 false);
10611 if (mParallelBroadcasts.size() == 0) {
10612 scheduleBroadcastsLocked();
10613 }
10614 mParallelBroadcasts.add(r);
10615 }
10616 }
10617
10618 return sticky;
10619 }
10620 }
10621
10622 public void unregisterReceiver(IIntentReceiver receiver) {
10623 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10624
10625 boolean doNext = false;
10626
10627 synchronized(this) {
10628 ReceiverList rl
10629 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10630 if (rl != null) {
10631 if (rl.curBroadcast != null) {
10632 BroadcastRecord r = rl.curBroadcast;
10633 doNext = finishReceiverLocked(
10634 receiver.asBinder(), r.resultCode, r.resultData,
10635 r.resultExtras, r.resultAbort, true);
10636 }
10637
10638 if (rl.app != null) {
10639 rl.app.receivers.remove(rl);
10640 }
10641 removeReceiverLocked(rl);
10642 if (rl.linkedToDeath) {
10643 rl.linkedToDeath = false;
10644 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10645 }
10646 }
10647 }
10648
10649 if (!doNext) {
10650 return;
10651 }
10652
10653 final long origId = Binder.clearCallingIdentity();
10654 processNextBroadcast(false);
10655 trimApplications();
10656 Binder.restoreCallingIdentity(origId);
10657 }
10658
10659 void removeReceiverLocked(ReceiverList rl) {
10660 mRegisteredReceivers.remove(rl.receiver.asBinder());
10661 int N = rl.size();
10662 for (int i=0; i<N; i++) {
10663 mReceiverResolver.removeFilter(rl.get(i));
10664 }
10665 }
10666
10667 private final int broadcastIntentLocked(ProcessRecord callerApp,
10668 String callerPackage, Intent intent, String resolvedType,
10669 IIntentReceiver resultTo, int resultCode, String resultData,
10670 Bundle map, String requiredPermission,
10671 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10672 intent = new Intent(intent);
10673
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010674 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010675 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10676 + " ordered=" + ordered);
10677 if ((resultTo != null) && !ordered) {
10678 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10679 }
10680
10681 // Handle special intents: if this broadcast is from the package
10682 // manager about a package being removed, we need to remove all of
10683 // its activities from the history stack.
10684 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10685 intent.getAction());
10686 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10687 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10688 || uidRemoved) {
10689 if (checkComponentPermission(
10690 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10691 callingPid, callingUid, -1)
10692 == PackageManager.PERMISSION_GRANTED) {
10693 if (uidRemoved) {
10694 final Bundle intentExtras = intent.getExtras();
10695 final int uid = intentExtras != null
10696 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10697 if (uid >= 0) {
10698 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10699 synchronized (bs) {
10700 bs.removeUidStatsLocked(uid);
10701 }
10702 }
10703 } else {
10704 Uri data = intent.getData();
10705 String ssp;
10706 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10707 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10708 uninstallPackageLocked(ssp,
10709 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10710 }
10711 }
10712 }
10713 } else {
10714 String msg = "Permission Denial: " + intent.getAction()
10715 + " broadcast from " + callerPackage + " (pid=" + callingPid
10716 + ", uid=" + callingUid + ")"
10717 + " requires "
10718 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10719 Log.w(TAG, msg);
10720 throw new SecurityException(msg);
10721 }
10722 }
10723
10724 /*
10725 * If this is the time zone changed action, queue up a message that will reset the timezone
10726 * of all currently running processes. This message will get queued up before the broadcast
10727 * happens.
10728 */
10729 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10730 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10731 }
10732
10733 // Add to the sticky list if requested.
10734 if (sticky) {
10735 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10736 callingPid, callingUid)
10737 != PackageManager.PERMISSION_GRANTED) {
10738 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10739 + callingPid + ", uid=" + callingUid
10740 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10741 Log.w(TAG, msg);
10742 throw new SecurityException(msg);
10743 }
10744 if (requiredPermission != null) {
10745 Log.w(TAG, "Can't broadcast sticky intent " + intent
10746 + " and enforce permission " + requiredPermission);
10747 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10748 }
10749 if (intent.getComponent() != null) {
10750 throw new SecurityException(
10751 "Sticky broadcasts can't target a specific component");
10752 }
10753 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10754 if (list == null) {
10755 list = new ArrayList<Intent>();
10756 mStickyBroadcasts.put(intent.getAction(), list);
10757 }
10758 int N = list.size();
10759 int i;
10760 for (i=0; i<N; i++) {
10761 if (intent.filterEquals(list.get(i))) {
10762 // This sticky already exists, replace it.
10763 list.set(i, new Intent(intent));
10764 break;
10765 }
10766 }
10767 if (i >= N) {
10768 list.add(new Intent(intent));
10769 }
10770 }
10771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010772 // Figure out who all will receive this broadcast.
10773 List receivers = null;
10774 List<BroadcastFilter> registeredReceivers = null;
10775 try {
10776 if (intent.getComponent() != null) {
10777 // Broadcast is going to one specific receiver class...
10778 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010779 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010780 if (ai != null) {
10781 receivers = new ArrayList();
10782 ResolveInfo ri = new ResolveInfo();
10783 ri.activityInfo = ai;
10784 receivers.add(ri);
10785 }
10786 } else {
10787 // Need to resolve the intent to interested receivers...
10788 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10789 == 0) {
10790 receivers =
10791 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010792 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010793 }
Mihai Preda074edef2009-05-18 17:13:31 +020010794 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010795 }
10796 } catch (RemoteException ex) {
10797 // pm is in same process, this will never happen.
10798 }
10799
10800 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10801 if (!ordered && NR > 0) {
10802 // If we are not serializing this broadcast, then send the
10803 // registered receivers separately so they don't wait for the
10804 // components to be launched.
10805 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10806 callerPackage, callingPid, callingUid, requiredPermission,
10807 registeredReceivers, resultTo, resultCode, resultData, map,
10808 ordered);
10809 if (DEBUG_BROADCAST) Log.v(
10810 TAG, "Enqueueing parallel broadcast " + r
10811 + ": prev had " + mParallelBroadcasts.size());
10812 mParallelBroadcasts.add(r);
10813 scheduleBroadcastsLocked();
10814 registeredReceivers = null;
10815 NR = 0;
10816 }
10817
10818 // Merge into one list.
10819 int ir = 0;
10820 if (receivers != null) {
10821 // A special case for PACKAGE_ADDED: do not allow the package
10822 // being added to see this broadcast. This prevents them from
10823 // using this as a back door to get run as soon as they are
10824 // installed. Maybe in the future we want to have a special install
10825 // broadcast or such for apps, but we'd like to deliberately make
10826 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010827 boolean skip = false;
10828 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010829 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010830 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10831 skip = true;
10832 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10833 skip = true;
10834 }
10835 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010836 ? intent.getData().getSchemeSpecificPart()
10837 : null;
10838 if (skipPackage != null && receivers != null) {
10839 int NT = receivers.size();
10840 for (int it=0; it<NT; it++) {
10841 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10842 if (curt.activityInfo.packageName.equals(skipPackage)) {
10843 receivers.remove(it);
10844 it--;
10845 NT--;
10846 }
10847 }
10848 }
10849
10850 int NT = receivers != null ? receivers.size() : 0;
10851 int it = 0;
10852 ResolveInfo curt = null;
10853 BroadcastFilter curr = null;
10854 while (it < NT && ir < NR) {
10855 if (curt == null) {
10856 curt = (ResolveInfo)receivers.get(it);
10857 }
10858 if (curr == null) {
10859 curr = registeredReceivers.get(ir);
10860 }
10861 if (curr.getPriority() >= curt.priority) {
10862 // Insert this broadcast record into the final list.
10863 receivers.add(it, curr);
10864 ir++;
10865 curr = null;
10866 it++;
10867 NT++;
10868 } else {
10869 // Skip to the next ResolveInfo in the final list.
10870 it++;
10871 curt = null;
10872 }
10873 }
10874 }
10875 while (ir < NR) {
10876 if (receivers == null) {
10877 receivers = new ArrayList();
10878 }
10879 receivers.add(registeredReceivers.get(ir));
10880 ir++;
10881 }
10882
10883 if ((receivers != null && receivers.size() > 0)
10884 || resultTo != null) {
10885 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10886 callerPackage, callingPid, callingUid, requiredPermission,
10887 receivers, resultTo, resultCode, resultData, map, ordered);
10888 if (DEBUG_BROADCAST) Log.v(
10889 TAG, "Enqueueing ordered broadcast " + r
10890 + ": prev had " + mOrderedBroadcasts.size());
10891 if (DEBUG_BROADCAST) {
10892 int seq = r.intent.getIntExtra("seq", -1);
10893 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10894 }
10895 mOrderedBroadcasts.add(r);
10896 scheduleBroadcastsLocked();
10897 }
10898
10899 return BROADCAST_SUCCESS;
10900 }
10901
10902 public final int broadcastIntent(IApplicationThread caller,
10903 Intent intent, String resolvedType, IIntentReceiver resultTo,
10904 int resultCode, String resultData, Bundle map,
10905 String requiredPermission, boolean serialized, boolean sticky) {
10906 // Refuse possible leaked file descriptors
10907 if (intent != null && intent.hasFileDescriptors() == true) {
10908 throw new IllegalArgumentException("File descriptors passed in Intent");
10909 }
10910
10911 synchronized(this) {
10912 if (!mSystemReady) {
10913 // if the caller really truly claims to know what they're doing, go
10914 // ahead and allow the broadcast without launching any receivers
10915 int flags = intent.getFlags();
10916 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10917 intent = new Intent(intent);
10918 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10919 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10920 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10921 + " before boot completion");
10922 throw new IllegalStateException("Cannot broadcast before boot completed");
10923 }
10924 }
10925
10926 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10927 final int callingPid = Binder.getCallingPid();
10928 final int callingUid = Binder.getCallingUid();
10929 final long origId = Binder.clearCallingIdentity();
10930 int res = broadcastIntentLocked(callerApp,
10931 callerApp != null ? callerApp.info.packageName : null,
10932 intent, resolvedType, resultTo,
10933 resultCode, resultData, map, requiredPermission, serialized,
10934 sticky, callingPid, callingUid);
10935 Binder.restoreCallingIdentity(origId);
10936 return res;
10937 }
10938 }
10939
10940 int broadcastIntentInPackage(String packageName, int uid,
10941 Intent intent, String resolvedType, IIntentReceiver resultTo,
10942 int resultCode, String resultData, Bundle map,
10943 String requiredPermission, boolean serialized, boolean sticky) {
10944 synchronized(this) {
10945 final long origId = Binder.clearCallingIdentity();
10946 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10947 resultTo, resultCode, resultData, map, requiredPermission,
10948 serialized, sticky, -1, uid);
10949 Binder.restoreCallingIdentity(origId);
10950 return res;
10951 }
10952 }
10953
10954 public final void unbroadcastIntent(IApplicationThread caller,
10955 Intent intent) {
10956 // Refuse possible leaked file descriptors
10957 if (intent != null && intent.hasFileDescriptors() == true) {
10958 throw new IllegalArgumentException("File descriptors passed in Intent");
10959 }
10960
10961 synchronized(this) {
10962 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10963 != PackageManager.PERMISSION_GRANTED) {
10964 String msg = "Permission Denial: unbroadcastIntent() from pid="
10965 + Binder.getCallingPid()
10966 + ", uid=" + Binder.getCallingUid()
10967 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10968 Log.w(TAG, msg);
10969 throw new SecurityException(msg);
10970 }
10971 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10972 if (list != null) {
10973 int N = list.size();
10974 int i;
10975 for (i=0; i<N; i++) {
10976 if (intent.filterEquals(list.get(i))) {
10977 list.remove(i);
10978 break;
10979 }
10980 }
10981 }
10982 }
10983 }
10984
10985 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10986 String resultData, Bundle resultExtras, boolean resultAbort,
10987 boolean explicit) {
10988 if (mOrderedBroadcasts.size() == 0) {
10989 if (explicit) {
10990 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10991 }
10992 return false;
10993 }
10994 BroadcastRecord r = mOrderedBroadcasts.get(0);
10995 if (r.receiver == null) {
10996 if (explicit) {
10997 Log.w(TAG, "finishReceiver called but none active");
10998 }
10999 return false;
11000 }
11001 if (r.receiver != receiver) {
11002 Log.w(TAG, "finishReceiver called but active receiver is different");
11003 return false;
11004 }
11005 int state = r.state;
11006 r.state = r.IDLE;
11007 if (state == r.IDLE) {
11008 if (explicit) {
11009 Log.w(TAG, "finishReceiver called but state is IDLE");
11010 }
11011 }
11012 r.receiver = null;
11013 r.intent.setComponent(null);
11014 if (r.curApp != null) {
11015 r.curApp.curReceiver = null;
11016 }
11017 if (r.curFilter != null) {
11018 r.curFilter.receiverList.curBroadcast = null;
11019 }
11020 r.curFilter = null;
11021 r.curApp = null;
11022 r.curComponent = null;
11023 r.curReceiver = null;
11024 mPendingBroadcast = null;
11025
11026 r.resultCode = resultCode;
11027 r.resultData = resultData;
11028 r.resultExtras = resultExtras;
11029 r.resultAbort = resultAbort;
11030
11031 // We will process the next receiver right now if this is finishing
11032 // an app receiver (which is always asynchronous) or after we have
11033 // come back from calling a receiver.
11034 return state == BroadcastRecord.APP_RECEIVE
11035 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11036 }
11037
11038 public void finishReceiver(IBinder who, int resultCode, String resultData,
11039 Bundle resultExtras, boolean resultAbort) {
11040 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11041
11042 // Refuse possible leaked file descriptors
11043 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11044 throw new IllegalArgumentException("File descriptors passed in Bundle");
11045 }
11046
11047 boolean doNext;
11048
11049 final long origId = Binder.clearCallingIdentity();
11050
11051 synchronized(this) {
11052 doNext = finishReceiverLocked(
11053 who, resultCode, resultData, resultExtras, resultAbort, true);
11054 }
11055
11056 if (doNext) {
11057 processNextBroadcast(false);
11058 }
11059 trimApplications();
11060
11061 Binder.restoreCallingIdentity(origId);
11062 }
11063
11064 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11065 if (r.nextReceiver > 0) {
11066 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11067 if (curReceiver instanceof BroadcastFilter) {
11068 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11069 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11070 System.identityHashCode(r),
11071 r.intent.getAction(),
11072 r.nextReceiver - 1,
11073 System.identityHashCode(bf));
11074 } else {
11075 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11076 System.identityHashCode(r),
11077 r.intent.getAction(),
11078 r.nextReceiver - 1,
11079 ((ResolveInfo)curReceiver).toString());
11080 }
11081 } else {
11082 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11083 + r);
11084 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11085 System.identityHashCode(r),
11086 r.intent.getAction(),
11087 r.nextReceiver,
11088 "NONE");
11089 }
11090 }
11091
11092 private final void broadcastTimeout() {
11093 synchronized (this) {
11094 if (mOrderedBroadcasts.size() == 0) {
11095 return;
11096 }
11097 long now = SystemClock.uptimeMillis();
11098 BroadcastRecord r = mOrderedBroadcasts.get(0);
11099 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11100 if (DEBUG_BROADCAST) Log.v(TAG,
11101 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11102 + (r.startTime + BROADCAST_TIMEOUT));
11103 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11104 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11105 return;
11106 }
11107
11108 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11109 r.startTime = now;
11110 r.anrCount++;
11111
11112 // Current receiver has passed its expiration date.
11113 if (r.nextReceiver <= 0) {
11114 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11115 return;
11116 }
11117
11118 ProcessRecord app = null;
11119
11120 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11121 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11122 logBroadcastReceiverDiscard(r);
11123 if (curReceiver instanceof BroadcastFilter) {
11124 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11125 if (bf.receiverList.pid != 0
11126 && bf.receiverList.pid != MY_PID) {
11127 synchronized (this.mPidsSelfLocked) {
11128 app = this.mPidsSelfLocked.get(
11129 bf.receiverList.pid);
11130 }
11131 }
11132 } else {
11133 app = r.curApp;
11134 }
11135
11136 if (app != null) {
11137 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11138 }
11139
11140 if (mPendingBroadcast == r) {
11141 mPendingBroadcast = null;
11142 }
11143
11144 // Move on to the next receiver.
11145 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11146 r.resultExtras, r.resultAbort, true);
11147 scheduleBroadcastsLocked();
11148 }
11149 }
11150
11151 private final void processCurBroadcastLocked(BroadcastRecord r,
11152 ProcessRecord app) throws RemoteException {
11153 if (app.thread == null) {
11154 throw new RemoteException();
11155 }
11156 r.receiver = app.thread.asBinder();
11157 r.curApp = app;
11158 app.curReceiver = r;
11159 updateLRUListLocked(app, true);
11160
11161 // Tell the application to launch this receiver.
11162 r.intent.setComponent(r.curComponent);
11163
11164 boolean started = false;
11165 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011166 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011167 "Delivering to component " + r.curComponent
11168 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011169 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011170 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11171 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11172 started = true;
11173 } finally {
11174 if (!started) {
11175 r.receiver = null;
11176 r.curApp = null;
11177 app.curReceiver = null;
11178 }
11179 }
11180
11181 }
11182
11183 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11184 Intent intent, int resultCode, String data,
11185 Bundle extras, boolean ordered) throws RemoteException {
11186 if (app != null && app.thread != null) {
11187 // If we have an app thread, do the call through that so it is
11188 // correctly ordered with other one-way calls.
11189 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11190 data, extras, ordered);
11191 } else {
11192 receiver.performReceive(intent, resultCode, data, extras, ordered);
11193 }
11194 }
11195
11196 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11197 BroadcastFilter filter, boolean ordered) {
11198 boolean skip = false;
11199 if (filter.requiredPermission != null) {
11200 int perm = checkComponentPermission(filter.requiredPermission,
11201 r.callingPid, r.callingUid, -1);
11202 if (perm != PackageManager.PERMISSION_GRANTED) {
11203 Log.w(TAG, "Permission Denial: broadcasting "
11204 + r.intent.toString()
11205 + " from " + r.callerPackage + " (pid="
11206 + r.callingPid + ", uid=" + r.callingUid + ")"
11207 + " requires " + filter.requiredPermission
11208 + " due to registered receiver " + filter);
11209 skip = true;
11210 }
11211 }
11212 if (r.requiredPermission != null) {
11213 int perm = checkComponentPermission(r.requiredPermission,
11214 filter.receiverList.pid, filter.receiverList.uid, -1);
11215 if (perm != PackageManager.PERMISSION_GRANTED) {
11216 Log.w(TAG, "Permission Denial: receiving "
11217 + r.intent.toString()
11218 + " to " + filter.receiverList.app
11219 + " (pid=" + filter.receiverList.pid
11220 + ", uid=" + filter.receiverList.uid + ")"
11221 + " requires " + r.requiredPermission
11222 + " due to sender " + r.callerPackage
11223 + " (uid " + r.callingUid + ")");
11224 skip = true;
11225 }
11226 }
11227
11228 if (!skip) {
11229 // If this is not being sent as an ordered broadcast, then we
11230 // don't want to touch the fields that keep track of the current
11231 // state of ordered broadcasts.
11232 if (ordered) {
11233 r.receiver = filter.receiverList.receiver.asBinder();
11234 r.curFilter = filter;
11235 filter.receiverList.curBroadcast = r;
11236 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011237 if (filter.receiverList.app != null) {
11238 // Bump hosting application to no longer be in background
11239 // scheduling class. Note that we can't do that if there
11240 // isn't an app... but we can only be in that case for
11241 // things that directly call the IActivityManager API, which
11242 // are already core system stuff so don't matter for this.
11243 r.curApp = filter.receiverList.app;
11244 filter.receiverList.app.curReceiver = r;
11245 updateOomAdjLocked();
11246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011247 }
11248 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011249 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011250 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011251 Log.i(TAG, "Delivering to " + filter.receiverList.app
11252 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011253 }
11254 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11255 new Intent(r.intent), r.resultCode,
11256 r.resultData, r.resultExtras, r.ordered);
11257 if (ordered) {
11258 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11259 }
11260 } catch (RemoteException e) {
11261 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11262 if (ordered) {
11263 r.receiver = null;
11264 r.curFilter = null;
11265 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011266 if (filter.receiverList.app != null) {
11267 filter.receiverList.app.curReceiver = null;
11268 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011269 }
11270 }
11271 }
11272 }
11273
11274 private final void processNextBroadcast(boolean fromMsg) {
11275 synchronized(this) {
11276 BroadcastRecord r;
11277
11278 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11279 + mParallelBroadcasts.size() + " broadcasts, "
11280 + mOrderedBroadcasts.size() + " serialized broadcasts");
11281
11282 updateCpuStats();
11283
11284 if (fromMsg) {
11285 mBroadcastsScheduled = false;
11286 }
11287
11288 // First, deliver any non-serialized broadcasts right away.
11289 while (mParallelBroadcasts.size() > 0) {
11290 r = mParallelBroadcasts.remove(0);
11291 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011292 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11293 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011294 for (int i=0; i<N; i++) {
11295 Object target = r.receivers.get(i);
11296 if (DEBUG_BROADCAST) Log.v(TAG,
11297 "Delivering non-serialized to registered "
11298 + target + ": " + r);
11299 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11300 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011301 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11302 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011303 }
11304
11305 // Now take care of the next serialized one...
11306
11307 // If we are waiting for a process to come up to handle the next
11308 // broadcast, then do nothing at this point. Just in case, we
11309 // check that the process we're waiting for still exists.
11310 if (mPendingBroadcast != null) {
11311 Log.i(TAG, "processNextBroadcast: waiting for "
11312 + mPendingBroadcast.curApp);
11313
11314 boolean isDead;
11315 synchronized (mPidsSelfLocked) {
11316 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11317 }
11318 if (!isDead) {
11319 // It's still alive, so keep waiting
11320 return;
11321 } else {
11322 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11323 + " died before responding to broadcast");
11324 mPendingBroadcast = null;
11325 }
11326 }
11327
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011328 boolean looped = false;
11329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011330 do {
11331 if (mOrderedBroadcasts.size() == 0) {
11332 // No more broadcasts pending, so all done!
11333 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011334 if (looped) {
11335 // If we had finished the last ordered broadcast, then
11336 // make sure all processes have correct oom and sched
11337 // adjustments.
11338 updateOomAdjLocked();
11339 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011340 return;
11341 }
11342 r = mOrderedBroadcasts.get(0);
11343 boolean forceReceive = false;
11344
11345 // Ensure that even if something goes awry with the timeout
11346 // detection, we catch "hung" broadcasts here, discard them,
11347 // and continue to make progress.
11348 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11349 long now = SystemClock.uptimeMillis();
11350 if (r.dispatchTime > 0) {
11351 if ((numReceivers > 0) &&
11352 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11353 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11354 + " now=" + now
11355 + " dispatchTime=" + r.dispatchTime
11356 + " startTime=" + r.startTime
11357 + " intent=" + r.intent
11358 + " numReceivers=" + numReceivers
11359 + " nextReceiver=" + r.nextReceiver
11360 + " state=" + r.state);
11361 broadcastTimeout(); // forcibly finish this broadcast
11362 forceReceive = true;
11363 r.state = BroadcastRecord.IDLE;
11364 }
11365 }
11366
11367 if (r.state != BroadcastRecord.IDLE) {
11368 if (DEBUG_BROADCAST) Log.d(TAG,
11369 "processNextBroadcast() called when not idle (state="
11370 + r.state + ")");
11371 return;
11372 }
11373
11374 if (r.receivers == null || r.nextReceiver >= numReceivers
11375 || r.resultAbort || forceReceive) {
11376 // No more receivers for this broadcast! Send the final
11377 // result if requested...
11378 if (r.resultTo != null) {
11379 try {
11380 if (DEBUG_BROADCAST) {
11381 int seq = r.intent.getIntExtra("seq", -1);
11382 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11383 + " seq=" + seq + " app=" + r.callerApp);
11384 }
11385 performReceive(r.callerApp, r.resultTo,
11386 new Intent(r.intent), r.resultCode,
11387 r.resultData, r.resultExtras, false);
11388 } catch (RemoteException e) {
11389 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11390 }
11391 }
11392
11393 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11394 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11395
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011396 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11397 + r);
11398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011399 // ... and on to the next...
11400 mOrderedBroadcasts.remove(0);
11401 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011402 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011403 continue;
11404 }
11405 } while (r == null);
11406
11407 // Get the next receiver...
11408 int recIdx = r.nextReceiver++;
11409
11410 // Keep track of when this receiver started, and make sure there
11411 // is a timeout message pending to kill it if need be.
11412 r.startTime = SystemClock.uptimeMillis();
11413 if (recIdx == 0) {
11414 r.dispatchTime = r.startTime;
11415
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011416 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11417 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011418 if (DEBUG_BROADCAST) Log.v(TAG,
11419 "Submitting BROADCAST_TIMEOUT_MSG for "
11420 + (r.startTime + BROADCAST_TIMEOUT));
11421 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11422 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11423 }
11424
11425 Object nextReceiver = r.receivers.get(recIdx);
11426 if (nextReceiver instanceof BroadcastFilter) {
11427 // Simple case: this is a registered receiver who gets
11428 // a direct call.
11429 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11430 if (DEBUG_BROADCAST) Log.v(TAG,
11431 "Delivering serialized to registered "
11432 + filter + ": " + r);
11433 deliverToRegisteredReceiver(r, filter, r.ordered);
11434 if (r.receiver == null || !r.ordered) {
11435 // The receiver has already finished, so schedule to
11436 // process the next one.
11437 r.state = BroadcastRecord.IDLE;
11438 scheduleBroadcastsLocked();
11439 }
11440 return;
11441 }
11442
11443 // Hard case: need to instantiate the receiver, possibly
11444 // starting its application process to host it.
11445
11446 ResolveInfo info =
11447 (ResolveInfo)nextReceiver;
11448
11449 boolean skip = false;
11450 int perm = checkComponentPermission(info.activityInfo.permission,
11451 r.callingPid, r.callingUid,
11452 info.activityInfo.exported
11453 ? -1 : info.activityInfo.applicationInfo.uid);
11454 if (perm != PackageManager.PERMISSION_GRANTED) {
11455 Log.w(TAG, "Permission Denial: broadcasting "
11456 + r.intent.toString()
11457 + " from " + r.callerPackage + " (pid=" + r.callingPid
11458 + ", uid=" + r.callingUid + ")"
11459 + " requires " + info.activityInfo.permission
11460 + " due to receiver " + info.activityInfo.packageName
11461 + "/" + info.activityInfo.name);
11462 skip = true;
11463 }
11464 if (r.callingUid != Process.SYSTEM_UID &&
11465 r.requiredPermission != null) {
11466 try {
11467 perm = ActivityThread.getPackageManager().
11468 checkPermission(r.requiredPermission,
11469 info.activityInfo.applicationInfo.packageName);
11470 } catch (RemoteException e) {
11471 perm = PackageManager.PERMISSION_DENIED;
11472 }
11473 if (perm != PackageManager.PERMISSION_GRANTED) {
11474 Log.w(TAG, "Permission Denial: receiving "
11475 + r.intent + " to "
11476 + info.activityInfo.applicationInfo.packageName
11477 + " requires " + r.requiredPermission
11478 + " due to sender " + r.callerPackage
11479 + " (uid " + r.callingUid + ")");
11480 skip = true;
11481 }
11482 }
11483 if (r.curApp != null && r.curApp.crashing) {
11484 // If the target process is crashing, just skip it.
11485 skip = true;
11486 }
11487
11488 if (skip) {
11489 r.receiver = null;
11490 r.curFilter = null;
11491 r.state = BroadcastRecord.IDLE;
11492 scheduleBroadcastsLocked();
11493 return;
11494 }
11495
11496 r.state = BroadcastRecord.APP_RECEIVE;
11497 String targetProcess = info.activityInfo.processName;
11498 r.curComponent = new ComponentName(
11499 info.activityInfo.applicationInfo.packageName,
11500 info.activityInfo.name);
11501 r.curReceiver = info.activityInfo;
11502
11503 // Is this receiver's application already running?
11504 ProcessRecord app = getProcessRecordLocked(targetProcess,
11505 info.activityInfo.applicationInfo.uid);
11506 if (app != null && app.thread != null) {
11507 try {
11508 processCurBroadcastLocked(r, app);
11509 return;
11510 } catch (RemoteException e) {
11511 Log.w(TAG, "Exception when sending broadcast to "
11512 + r.curComponent, e);
11513 }
11514
11515 // If a dead object exception was thrown -- fall through to
11516 // restart the application.
11517 }
11518
11519 // Not running -- get it started, and enqueue this history record
11520 // to be executed when the app comes up.
11521 if ((r.curApp=startProcessLocked(targetProcess,
11522 info.activityInfo.applicationInfo, true,
11523 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11524 "broadcast", r.curComponent)) == null) {
11525 // Ah, this recipient is unavailable. Finish it if necessary,
11526 // and mark the broadcast record as ready for the next.
11527 Log.w(TAG, "Unable to launch app "
11528 + info.activityInfo.applicationInfo.packageName + "/"
11529 + info.activityInfo.applicationInfo.uid + " for broadcast "
11530 + r.intent + ": process is bad");
11531 logBroadcastReceiverDiscard(r);
11532 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11533 r.resultExtras, r.resultAbort, true);
11534 scheduleBroadcastsLocked();
11535 r.state = BroadcastRecord.IDLE;
11536 return;
11537 }
11538
11539 mPendingBroadcast = r;
11540 }
11541 }
11542
11543 // =========================================================
11544 // INSTRUMENTATION
11545 // =========================================================
11546
11547 public boolean startInstrumentation(ComponentName className,
11548 String profileFile, int flags, Bundle arguments,
11549 IInstrumentationWatcher watcher) {
11550 // Refuse possible leaked file descriptors
11551 if (arguments != null && arguments.hasFileDescriptors()) {
11552 throw new IllegalArgumentException("File descriptors passed in Bundle");
11553 }
11554
11555 synchronized(this) {
11556 InstrumentationInfo ii = null;
11557 ApplicationInfo ai = null;
11558 try {
11559 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011560 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011561 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011562 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011563 } catch (PackageManager.NameNotFoundException e) {
11564 }
11565 if (ii == null) {
11566 reportStartInstrumentationFailure(watcher, className,
11567 "Unable to find instrumentation info for: " + className);
11568 return false;
11569 }
11570 if (ai == null) {
11571 reportStartInstrumentationFailure(watcher, className,
11572 "Unable to find instrumentation target package: " + ii.targetPackage);
11573 return false;
11574 }
11575
11576 int match = mContext.getPackageManager().checkSignatures(
11577 ii.targetPackage, ii.packageName);
11578 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11579 String msg = "Permission Denial: starting instrumentation "
11580 + className + " from pid="
11581 + Binder.getCallingPid()
11582 + ", uid=" + Binder.getCallingPid()
11583 + " not allowed because package " + ii.packageName
11584 + " does not have a signature matching the target "
11585 + ii.targetPackage;
11586 reportStartInstrumentationFailure(watcher, className, msg);
11587 throw new SecurityException(msg);
11588 }
11589
11590 final long origId = Binder.clearCallingIdentity();
11591 uninstallPackageLocked(ii.targetPackage, -1, true);
11592 ProcessRecord app = addAppLocked(ai);
11593 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011594 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011595 app.instrumentationProfileFile = profileFile;
11596 app.instrumentationArguments = arguments;
11597 app.instrumentationWatcher = watcher;
11598 app.instrumentationResultClass = className;
11599 Binder.restoreCallingIdentity(origId);
11600 }
11601
11602 return true;
11603 }
11604
11605 /**
11606 * Report errors that occur while attempting to start Instrumentation. Always writes the
11607 * error to the logs, but if somebody is watching, send the report there too. This enables
11608 * the "am" command to report errors with more information.
11609 *
11610 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11611 * @param cn The component name of the instrumentation.
11612 * @param report The error report.
11613 */
11614 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11615 ComponentName cn, String report) {
11616 Log.w(TAG, report);
11617 try {
11618 if (watcher != null) {
11619 Bundle results = new Bundle();
11620 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11621 results.putString("Error", report);
11622 watcher.instrumentationStatus(cn, -1, results);
11623 }
11624 } catch (RemoteException e) {
11625 Log.w(TAG, e);
11626 }
11627 }
11628
11629 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11630 if (app.instrumentationWatcher != null) {
11631 try {
11632 // NOTE: IInstrumentationWatcher *must* be oneway here
11633 app.instrumentationWatcher.instrumentationFinished(
11634 app.instrumentationClass,
11635 resultCode,
11636 results);
11637 } catch (RemoteException e) {
11638 }
11639 }
11640 app.instrumentationWatcher = null;
11641 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011642 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011643 app.instrumentationProfileFile = null;
11644 app.instrumentationArguments = null;
11645
11646 uninstallPackageLocked(app.processName, -1, false);
11647 }
11648
11649 public void finishInstrumentation(IApplicationThread target,
11650 int resultCode, Bundle results) {
11651 // Refuse possible leaked file descriptors
11652 if (results != null && results.hasFileDescriptors()) {
11653 throw new IllegalArgumentException("File descriptors passed in Intent");
11654 }
11655
11656 synchronized(this) {
11657 ProcessRecord app = getRecordForAppLocked(target);
11658 if (app == null) {
11659 Log.w(TAG, "finishInstrumentation: no app for " + target);
11660 return;
11661 }
11662 final long origId = Binder.clearCallingIdentity();
11663 finishInstrumentationLocked(app, resultCode, results);
11664 Binder.restoreCallingIdentity(origId);
11665 }
11666 }
11667
11668 // =========================================================
11669 // CONFIGURATION
11670 // =========================================================
11671
11672 public ConfigurationInfo getDeviceConfigurationInfo() {
11673 ConfigurationInfo config = new ConfigurationInfo();
11674 synchronized (this) {
11675 config.reqTouchScreen = mConfiguration.touchscreen;
11676 config.reqKeyboardType = mConfiguration.keyboard;
11677 config.reqNavigation = mConfiguration.navigation;
11678 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11679 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11680 }
11681 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11682 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11683 }
11684 }
11685 return config;
11686 }
11687
11688 public Configuration getConfiguration() {
11689 Configuration ci;
11690 synchronized(this) {
11691 ci = new Configuration(mConfiguration);
11692 }
11693 return ci;
11694 }
11695
11696 public void updateConfiguration(Configuration values) {
11697 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11698 "updateConfiguration()");
11699
11700 synchronized(this) {
11701 if (values == null && mWindowManager != null) {
11702 // sentinel: fetch the current configuration from the window manager
11703 values = mWindowManager.computeNewConfiguration();
11704 }
11705
11706 final long origId = Binder.clearCallingIdentity();
11707 updateConfigurationLocked(values, null);
11708 Binder.restoreCallingIdentity(origId);
11709 }
11710 }
11711
11712 /**
11713 * Do either or both things: (1) change the current configuration, and (2)
11714 * make sure the given activity is running with the (now) current
11715 * configuration. Returns true if the activity has been left running, or
11716 * false if <var>starting</var> is being destroyed to match the new
11717 * configuration.
11718 */
11719 public boolean updateConfigurationLocked(Configuration values,
11720 HistoryRecord starting) {
11721 int changes = 0;
11722
11723 boolean kept = true;
11724
11725 if (values != null) {
11726 Configuration newConfig = new Configuration(mConfiguration);
11727 changes = newConfig.updateFrom(values);
11728 if (changes != 0) {
11729 if (DEBUG_SWITCH) {
11730 Log.i(TAG, "Updating configuration to: " + values);
11731 }
11732
11733 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11734
11735 if (values.locale != null) {
11736 saveLocaleLocked(values.locale,
11737 !values.locale.equals(mConfiguration.locale),
11738 values.userSetLocale);
11739 }
11740
11741 mConfiguration = newConfig;
11742
11743 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11744 msg.obj = new Configuration(mConfiguration);
11745 mHandler.sendMessage(msg);
11746
11747 final int N = mLRUProcesses.size();
11748 for (int i=0; i<N; i++) {
11749 ProcessRecord app = mLRUProcesses.get(i);
11750 try {
11751 if (app.thread != null) {
11752 app.thread.scheduleConfigurationChanged(mConfiguration);
11753 }
11754 } catch (Exception e) {
11755 }
11756 }
11757 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11758 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11759 null, false, false, MY_PID, Process.SYSTEM_UID);
11760 }
11761 }
11762
11763 if (changes != 0 && starting == null) {
11764 // If the configuration changed, and the caller is not already
11765 // in the process of starting an activity, then find the top
11766 // activity to check if its configuration needs to change.
11767 starting = topRunningActivityLocked(null);
11768 }
11769
11770 if (starting != null) {
11771 kept = ensureActivityConfigurationLocked(starting, changes);
11772 if (kept) {
11773 // If this didn't result in the starting activity being
11774 // destroyed, then we need to make sure at this point that all
11775 // other activities are made visible.
11776 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11777 + ", ensuring others are correct.");
11778 ensureActivitiesVisibleLocked(starting, changes);
11779 }
11780 }
11781
11782 return kept;
11783 }
11784
11785 private final boolean relaunchActivityLocked(HistoryRecord r,
11786 int changes, boolean andResume) {
11787 List<ResultInfo> results = null;
11788 List<Intent> newIntents = null;
11789 if (andResume) {
11790 results = r.results;
11791 newIntents = r.newIntents;
11792 }
11793 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11794 + " with results=" + results + " newIntents=" + newIntents
11795 + " andResume=" + andResume);
11796 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11797 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11798 r.task.taskId, r.shortComponentName);
11799
11800 r.startFreezingScreenLocked(r.app, 0);
11801
11802 try {
11803 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11804 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11805 changes, !andResume);
11806 // Note: don't need to call pauseIfSleepingLocked() here, because
11807 // the caller will only pass in 'andResume' if this activity is
11808 // currently resumed, which implies we aren't sleeping.
11809 } catch (RemoteException e) {
11810 return false;
11811 }
11812
11813 if (andResume) {
11814 r.results = null;
11815 r.newIntents = null;
11816 }
11817
11818 return true;
11819 }
11820
11821 /**
11822 * Make sure the given activity matches the current configuration. Returns
11823 * false if the activity had to be destroyed. Returns true if the
11824 * configuration is the same, or the activity will remain running as-is
11825 * for whatever reason. Ensures the HistoryRecord is updated with the
11826 * correct configuration and all other bookkeeping is handled.
11827 */
11828 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11829 int globalChanges) {
11830 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11831
11832 // Short circuit: if the two configurations are the exact same
11833 // object (the common case), then there is nothing to do.
11834 Configuration newConfig = mConfiguration;
11835 if (r.configuration == newConfig) {
11836 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11837 return true;
11838 }
11839
11840 // We don't worry about activities that are finishing.
11841 if (r.finishing) {
11842 if (DEBUG_SWITCH) Log.i(TAG,
11843 "Configuration doesn't matter in finishing " + r);
11844 r.stopFreezingScreenLocked(false);
11845 return true;
11846 }
11847
11848 // Okay we now are going to make this activity have the new config.
11849 // But then we need to figure out how it needs to deal with that.
11850 Configuration oldConfig = r.configuration;
11851 r.configuration = newConfig;
11852
11853 // If the activity isn't currently running, just leave the new
11854 // configuration and it will pick that up next time it starts.
11855 if (r.app == null || r.app.thread == null) {
11856 if (DEBUG_SWITCH) Log.i(TAG,
11857 "Configuration doesn't matter not running " + r);
11858 r.stopFreezingScreenLocked(false);
11859 return true;
11860 }
11861
11862 // If the activity isn't persistent, there is a chance we will
11863 // need to restart it.
11864 if (!r.persistent) {
11865
11866 // Figure out what has changed between the two configurations.
11867 int changes = oldConfig.diff(newConfig);
11868 if (DEBUG_SWITCH) {
11869 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11870 + Integer.toHexString(changes) + ", handles=0x"
11871 + Integer.toHexString(r.info.configChanges));
11872 }
11873 if ((changes&(~r.info.configChanges)) != 0) {
11874 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11875 r.configChangeFlags |= changes;
11876 r.startFreezingScreenLocked(r.app, globalChanges);
11877 if (r.app == null || r.app.thread == null) {
11878 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11879 destroyActivityLocked(r, true);
11880 } else if (r.state == ActivityState.PAUSING) {
11881 // A little annoying: we are waiting for this activity to
11882 // finish pausing. Let's not do anything now, but just
11883 // flag that it needs to be restarted when done pausing.
11884 r.configDestroy = true;
11885 return true;
11886 } else if (r.state == ActivityState.RESUMED) {
11887 // Try to optimize this case: the configuration is changing
11888 // and we need to restart the top, resumed activity.
11889 // Instead of doing the normal handshaking, just say
11890 // "restart!".
11891 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11892 relaunchActivityLocked(r, r.configChangeFlags, true);
11893 r.configChangeFlags = 0;
11894 } else {
11895 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11896 relaunchActivityLocked(r, r.configChangeFlags, false);
11897 r.configChangeFlags = 0;
11898 }
11899
11900 // All done... tell the caller we weren't able to keep this
11901 // activity around.
11902 return false;
11903 }
11904 }
11905
11906 // Default case: the activity can handle this new configuration, so
11907 // hand it over. Note that we don't need to give it the new
11908 // configuration, since we always send configuration changes to all
11909 // process when they happen so it can just use whatever configuration
11910 // it last got.
11911 if (r.app != null && r.app.thread != null) {
11912 try {
11913 r.app.thread.scheduleActivityConfigurationChanged(r);
11914 } catch (RemoteException e) {
11915 // If process died, whatever.
11916 }
11917 }
11918 r.stopFreezingScreenLocked(false);
11919
11920 return true;
11921 }
11922
11923 /**
11924 * Save the locale. You must be inside a synchronized (this) block.
11925 */
11926 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11927 if(isDiff) {
11928 SystemProperties.set("user.language", l.getLanguage());
11929 SystemProperties.set("user.region", l.getCountry());
11930 }
11931
11932 if(isPersist) {
11933 SystemProperties.set("persist.sys.language", l.getLanguage());
11934 SystemProperties.set("persist.sys.country", l.getCountry());
11935 SystemProperties.set("persist.sys.localevar", l.getVariant());
11936 }
11937 }
11938
11939 // =========================================================
11940 // LIFETIME MANAGEMENT
11941 // =========================================================
11942
11943 private final int computeOomAdjLocked(
11944 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11945 if (mAdjSeq == app.adjSeq) {
11946 // This adjustment has already been computed.
11947 return app.curAdj;
11948 }
11949
11950 if (app.thread == null) {
11951 app.adjSeq = mAdjSeq;
11952 return (app.curAdj=EMPTY_APP_ADJ);
11953 }
11954
11955 app.isForeground = false;
11956
The Android Open Source Project4df24232009-03-05 14:34:35 -080011957 // Determine the importance of the process, starting with most
11958 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011959 int adj;
11960 int N;
11961 if (app == TOP_APP || app.instrumentationClass != null
11962 || app.persistentActivities > 0) {
11963 // The last app on the list is the foreground app.
11964 adj = FOREGROUND_APP_ADJ;
11965 app.isForeground = true;
11966 } else if (app.curReceiver != null ||
11967 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11968 // An app that is currently receiving a broadcast also
11969 // counts as being in the foreground.
11970 adj = FOREGROUND_APP_ADJ;
11971 } else if (app.executingServices.size() > 0) {
11972 // An app that is currently executing a service callback also
11973 // counts as being in the foreground.
11974 adj = FOREGROUND_APP_ADJ;
11975 } else if (app.foregroundServices || app.forcingToForeground != null) {
11976 // The user is aware of this app, so make it visible.
11977 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011978 } else if (app == mHomeProcess) {
11979 // This process is hosting what we currently consider to be the
11980 // home app, so we don't want to let it go into the background.
11981 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011982 } else if ((N=app.activities.size()) != 0) {
11983 // This app is in the background with paused activities.
11984 adj = hiddenAdj;
11985 for (int j=0; j<N; j++) {
11986 if (((HistoryRecord)app.activities.get(j)).visible) {
11987 // This app has a visible activity!
11988 adj = VISIBLE_APP_ADJ;
11989 break;
11990 }
11991 }
11992 } else {
11993 // A very not-needed process.
11994 adj = EMPTY_APP_ADJ;
11995 }
11996
The Android Open Source Project4df24232009-03-05 14:34:35 -080011997 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011998 // there are applications dependent on our services or providers, but
11999 // this gives us a baseline and makes sure we don't get into an
12000 // infinite recursion.
12001 app.adjSeq = mAdjSeq;
12002 app.curRawAdj = adj;
12003 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12004
Christopher Tate6fa95972009-06-05 18:43:55 -070012005 if (mBackupTarget != null && app == mBackupTarget.app) {
12006 // If possible we want to avoid killing apps while they're being backed up
12007 if (adj > BACKUP_APP_ADJ) {
12008 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12009 adj = BACKUP_APP_ADJ;
12010 }
12011 }
12012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012013 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12014 // If this process has active services running in it, we would
12015 // like to avoid killing it unless it would prevent the current
12016 // application from running.
12017 if (adj > hiddenAdj) {
12018 adj = hiddenAdj;
12019 }
12020 final long now = SystemClock.uptimeMillis();
12021 // This process is more important if the top activity is
12022 // bound to the service.
12023 Iterator jt = app.services.iterator();
12024 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12025 ServiceRecord s = (ServiceRecord)jt.next();
12026 if (s.startRequested) {
12027 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12028 // This service has seen some activity within
12029 // recent memory, so we will keep its process ahead
12030 // of the background processes.
12031 if (adj > SECONDARY_SERVER_ADJ) {
12032 adj = SECONDARY_SERVER_ADJ;
12033 }
12034 } else {
12035 // This service has been inactive for too long, just
12036 // put it with the rest of the background processes.
12037 if (adj > hiddenAdj) {
12038 adj = hiddenAdj;
12039 }
12040 }
12041 }
12042 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12043 Iterator<ConnectionRecord> kt
12044 = s.connections.values().iterator();
12045 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12046 // XXX should compute this based on the max of
12047 // all connected clients.
12048 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012049 if (cr.binding.client == app) {
12050 // Binding to ourself is not interesting.
12051 continue;
12052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012053 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12054 ProcessRecord client = cr.binding.client;
12055 int myHiddenAdj = hiddenAdj;
12056 if (myHiddenAdj > client.hiddenAdj) {
12057 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12058 myHiddenAdj = client.hiddenAdj;
12059 } else {
12060 myHiddenAdj = VISIBLE_APP_ADJ;
12061 }
12062 }
12063 int clientAdj = computeOomAdjLocked(
12064 client, myHiddenAdj, TOP_APP);
12065 if (adj > clientAdj) {
12066 adj = clientAdj > VISIBLE_APP_ADJ
12067 ? clientAdj : VISIBLE_APP_ADJ;
12068 }
12069 }
12070 HistoryRecord a = cr.activity;
12071 //if (a != null) {
12072 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12073 //}
12074 if (a != null && adj > FOREGROUND_APP_ADJ &&
12075 (a.state == ActivityState.RESUMED
12076 || a.state == ActivityState.PAUSING)) {
12077 adj = FOREGROUND_APP_ADJ;
12078 }
12079 }
12080 }
12081 }
12082 }
12083
12084 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12085 // If this process has published any content providers, then
12086 // its adjustment makes it at least as important as any of the
12087 // processes using those providers, and no less important than
12088 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12089 if (adj > CONTENT_PROVIDER_ADJ) {
12090 adj = CONTENT_PROVIDER_ADJ;
12091 }
12092 Iterator jt = app.pubProviders.values().iterator();
12093 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12094 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12095 if (cpr.clients.size() != 0) {
12096 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12097 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12098 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012099 if (client == app) {
12100 // Being our own client is not interesting.
12101 continue;
12102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012103 int myHiddenAdj = hiddenAdj;
12104 if (myHiddenAdj > client.hiddenAdj) {
12105 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12106 myHiddenAdj = client.hiddenAdj;
12107 } else {
12108 myHiddenAdj = FOREGROUND_APP_ADJ;
12109 }
12110 }
12111 int clientAdj = computeOomAdjLocked(
12112 client, myHiddenAdj, TOP_APP);
12113 if (adj > clientAdj) {
12114 adj = clientAdj > FOREGROUND_APP_ADJ
12115 ? clientAdj : FOREGROUND_APP_ADJ;
12116 }
12117 }
12118 }
12119 // If the provider has external (non-framework) process
12120 // dependencies, ensure that its adjustment is at least
12121 // FOREGROUND_APP_ADJ.
12122 if (cpr.externals != 0) {
12123 if (adj > FOREGROUND_APP_ADJ) {
12124 adj = FOREGROUND_APP_ADJ;
12125 }
12126 }
12127 }
12128 }
12129
12130 app.curRawAdj = adj;
12131
12132 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12133 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12134 if (adj > app.maxAdj) {
12135 adj = app.maxAdj;
12136 }
12137
12138 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012139 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12140 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12141 : Process.THREAD_GROUP_DEFAULT;
12142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012143 return adj;
12144 }
12145
12146 /**
12147 * Ask a given process to GC right now.
12148 */
12149 final void performAppGcLocked(ProcessRecord app) {
12150 try {
12151 app.lastRequestedGc = SystemClock.uptimeMillis();
12152 if (app.thread != null) {
12153 app.thread.processInBackground();
12154 }
12155 } catch (Exception e) {
12156 // whatever.
12157 }
12158 }
12159
12160 /**
12161 * Returns true if things are idle enough to perform GCs.
12162 */
12163 private final boolean canGcNow() {
12164 return mParallelBroadcasts.size() == 0
12165 && mOrderedBroadcasts.size() == 0
12166 && (mSleeping || (mResumedActivity != null &&
12167 mResumedActivity.idle));
12168 }
12169
12170 /**
12171 * Perform GCs on all processes that are waiting for it, but only
12172 * if things are idle.
12173 */
12174 final void performAppGcsLocked() {
12175 final int N = mProcessesToGc.size();
12176 if (N <= 0) {
12177 return;
12178 }
12179 if (canGcNow()) {
12180 while (mProcessesToGc.size() > 0) {
12181 ProcessRecord proc = mProcessesToGc.remove(0);
12182 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12183 // To avoid spamming the system, we will GC processes one
12184 // at a time, waiting a few seconds between each.
12185 performAppGcLocked(proc);
12186 scheduleAppGcsLocked();
12187 return;
12188 }
12189 }
12190 }
12191 }
12192
12193 /**
12194 * If all looks good, perform GCs on all processes waiting for them.
12195 */
12196 final void performAppGcsIfAppropriateLocked() {
12197 if (canGcNow()) {
12198 performAppGcsLocked();
12199 return;
12200 }
12201 // Still not idle, wait some more.
12202 scheduleAppGcsLocked();
12203 }
12204
12205 /**
12206 * Schedule the execution of all pending app GCs.
12207 */
12208 final void scheduleAppGcsLocked() {
12209 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12210 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12211 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12212 }
12213
12214 /**
12215 * Set up to ask a process to GC itself. This will either do it
12216 * immediately, or put it on the list of processes to gc the next
12217 * time things are idle.
12218 */
12219 final void scheduleAppGcLocked(ProcessRecord app) {
12220 long now = SystemClock.uptimeMillis();
12221 if ((app.lastRequestedGc+5000) > now) {
12222 return;
12223 }
12224 if (!mProcessesToGc.contains(app)) {
12225 mProcessesToGc.add(app);
12226 scheduleAppGcsLocked();
12227 }
12228 }
12229
12230 private final boolean updateOomAdjLocked(
12231 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12232 app.hiddenAdj = hiddenAdj;
12233
12234 if (app.thread == null) {
12235 return true;
12236 }
12237
12238 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12239
12240 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12241 //Thread priority adjustment is disabled out to see
12242 //how the kernel scheduler performs.
12243 if (false) {
12244 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12245 app.setIsForeground = app.isForeground;
12246 if (app.pid != MY_PID) {
12247 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12248 + " to " + (app.isForeground
12249 ? Process.THREAD_PRIORITY_FOREGROUND
12250 : Process.THREAD_PRIORITY_DEFAULT));
12251 try {
12252 Process.setThreadPriority(app.pid, app.isForeground
12253 ? Process.THREAD_PRIORITY_FOREGROUND
12254 : Process.THREAD_PRIORITY_DEFAULT);
12255 } catch (RuntimeException e) {
12256 Log.w(TAG, "Exception trying to set priority of application thread "
12257 + app.pid, e);
12258 }
12259 }
12260 }
12261 }
12262 if (app.pid != 0 && app.pid != MY_PID) {
12263 if (app.curRawAdj != app.setRawAdj) {
12264 if (app.curRawAdj > FOREGROUND_APP_ADJ
12265 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12266 // If this app is transitioning from foreground to
12267 // non-foreground, have it do a gc.
12268 scheduleAppGcLocked(app);
12269 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12270 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12271 // Likewise do a gc when an app is moving in to the
12272 // background (such as a service stopping).
12273 scheduleAppGcLocked(app);
12274 }
12275 app.setRawAdj = app.curRawAdj;
12276 }
12277 if (adj != app.setAdj) {
12278 if (Process.setOomAdj(app.pid, adj)) {
12279 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12280 TAG, "Set app " + app.processName +
12281 " oom adj to " + adj);
12282 app.setAdj = adj;
12283 } else {
12284 return false;
12285 }
12286 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012287 if (app.setSchedGroup != app.curSchedGroup) {
12288 app.setSchedGroup = app.curSchedGroup;
12289 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12290 "Setting process group of " + app.processName
12291 + " to " + app.curSchedGroup);
12292 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012293 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012294 try {
12295 Process.setProcessGroup(app.pid, app.curSchedGroup);
12296 } catch (Exception e) {
12297 Log.w(TAG, "Failed setting process group of " + app.pid
12298 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012299 e.printStackTrace();
12300 } finally {
12301 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012302 }
12303 }
12304 if (false) {
12305 if (app.thread != null) {
12306 try {
12307 app.thread.setSchedulingGroup(app.curSchedGroup);
12308 } catch (RemoteException e) {
12309 }
12310 }
12311 }
12312 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012313 }
12314
12315 return true;
12316 }
12317
12318 private final HistoryRecord resumedAppLocked() {
12319 HistoryRecord resumedActivity = mResumedActivity;
12320 if (resumedActivity == null || resumedActivity.app == null) {
12321 resumedActivity = mPausingActivity;
12322 if (resumedActivity == null || resumedActivity.app == null) {
12323 resumedActivity = topRunningActivityLocked(null);
12324 }
12325 }
12326 return resumedActivity;
12327 }
12328
12329 private final boolean updateOomAdjLocked(ProcessRecord app) {
12330 final HistoryRecord TOP_ACT = resumedAppLocked();
12331 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12332 int curAdj = app.curAdj;
12333 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12334 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12335
12336 mAdjSeq++;
12337
12338 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12339 if (res) {
12340 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12341 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12342 if (nowHidden != wasHidden) {
12343 // Changed to/from hidden state, so apps after it in the LRU
12344 // list may also be changed.
12345 updateOomAdjLocked();
12346 }
12347 }
12348 return res;
12349 }
12350
12351 private final boolean updateOomAdjLocked() {
12352 boolean didOomAdj = true;
12353 final HistoryRecord TOP_ACT = resumedAppLocked();
12354 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12355
12356 if (false) {
12357 RuntimeException e = new RuntimeException();
12358 e.fillInStackTrace();
12359 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12360 }
12361
12362 mAdjSeq++;
12363
12364 // First try updating the OOM adjustment for each of the
12365 // application processes based on their current state.
12366 int i = mLRUProcesses.size();
12367 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12368 while (i > 0) {
12369 i--;
12370 ProcessRecord app = mLRUProcesses.get(i);
12371 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12372 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12373 && app.curAdj == curHiddenAdj) {
12374 curHiddenAdj++;
12375 }
12376 } else {
12377 didOomAdj = false;
12378 }
12379 }
12380
12381 // todo: for now pretend like OOM ADJ didn't work, because things
12382 // aren't behaving as expected on Linux -- it's not killing processes.
12383 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12384 }
12385
12386 private final void trimApplications() {
12387 synchronized (this) {
12388 int i;
12389
12390 // First remove any unused application processes whose package
12391 // has been removed.
12392 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12393 final ProcessRecord app = mRemovedProcesses.get(i);
12394 if (app.activities.size() == 0
12395 && app.curReceiver == null && app.services.size() == 0) {
12396 Log.i(
12397 TAG, "Exiting empty application process "
12398 + app.processName + " ("
12399 + (app.thread != null ? app.thread.asBinder() : null)
12400 + ")\n");
12401 if (app.pid > 0 && app.pid != MY_PID) {
12402 Process.killProcess(app.pid);
12403 } else {
12404 try {
12405 app.thread.scheduleExit();
12406 } catch (Exception e) {
12407 // Ignore exceptions.
12408 }
12409 }
12410 cleanUpApplicationRecordLocked(app, false, -1);
12411 mRemovedProcesses.remove(i);
12412
12413 if (app.persistent) {
12414 if (app.persistent) {
12415 addAppLocked(app.info);
12416 }
12417 }
12418 }
12419 }
12420
12421 // Now try updating the OOM adjustment for each of the
12422 // application processes based on their current state.
12423 // If the setOomAdj() API is not supported, then go with our
12424 // back-up plan...
12425 if (!updateOomAdjLocked()) {
12426
12427 // Count how many processes are running services.
12428 int numServiceProcs = 0;
12429 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12430 final ProcessRecord app = mLRUProcesses.get(i);
12431
12432 if (app.persistent || app.services.size() != 0
12433 || app.curReceiver != null
12434 || app.persistentActivities > 0) {
12435 // Don't count processes holding services against our
12436 // maximum process count.
12437 if (localLOGV) Log.v(
12438 TAG, "Not trimming app " + app + " with services: "
12439 + app.services);
12440 numServiceProcs++;
12441 }
12442 }
12443
12444 int curMaxProcs = mProcessLimit;
12445 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12446 if (mAlwaysFinishActivities) {
12447 curMaxProcs = 1;
12448 }
12449 curMaxProcs += numServiceProcs;
12450
12451 // Quit as many processes as we can to get down to the desired
12452 // process count. First remove any processes that no longer
12453 // have activites running in them.
12454 for ( i=0;
12455 i<mLRUProcesses.size()
12456 && mLRUProcesses.size() > curMaxProcs;
12457 i++) {
12458 final ProcessRecord app = mLRUProcesses.get(i);
12459 // Quit an application only if it is not currently
12460 // running any activities.
12461 if (!app.persistent && app.activities.size() == 0
12462 && app.curReceiver == null && app.services.size() == 0) {
12463 Log.i(
12464 TAG, "Exiting empty application process "
12465 + app.processName + " ("
12466 + (app.thread != null ? app.thread.asBinder() : null)
12467 + ")\n");
12468 if (app.pid > 0 && app.pid != MY_PID) {
12469 Process.killProcess(app.pid);
12470 } else {
12471 try {
12472 app.thread.scheduleExit();
12473 } catch (Exception e) {
12474 // Ignore exceptions.
12475 }
12476 }
12477 // todo: For now we assume the application is not buggy
12478 // or evil, and will quit as a result of our request.
12479 // Eventually we need to drive this off of the death
12480 // notification, and kill the process if it takes too long.
12481 cleanUpApplicationRecordLocked(app, false, i);
12482 i--;
12483 }
12484 }
12485
12486 // If we still have too many processes, now from the least
12487 // recently used process we start finishing activities.
12488 if (Config.LOGV) Log.v(
12489 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12490 " of " + curMaxProcs + " processes");
12491 for ( i=0;
12492 i<mLRUProcesses.size()
12493 && mLRUProcesses.size() > curMaxProcs;
12494 i++) {
12495 final ProcessRecord app = mLRUProcesses.get(i);
12496 // Quit the application only if we have a state saved for
12497 // all of its activities.
12498 boolean canQuit = !app.persistent && app.curReceiver == null
12499 && app.services.size() == 0
12500 && app.persistentActivities == 0;
12501 int NUMA = app.activities.size();
12502 int j;
12503 if (Config.LOGV) Log.v(
12504 TAG, "Looking to quit " + app.processName);
12505 for (j=0; j<NUMA && canQuit; j++) {
12506 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12507 if (Config.LOGV) Log.v(
12508 TAG, " " + r.intent.getComponent().flattenToShortString()
12509 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12510 canQuit = (r.haveState || !r.stateNotNeeded)
12511 && !r.visible && r.stopped;
12512 }
12513 if (canQuit) {
12514 // Finish all of the activities, and then the app itself.
12515 for (j=0; j<NUMA; j++) {
12516 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12517 if (!r.finishing) {
12518 destroyActivityLocked(r, false);
12519 }
12520 r.resultTo = null;
12521 }
12522 Log.i(TAG, "Exiting application process "
12523 + app.processName + " ("
12524 + (app.thread != null ? app.thread.asBinder() : null)
12525 + ")\n");
12526 if (app.pid > 0 && app.pid != MY_PID) {
12527 Process.killProcess(app.pid);
12528 } else {
12529 try {
12530 app.thread.scheduleExit();
12531 } catch (Exception e) {
12532 // Ignore exceptions.
12533 }
12534 }
12535 // todo: For now we assume the application is not buggy
12536 // or evil, and will quit as a result of our request.
12537 // Eventually we need to drive this off of the death
12538 // notification, and kill the process if it takes too long.
12539 cleanUpApplicationRecordLocked(app, false, i);
12540 i--;
12541 //dump();
12542 }
12543 }
12544
12545 }
12546
12547 int curMaxActivities = MAX_ACTIVITIES;
12548 if (mAlwaysFinishActivities) {
12549 curMaxActivities = 1;
12550 }
12551
12552 // Finally, if there are too many activities now running, try to
12553 // finish as many as we can to get back down to the limit.
12554 for ( i=0;
12555 i<mLRUActivities.size()
12556 && mLRUActivities.size() > curMaxActivities;
12557 i++) {
12558 final HistoryRecord r
12559 = (HistoryRecord)mLRUActivities.get(i);
12560
12561 // We can finish this one if we have its icicle saved and
12562 // it is not persistent.
12563 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12564 && r.stopped && !r.persistent && !r.finishing) {
12565 final int origSize = mLRUActivities.size();
12566 destroyActivityLocked(r, true);
12567
12568 // This will remove it from the LRU list, so keep
12569 // our index at the same value. Note that this check to
12570 // see if the size changes is just paranoia -- if
12571 // something unexpected happens, we don't want to end up
12572 // in an infinite loop.
12573 if (origSize > mLRUActivities.size()) {
12574 i--;
12575 }
12576 }
12577 }
12578 }
12579 }
12580
12581 /** This method sends the specified signal to each of the persistent apps */
12582 public void signalPersistentProcesses(int sig) throws RemoteException {
12583 if (sig != Process.SIGNAL_USR1) {
12584 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12585 }
12586
12587 synchronized (this) {
12588 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12589 != PackageManager.PERMISSION_GRANTED) {
12590 throw new SecurityException("Requires permission "
12591 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12592 }
12593
12594 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12595 ProcessRecord r = mLRUProcesses.get(i);
12596 if (r.thread != null && r.persistent) {
12597 Process.sendSignal(r.pid, sig);
12598 }
12599 }
12600 }
12601 }
12602
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012603 public boolean profileControl(String process, boolean start,
12604 String path) throws RemoteException {
12605
12606 synchronized (this) {
12607 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12608 // its own permission.
12609 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12610 != PackageManager.PERMISSION_GRANTED) {
12611 throw new SecurityException("Requires permission "
12612 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12613 }
12614
12615 ProcessRecord proc = null;
12616 try {
12617 int pid = Integer.parseInt(process);
12618 synchronized (mPidsSelfLocked) {
12619 proc = mPidsSelfLocked.get(pid);
12620 }
12621 } catch (NumberFormatException e) {
12622 }
12623
12624 if (proc == null) {
12625 HashMap<String, SparseArray<ProcessRecord>> all
12626 = mProcessNames.getMap();
12627 SparseArray<ProcessRecord> procs = all.get(process);
12628 if (procs != null && procs.size() > 0) {
12629 proc = procs.valueAt(0);
12630 }
12631 }
12632
12633 if (proc == null || proc.thread == null) {
12634 throw new IllegalArgumentException("Unknown process: " + process);
12635 }
12636
12637 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12638 if (isSecure) {
12639 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12640 throw new SecurityException("Process not debuggable: " + proc);
12641 }
12642 }
12643
12644 try {
12645 proc.thread.profilerControl(start, path);
12646 return true;
12647 } catch (RemoteException e) {
12648 throw new IllegalStateException("Process disappeared");
12649 }
12650 }
12651 }
12652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012653 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12654 public void monitor() {
12655 synchronized (this) { }
12656 }
12657}