blob: 3b26cb78d7213ebb91585ec4f390d4ef1a578abb [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;
20import com.android.internal.os.RuntimeInit;
21import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
35import android.app.IActivityWatcher;
36import android.app.IApplicationThread;
37import android.app.IInstrumentationWatcher;
38import android.app.IIntentReceiver;
39import android.app.IIntentSender;
40import android.app.IServiceConnection;
41import android.app.IThumbnailReceiver;
42import android.app.Instrumentation;
43import android.app.PendingIntent;
44import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070045import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020046import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.content.ComponentName;
48import android.content.ContentResolver;
49import android.content.Context;
50import android.content.Intent;
51import android.content.IntentFilter;
52import android.content.pm.ActivityInfo;
53import android.content.pm.ApplicationInfo;
54import android.content.pm.ConfigurationInfo;
55import android.content.pm.IPackageDataObserver;
56import android.content.pm.IPackageManager;
57import android.content.pm.InstrumentationInfo;
58import android.content.pm.PackageManager;
59import android.content.pm.ProviderInfo;
60import android.content.pm.ResolveInfo;
61import android.content.pm.ServiceInfo;
62import android.content.res.Configuration;
63import android.graphics.Bitmap;
64import android.net.Uri;
65import 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;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.util.LogPrinter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.util.PrintWriterPrinter;
93import android.util.SparseArray;
94import android.view.Gravity;
95import android.view.LayoutInflater;
96import android.view.View;
97import android.view.WindowManager;
98import android.view.WindowManagerPolicy;
99
100import dalvik.system.Zygote;
101
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200102import java.io.ByteArrayInputStream;
103import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import java.io.File;
105import java.io.FileDescriptor;
106import java.io.FileInputStream;
107import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.PrintWriter;
110import java.lang.IllegalStateException;
111import java.lang.ref.WeakReference;
112import java.util.ArrayList;
113import java.util.HashMap;
114import java.util.HashSet;
115import java.util.Iterator;
116import java.util.List;
117import java.util.Locale;
118import java.util.Map;
119
120public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
121 static final String TAG = "ActivityManager";
122 static final boolean DEBUG = false;
123 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
124 static final boolean DEBUG_SWITCH = localLOGV || false;
125 static final boolean DEBUG_TASKS = localLOGV || false;
126 static final boolean DEBUG_PAUSE = localLOGV || false;
127 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
128 static final boolean DEBUG_TRANSITION = localLOGV || false;
129 static final boolean DEBUG_BROADCAST = localLOGV || false;
130 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
185 | PackageManager.GET_SUPPORTS_DENSITIES;
186
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 // This is a process holding a secondary server -- killing it will not
292 // have much of an impact as far as the user is concerned. Value set in
293 // system/rootdir/init.rc on startup.
294 final int SECONDARY_SERVER_ADJ;
295
296 // This is a process only hosting activities that are visible to the
297 // user, so we'd prefer they don't disappear. Value set in
298 // system/rootdir/init.rc on startup.
299 final int VISIBLE_APP_ADJ;
300
301 // This is the process running the current foreground app. We'd really
302 // rather not kill it! Value set in system/rootdir/init.rc on startup.
303 final int FOREGROUND_APP_ADJ;
304
305 // This is a process running a core server, such as telephony. Definitely
306 // don't want to kill it, but doing so is not completely fatal.
307 static final int CORE_SERVER_ADJ = -12;
308
309 // The system process runs at the default adjustment.
310 static final int SYSTEM_ADJ = -16;
311
312 // Memory pages are 4K.
313 static final int PAGE_SIZE = 4*1024;
314
315 // Corresponding memory levels for above adjustments.
316 final int EMPTY_APP_MEM;
317 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800318 final int HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 final int SECONDARY_SERVER_MEM;
320 final int VISIBLE_APP_MEM;
321 final int FOREGROUND_APP_MEM;
322
323 final int MY_PID;
324
325 static final String[] EMPTY_STRING_ARRAY = new String[0];
326
327 enum ActivityState {
328 INITIALIZING,
329 RESUMED,
330 PAUSING,
331 PAUSED,
332 STOPPING,
333 STOPPED,
334 FINISHING,
335 DESTROYING,
336 DESTROYED
337 }
338
339 /**
340 * The back history of all previous (and possibly still
341 * running) activities. It contains HistoryRecord objects.
342 */
343 final ArrayList mHistory = new ArrayList();
344
345 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700346 * Description of a request to start a new activity, which has been held
347 * due to app switches being disabled.
348 */
349 class PendingActivityLaunch {
350 HistoryRecord r;
351 HistoryRecord sourceRecord;
352 Uri[] grantedUriPermissions;
353 int grantedMode;
354 boolean onlyIfNeeded;
355 }
356
357 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
358 = new ArrayList<PendingActivityLaunch>();
359
360 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 * List of all active broadcasts that are to be executed immediately
362 * (without waiting for another broadcast to finish). Currently this only
363 * contains broadcasts to registered receivers, to avoid spinning up
364 * a bunch of processes to execute IntentReceiver components.
365 */
366 final ArrayList<BroadcastRecord> mParallelBroadcasts
367 = new ArrayList<BroadcastRecord>();
368
369 /**
370 * List of all active broadcasts that are to be executed one at a time.
371 * The object at the top of the list is the currently activity broadcasts;
372 * those after it are waiting for the top to finish..
373 */
374 final ArrayList<BroadcastRecord> mOrderedBroadcasts
375 = new ArrayList<BroadcastRecord>();
376
377 /**
378 * Set when we current have a BROADCAST_INTENT_MSG in flight.
379 */
380 boolean mBroadcastsScheduled = false;
381
382 /**
383 * Set to indicate whether to issue an onUserLeaving callback when a
384 * newly launched activity is being brought in front of us.
385 */
386 boolean mUserLeaving = false;
387
388 /**
389 * When we are in the process of pausing an activity, before starting the
390 * next one, this variable holds the activity that is currently being paused.
391 */
392 HistoryRecord mPausingActivity = null;
393
394 /**
395 * Current activity that is resumed, or null if there is none.
396 */
397 HistoryRecord mResumedActivity = null;
398
399 /**
400 * Activity we have told the window manager to have key focus.
401 */
402 HistoryRecord mFocusedActivity = null;
403
404 /**
405 * This is the last activity that we put into the paused state. This is
406 * used to determine if we need to do an activity transition while sleeping,
407 * when we normally hold the top activity paused.
408 */
409 HistoryRecord mLastPausedActivity = null;
410
411 /**
412 * List of activities that are waiting for a new activity
413 * to become visible before completing whatever operation they are
414 * supposed to do.
415 */
416 final ArrayList mWaitingVisibleActivities = new ArrayList();
417
418 /**
419 * List of activities that are ready to be stopped, but waiting
420 * for the next activity to settle down before doing so. It contains
421 * HistoryRecord objects.
422 */
423 final ArrayList<HistoryRecord> mStoppingActivities
424 = new ArrayList<HistoryRecord>();
425
426 /**
427 * List of intents that were used to start the most recent tasks.
428 */
429 final ArrayList<TaskRecord> mRecentTasks
430 = new ArrayList<TaskRecord>();
431
432 /**
433 * List of activities that are ready to be finished, but waiting
434 * for the previous activity to settle down before doing so. It contains
435 * HistoryRecord objects.
436 */
437 final ArrayList mFinishingActivities = new ArrayList();
438
439 /**
440 * All of the applications we currently have running organized by name.
441 * The keys are strings of the application package name (as
442 * returned by the package manager), and the keys are ApplicationRecord
443 * objects.
444 */
445 final ProcessMap<ProcessRecord> mProcessNames
446 = new ProcessMap<ProcessRecord>();
447
448 /**
449 * The last time that various processes have crashed.
450 */
451 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
452
453 /**
454 * Set of applications that we consider to be bad, and will reject
455 * incoming broadcasts from (which the user has no control over).
456 * Processes are added to this set when they have crashed twice within
457 * a minimum amount of time; they are removed from it when they are
458 * later restarted (hopefully due to some user action). The value is the
459 * time it was added to the list.
460 */
461 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
462
463 /**
464 * All of the processes we currently have running organized by pid.
465 * The keys are the pid running the application.
466 *
467 * <p>NOTE: This object is protected by its own lock, NOT the global
468 * activity manager lock!
469 */
470 final SparseArray<ProcessRecord> mPidsSelfLocked
471 = new SparseArray<ProcessRecord>();
472
473 /**
474 * All of the processes that have been forced to be foreground. The key
475 * is the pid of the caller who requested it (we hold a death
476 * link on it).
477 */
478 abstract class ForegroundToken implements IBinder.DeathRecipient {
479 int pid;
480 IBinder token;
481 }
482 final SparseArray<ForegroundToken> mForegroundProcesses
483 = new SparseArray<ForegroundToken>();
484
485 /**
486 * List of records for processes that someone had tried to start before the
487 * system was ready. We don't start them at that point, but ensure they
488 * are started by the time booting is complete.
489 */
490 final ArrayList<ProcessRecord> mProcessesOnHold
491 = new ArrayList<ProcessRecord>();
492
493 /**
494 * List of records for processes that we have started and are waiting
495 * for them to call back. This is really only needed when running in
496 * single processes mode, in which case we do not have a unique pid for
497 * each process.
498 */
499 final ArrayList<ProcessRecord> mStartingProcesses
500 = new ArrayList<ProcessRecord>();
501
502 /**
503 * List of persistent applications that are in the process
504 * of being started.
505 */
506 final ArrayList<ProcessRecord> mPersistentStartingProcesses
507 = new ArrayList<ProcessRecord>();
508
509 /**
510 * Processes that are being forcibly torn down.
511 */
512 final ArrayList<ProcessRecord> mRemovedProcesses
513 = new ArrayList<ProcessRecord>();
514
515 /**
516 * List of running applications, sorted by recent usage.
517 * The first entry in the list is the least recently used.
518 * It contains ApplicationRecord objects. This list does NOT include
519 * any persistent application records (since we never want to exit them).
520 */
521 final ArrayList<ProcessRecord> mLRUProcesses
522 = new ArrayList<ProcessRecord>();
523
524 /**
525 * List of processes that should gc as soon as things are idle.
526 */
527 final ArrayList<ProcessRecord> mProcessesToGc
528 = new ArrayList<ProcessRecord>();
529
530 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800531 * This is the process holding what we currently consider to be
532 * the "home" activity.
533 */
534 private ProcessRecord mHomeProcess;
535
536 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 * List of running activities, sorted by recent usage.
538 * The first entry in the list is the least recently used.
539 * It contains HistoryRecord objects.
540 */
541 private final ArrayList mLRUActivities = new ArrayList();
542
543 /**
544 * Set of PendingResultRecord objects that are currently active.
545 */
546 final HashSet mPendingResultRecords = new HashSet();
547
548 /**
549 * Set of IntentSenderRecord objects that are currently active.
550 */
551 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
552 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
553
554 /**
555 * Intent broadcast that we have tried to start, but are
556 * waiting for its application's process to be created. We only
557 * need one (instead of a list) because we always process broadcasts
558 * one at a time, so no others can be started while waiting for this
559 * one.
560 */
561 BroadcastRecord mPendingBroadcast = null;
562
563 /**
564 * Keeps track of all IIntentReceivers that have been registered for
565 * broadcasts. Hash keys are the receiver IBinder, hash value is
566 * a ReceiverList.
567 */
568 final HashMap mRegisteredReceivers = new HashMap();
569
570 /**
571 * Resolver for broadcast intents to registered receivers.
572 * Holds BroadcastFilter (subclass of IntentFilter).
573 */
574 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
575 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
576 @Override
577 protected boolean allowFilterResult(
578 BroadcastFilter filter, List<BroadcastFilter> dest) {
579 IBinder target = filter.receiverList.receiver.asBinder();
580 for (int i=dest.size()-1; i>=0; i--) {
581 if (dest.get(i).receiverList.receiver.asBinder() == target) {
582 return false;
583 }
584 }
585 return true;
586 }
587 };
588
589 /**
590 * State of all active sticky broadcasts. Keys are the action of the
591 * sticky Intent, values are an ArrayList of all broadcasted intents with
592 * that action (which should usually be one).
593 */
594 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
595 new HashMap<String, ArrayList<Intent>>();
596
597 /**
598 * All currently running services.
599 */
600 final HashMap<ComponentName, ServiceRecord> mServices =
601 new HashMap<ComponentName, ServiceRecord>();
602
603 /**
604 * All currently running services indexed by the Intent used to start them.
605 */
606 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
607 new HashMap<Intent.FilterComparison, ServiceRecord>();
608
609 /**
610 * All currently bound service connections. Keys are the IBinder of
611 * the client's IServiceConnection.
612 */
613 final HashMap<IBinder, ConnectionRecord> mServiceConnections
614 = new HashMap<IBinder, ConnectionRecord>();
615
616 /**
617 * List of services that we have been asked to start,
618 * but haven't yet been able to. It is used to hold start requests
619 * while waiting for their corresponding application thread to get
620 * going.
621 */
622 final ArrayList<ServiceRecord> mPendingServices
623 = new ArrayList<ServiceRecord>();
624
625 /**
626 * List of services that are scheduled to restart following a crash.
627 */
628 final ArrayList<ServiceRecord> mRestartingServices
629 = new ArrayList<ServiceRecord>();
630
631 /**
632 * List of services that are in the process of being stopped.
633 */
634 final ArrayList<ServiceRecord> mStoppingServices
635 = new ArrayList<ServiceRecord>();
636
637 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700638 * Backup/restore process management
639 */
640 String mBackupAppName = null;
641 BackupRecord mBackupTarget = null;
642
643 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 * List of PendingThumbnailsRecord objects of clients who are still
645 * waiting to receive all of the thumbnails for a task.
646 */
647 final ArrayList mPendingThumbnails = new ArrayList();
648
649 /**
650 * List of HistoryRecord objects that have been finished and must
651 * still report back to a pending thumbnail receiver.
652 */
653 final ArrayList mCancelledThumbnails = new ArrayList();
654
655 /**
656 * All of the currently running global content providers. Keys are a
657 * string containing the provider name and values are a
658 * ContentProviderRecord object containing the data about it. Note
659 * that a single provider may be published under multiple names, so
660 * there may be multiple entries here for a single one in mProvidersByClass.
661 */
662 final HashMap mProvidersByName = new HashMap();
663
664 /**
665 * All of the currently running global content providers. Keys are a
666 * string containing the provider's implementation class and values are a
667 * ContentProviderRecord object containing the data about it.
668 */
669 final HashMap mProvidersByClass = new HashMap();
670
671 /**
672 * List of content providers who have clients waiting for them. The
673 * application is currently being launched and the provider will be
674 * removed from this list once it is published.
675 */
676 final ArrayList mLaunchingProviders = new ArrayList();
677
678 /**
679 * Global set of specific Uri permissions that have been granted.
680 */
681 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
682 = new SparseArray<HashMap<Uri, UriPermission>>();
683
684 /**
685 * Thread-local storage used to carry caller permissions over through
686 * indirect content-provider access.
687 * @see #ActivityManagerService.openContentUri()
688 */
689 private class Identity {
690 public int pid;
691 public int uid;
692
693 Identity(int _pid, int _uid) {
694 pid = _pid;
695 uid = _uid;
696 }
697 }
698 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
699
700 /**
701 * All information we have collected about the runtime performance of
702 * any user id that can impact battery performance.
703 */
704 final BatteryStatsService mBatteryStatsService;
705
706 /**
707 * information about component usage
708 */
709 final UsageStatsService mUsageStatsService;
710
711 /**
712 * Current configuration information. HistoryRecord objects are given
713 * a reference to this object to indicate which configuration they are
714 * currently running in, so this object must be kept immutable.
715 */
716 Configuration mConfiguration = new Configuration();
717
718 /**
719 * List of initialization arguments to pass to all processes when binding applications to them.
720 * For example, references to the commonly used services.
721 */
722 HashMap<String, IBinder> mAppBindArgs;
723
724 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700725 * Temporary to avoid allocations. Protected by main lock.
726 */
727 final StringBuilder mStringBuilder = new StringBuilder(256);
728
729 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 * Used to control how we initialize the service.
731 */
732 boolean mStartRunning = false;
733 ComponentName mTopComponent;
734 String mTopAction;
735 String mTopData;
736 boolean mSystemReady = false;
737 boolean mBooting = false;
738
739 Context mContext;
740
741 int mFactoryTest;
742
743 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700744 * The time at which we will allow normal application switches again,
745 * after a call to {@link #stopAppSwitches()}.
746 */
747 long mAppSwitchesAllowedTime;
748
749 /**
750 * This is set to true after the first switch after mAppSwitchesAllowedTime
751 * is set; any switches after that will clear the time.
752 */
753 boolean mDidAppSwitch;
754
755 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 * Set while we are wanting to sleep, to prevent any
757 * activities from being started/resumed.
758 */
759 boolean mSleeping = false;
760
761 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700762 * Set if we are shutting down the system, similar to sleeping.
763 */
764 boolean mShuttingDown = false;
765
766 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 * Set when the system is going to sleep, until we have
768 * successfully paused the current activity and released our wake lock.
769 * At that point the system is allowed to actually sleep.
770 */
771 PowerManager.WakeLock mGoingToSleep;
772
773 /**
774 * We don't want to allow the device to go to sleep while in the process
775 * of launching an activity. This is primarily to allow alarm intent
776 * receivers to launch an activity and get that to run before the device
777 * goes back to sleep.
778 */
779 PowerManager.WakeLock mLaunchingActivity;
780
781 /**
782 * Task identifier that activities are currently being started
783 * in. Incremented each time a new task is created.
784 * todo: Replace this with a TokenSpace class that generates non-repeating
785 * integers that won't wrap.
786 */
787 int mCurTask = 1;
788
789 /**
790 * Current sequence id for oom_adj computation traversal.
791 */
792 int mAdjSeq = 0;
793
794 /**
795 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
796 * is set, indicating the user wants processes started in such a way
797 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
798 * running in each process (thus no pre-initialized process, etc).
799 */
800 boolean mSimpleProcessManagement = false;
801
802 /**
803 * System monitoring: number of processes that died since the last
804 * N procs were started.
805 */
806 int[] mProcDeaths = new int[20];
807
808 String mDebugApp = null;
809 boolean mWaitForDebugger = false;
810 boolean mDebugTransient = false;
811 String mOrigDebugApp = null;
812 boolean mOrigWaitForDebugger = false;
813 boolean mAlwaysFinishActivities = false;
814 IActivityWatcher mWatcher = null;
815
816 /**
817 * Callback of last caller to {@link #requestPss}.
818 */
819 Runnable mRequestPssCallback;
820
821 /**
822 * Remaining processes for which we are waiting results from the last
823 * call to {@link #requestPss}.
824 */
825 final ArrayList<ProcessRecord> mRequestPssList
826 = new ArrayList<ProcessRecord>();
827
828 /**
829 * Runtime statistics collection thread. This object's lock is used to
830 * protect all related state.
831 */
832 final Thread mProcessStatsThread;
833
834 /**
835 * Used to collect process stats when showing not responding dialog.
836 * Protected by mProcessStatsThread.
837 */
838 final ProcessStats mProcessStats = new ProcessStats(
839 MONITOR_THREAD_CPU_USAGE);
840 long mLastCpuTime = 0;
841 long mLastWriteTime = 0;
842
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700843 long mInitialStartTime = 0;
844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 /**
846 * Set to true after the system has finished booting.
847 */
848 boolean mBooted = false;
849
850 int mProcessLimit = 0;
851
852 WindowManagerService mWindowManager;
853
854 static ActivityManagerService mSelf;
855 static ActivityThread mSystemThread;
856
857 private final class AppDeathRecipient implements IBinder.DeathRecipient {
858 final ProcessRecord mApp;
859 final int mPid;
860 final IApplicationThread mAppThread;
861
862 AppDeathRecipient(ProcessRecord app, int pid,
863 IApplicationThread thread) {
864 if (localLOGV) Log.v(
865 TAG, "New death recipient " + this
866 + " for thread " + thread.asBinder());
867 mApp = app;
868 mPid = pid;
869 mAppThread = thread;
870 }
871
872 public void binderDied() {
873 if (localLOGV) Log.v(
874 TAG, "Death received in " + this
875 + " for thread " + mAppThread.asBinder());
876 removeRequestedPss(mApp);
877 synchronized(ActivityManagerService.this) {
878 appDiedLocked(mApp, mPid, mAppThread);
879 }
880 }
881 }
882
883 static final int SHOW_ERROR_MSG = 1;
884 static final int SHOW_NOT_RESPONDING_MSG = 2;
885 static final int SHOW_FACTORY_ERROR_MSG = 3;
886 static final int UPDATE_CONFIGURATION_MSG = 4;
887 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
888 static final int WAIT_FOR_DEBUGGER_MSG = 6;
889 static final int BROADCAST_INTENT_MSG = 7;
890 static final int BROADCAST_TIMEOUT_MSG = 8;
891 static final int PAUSE_TIMEOUT_MSG = 9;
892 static final int IDLE_TIMEOUT_MSG = 10;
893 static final int IDLE_NOW_MSG = 11;
894 static final int SERVICE_TIMEOUT_MSG = 12;
895 static final int UPDATE_TIME_ZONE = 13;
896 static final int SHOW_UID_ERROR_MSG = 14;
897 static final int IM_FEELING_LUCKY_MSG = 15;
898 static final int LAUNCH_TIMEOUT_MSG = 16;
899 static final int DESTROY_TIMEOUT_MSG = 17;
900 static final int SERVICE_ERROR_MSG = 18;
901 static final int RESUME_TOP_ACTIVITY_MSG = 19;
902 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700903 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904
905 AlertDialog mUidAlert;
906
907 final Handler mHandler = new Handler() {
908 //public Handler() {
909 // if (localLOGV) Log.v(TAG, "Handler started!");
910 //}
911
912 public void handleMessage(Message msg) {
913 switch (msg.what) {
914 case SHOW_ERROR_MSG: {
915 HashMap data = (HashMap) msg.obj;
916 byte[] crashData = (byte[])data.get("crashData");
917 if (crashData != null) {
918 // This needs to be *un*synchronized to avoid deadlock.
919 ContentResolver resolver = mContext.getContentResolver();
920 Checkin.reportCrash(resolver, crashData);
921 }
922 synchronized (ActivityManagerService.this) {
923 ProcessRecord proc = (ProcessRecord)data.get("app");
924 if (proc != null && proc.crashDialog != null) {
925 Log.e(TAG, "App already has crash dialog: " + proc);
926 return;
927 }
928 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700929 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 Dialog d = new AppErrorDialog(
931 mContext, res, proc,
932 (Integer)data.get("flags"),
933 (String)data.get("shortMsg"),
934 (String)data.get("longMsg"));
935 d.show();
936 proc.crashDialog = d;
937 } else {
938 // The device is asleep, so just pretend that the user
939 // saw a crash dialog and hit "force quit".
940 res.set(0);
941 }
942 }
943 } break;
944 case SHOW_NOT_RESPONDING_MSG: {
945 synchronized (ActivityManagerService.this) {
946 HashMap data = (HashMap) msg.obj;
947 ProcessRecord proc = (ProcessRecord)data.get("app");
948 if (proc != null && proc.anrDialog != null) {
949 Log.e(TAG, "App already has anr dialog: " + proc);
950 return;
951 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800952
953 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
954 null, null, 0, null, null, null,
955 false, false, MY_PID, Process.SYSTEM_UID);
956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
958 mContext, proc, (HistoryRecord)data.get("activity"));
959 d.show();
960 proc.anrDialog = d;
961 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700962
963 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 } break;
965 case SHOW_FACTORY_ERROR_MSG: {
966 Dialog d = new FactoryErrorDialog(
967 mContext, msg.getData().getCharSequence("msg"));
968 d.show();
969 enableScreenAfterBoot();
970 } break;
971 case UPDATE_CONFIGURATION_MSG: {
972 final ContentResolver resolver = mContext.getContentResolver();
973 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
974 } break;
975 case GC_BACKGROUND_PROCESSES_MSG: {
976 synchronized (ActivityManagerService.this) {
977 performAppGcsIfAppropriateLocked();
978 }
979 } break;
980 case WAIT_FOR_DEBUGGER_MSG: {
981 synchronized (ActivityManagerService.this) {
982 ProcessRecord app = (ProcessRecord)msg.obj;
983 if (msg.arg1 != 0) {
984 if (!app.waitedForDebugger) {
985 Dialog d = new AppWaitingForDebuggerDialog(
986 ActivityManagerService.this,
987 mContext, app);
988 app.waitDialog = d;
989 app.waitedForDebugger = true;
990 d.show();
991 }
992 } else {
993 if (app.waitDialog != null) {
994 app.waitDialog.dismiss();
995 app.waitDialog = null;
996 }
997 }
998 }
999 } break;
1000 case BROADCAST_INTENT_MSG: {
1001 if (DEBUG_BROADCAST) Log.v(
1002 TAG, "Received BROADCAST_INTENT_MSG");
1003 processNextBroadcast(true);
1004 } break;
1005 case BROADCAST_TIMEOUT_MSG: {
1006 broadcastTimeout();
1007 } break;
1008 case PAUSE_TIMEOUT_MSG: {
1009 IBinder token = (IBinder)msg.obj;
1010 // We don't at this point know if the activity is fullscreen,
1011 // so we need to be conservative and assume it isn't.
1012 Log.w(TAG, "Activity pause timeout for " + token);
1013 activityPaused(token, null, true);
1014 } break;
1015 case IDLE_TIMEOUT_MSG: {
1016 IBinder token = (IBinder)msg.obj;
1017 // We don't at this point know if the activity is fullscreen,
1018 // so we need to be conservative and assume it isn't.
1019 Log.w(TAG, "Activity idle timeout for " + token);
1020 activityIdleInternal(token, true);
1021 } break;
1022 case DESTROY_TIMEOUT_MSG: {
1023 IBinder token = (IBinder)msg.obj;
1024 // We don't at this point know if the activity is fullscreen,
1025 // so we need to be conservative and assume it isn't.
1026 Log.w(TAG, "Activity destroy timeout for " + token);
1027 activityDestroyed(token);
1028 } break;
1029 case IDLE_NOW_MSG: {
1030 IBinder token = (IBinder)msg.obj;
1031 activityIdle(token);
1032 } break;
1033 case SERVICE_TIMEOUT_MSG: {
1034 serviceTimeout((ProcessRecord)msg.obj);
1035 } break;
1036 case UPDATE_TIME_ZONE: {
1037 synchronized (ActivityManagerService.this) {
1038 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1039 ProcessRecord r = mLRUProcesses.get(i);
1040 if (r.thread != null) {
1041 try {
1042 r.thread.updateTimeZone();
1043 } catch (RemoteException ex) {
1044 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1045 }
1046 }
1047 }
1048 }
1049 break;
1050 }
1051 case SHOW_UID_ERROR_MSG: {
1052 // XXX This is a temporary dialog, no need to localize.
1053 AlertDialog d = new BaseErrorDialog(mContext);
1054 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1055 d.setCancelable(false);
1056 d.setTitle("System UIDs Inconsistent");
1057 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1058 d.setButton("I'm Feeling Lucky",
1059 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1060 mUidAlert = d;
1061 d.show();
1062 } break;
1063 case IM_FEELING_LUCKY_MSG: {
1064 if (mUidAlert != null) {
1065 mUidAlert.dismiss();
1066 mUidAlert = null;
1067 }
1068 } break;
1069 case LAUNCH_TIMEOUT_MSG: {
1070 synchronized (ActivityManagerService.this) {
1071 if (mLaunchingActivity.isHeld()) {
1072 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1073 mLaunchingActivity.release();
1074 }
1075 }
1076 } break;
1077 case SERVICE_ERROR_MSG: {
1078 ServiceRecord srv = (ServiceRecord)msg.obj;
1079 // This needs to be *un*synchronized to avoid deadlock.
1080 Checkin.logEvent(mContext.getContentResolver(),
1081 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1082 srv.name.toShortString());
1083 } break;
1084 case RESUME_TOP_ACTIVITY_MSG: {
1085 synchronized (ActivityManagerService.this) {
1086 resumeTopActivityLocked(null);
1087 }
1088 }
1089 case PROC_START_TIMEOUT_MSG: {
1090 ProcessRecord app = (ProcessRecord)msg.obj;
1091 synchronized (ActivityManagerService.this) {
1092 processStartTimedOutLocked(app);
1093 }
1094 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001095 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1096 synchronized (ActivityManagerService.this) {
1097 doPendingActivityLaunchesLocked(true);
1098 }
1099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 }
1101 }
1102 };
1103
1104 public static void setSystemProcess() {
1105 try {
1106 ActivityManagerService m = mSelf;
1107
1108 ServiceManager.addService("activity", m);
1109 ServiceManager.addService("meminfo", new MemBinder(m));
1110 if (MONITOR_CPU_USAGE) {
1111 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1112 }
1113 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1114 ServiceManager.addService("activity.services", new ServicesBinder(m));
1115 ServiceManager.addService("activity.senders", new SendersBinder(m));
1116 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1117 ServiceManager.addService("permission", new PermissionController(m));
1118
1119 ApplicationInfo info =
1120 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001121 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 synchronized (mSelf) {
1123 ProcessRecord app = mSelf.newProcessRecordLocked(
1124 mSystemThread.getApplicationThread(), info,
1125 info.processName);
1126 app.persistent = true;
1127 app.pid = Process.myPid();
1128 app.maxAdj = SYSTEM_ADJ;
1129 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1130 synchronized (mSelf.mPidsSelfLocked) {
1131 mSelf.mPidsSelfLocked.put(app.pid, app);
1132 }
1133 mSelf.updateLRUListLocked(app, true);
1134 }
1135 } catch (PackageManager.NameNotFoundException e) {
1136 throw new RuntimeException(
1137 "Unable to find android system package", e);
1138 }
1139 }
1140
1141 public void setWindowManager(WindowManagerService wm) {
1142 mWindowManager = wm;
1143 }
1144
1145 public static final Context main(int factoryTest) {
1146 AThread thr = new AThread();
1147 thr.start();
1148
1149 synchronized (thr) {
1150 while (thr.mService == null) {
1151 try {
1152 thr.wait();
1153 } catch (InterruptedException e) {
1154 }
1155 }
1156 }
1157
1158 ActivityManagerService m = thr.mService;
1159 mSelf = m;
1160 ActivityThread at = ActivityThread.systemMain();
1161 mSystemThread = at;
1162 Context context = at.getSystemContext();
1163 m.mContext = context;
1164 m.mFactoryTest = factoryTest;
1165 PowerManager pm =
1166 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1167 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1168 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1169 m.mLaunchingActivity.setReferenceCounted(false);
1170
1171 m.mBatteryStatsService.publish(context);
1172 m.mUsageStatsService.publish(context);
1173
1174 synchronized (thr) {
1175 thr.mReady = true;
1176 thr.notifyAll();
1177 }
1178
1179 m.startRunning(null, null, null, null);
1180
1181 return context;
1182 }
1183
1184 public static ActivityManagerService self() {
1185 return mSelf;
1186 }
1187
1188 static class AThread extends Thread {
1189 ActivityManagerService mService;
1190 boolean mReady = false;
1191
1192 public AThread() {
1193 super("ActivityManager");
1194 }
1195
1196 public void run() {
1197 Looper.prepare();
1198
1199 android.os.Process.setThreadPriority(
1200 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1201
1202 ActivityManagerService m = new ActivityManagerService();
1203
1204 synchronized (this) {
1205 mService = m;
1206 notifyAll();
1207 }
1208
1209 synchronized (this) {
1210 while (!mReady) {
1211 try {
1212 wait();
1213 } catch (InterruptedException e) {
1214 }
1215 }
1216 }
1217
1218 Looper.loop();
1219 }
1220 }
1221
1222 static class BroadcastsBinder extends Binder {
1223 ActivityManagerService mActivityManagerService;
1224 BroadcastsBinder(ActivityManagerService activityManagerService) {
1225 mActivityManagerService = activityManagerService;
1226 }
1227
1228 @Override
1229 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1230 mActivityManagerService.dumpBroadcasts(pw);
1231 }
1232 }
1233
1234 static class ServicesBinder extends Binder {
1235 ActivityManagerService mActivityManagerService;
1236 ServicesBinder(ActivityManagerService activityManagerService) {
1237 mActivityManagerService = activityManagerService;
1238 }
1239
1240 @Override
1241 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1242 mActivityManagerService.dumpServices(pw);
1243 }
1244 }
1245
1246 static class SendersBinder extends Binder {
1247 ActivityManagerService mActivityManagerService;
1248 SendersBinder(ActivityManagerService activityManagerService) {
1249 mActivityManagerService = activityManagerService;
1250 }
1251
1252 @Override
1253 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1254 mActivityManagerService.dumpSenders(pw);
1255 }
1256 }
1257
1258 static class ProvidersBinder extends Binder {
1259 ActivityManagerService mActivityManagerService;
1260 ProvidersBinder(ActivityManagerService activityManagerService) {
1261 mActivityManagerService = activityManagerService;
1262 }
1263
1264 @Override
1265 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1266 mActivityManagerService.dumpProviders(pw);
1267 }
1268 }
1269
1270 static class MemBinder extends Binder {
1271 ActivityManagerService mActivityManagerService;
1272 MemBinder(ActivityManagerService activityManagerService) {
1273 mActivityManagerService = activityManagerService;
1274 }
1275
1276 @Override
1277 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1278 ActivityManagerService service = mActivityManagerService;
1279 ArrayList<ProcessRecord> procs;
1280 synchronized (mActivityManagerService) {
1281 if (args != null && args.length > 0
1282 && args[0].charAt(0) != '-') {
1283 procs = new ArrayList<ProcessRecord>();
1284 int pid = -1;
1285 try {
1286 pid = Integer.parseInt(args[0]);
1287 } catch (NumberFormatException e) {
1288
1289 }
1290 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1291 ProcessRecord proc = service.mLRUProcesses.get(i);
1292 if (proc.pid == pid) {
1293 procs.add(proc);
1294 } else if (proc.processName.equals(args[0])) {
1295 procs.add(proc);
1296 }
1297 }
1298 if (procs.size() <= 0) {
1299 pw.println("No process found for: " + args[0]);
1300 return;
1301 }
1302 } else {
1303 procs = service.mLRUProcesses;
1304 }
1305 }
1306 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1307 }
1308 }
1309
1310 static class CpuBinder extends Binder {
1311 ActivityManagerService mActivityManagerService;
1312 CpuBinder(ActivityManagerService activityManagerService) {
1313 mActivityManagerService = activityManagerService;
1314 }
1315
1316 @Override
1317 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1318 synchronized (mActivityManagerService.mProcessStatsThread) {
1319 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1320 }
1321 }
1322 }
1323
1324 private ActivityManagerService() {
1325 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1326 if (v != null && Integer.getInteger(v) != 0) {
1327 mSimpleProcessManagement = true;
1328 }
1329 v = System.getenv("ANDROID_DEBUG_APP");
1330 if (v != null) {
1331 mSimpleProcessManagement = true;
1332 }
1333
1334 MY_PID = Process.myPid();
1335
1336 File dataDir = Environment.getDataDirectory();
1337 File systemDir = new File(dataDir, "system");
1338 systemDir.mkdirs();
1339 mBatteryStatsService = new BatteryStatsService(new File(
1340 systemDir, "batterystats.bin").toString());
1341 mBatteryStatsService.getActiveStatistics().readLocked();
1342 mBatteryStatsService.getActiveStatistics().writeLocked();
1343
1344 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001345 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346
1347 mConfiguration.makeDefault();
1348 mProcessStats.init();
1349
1350 // Add ourself to the Watchdog monitors.
1351 Watchdog.getInstance().addMonitor(this);
1352
1353 // These values are set in system/rootdir/init.rc on startup.
1354 FOREGROUND_APP_ADJ =
1355 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1356 VISIBLE_APP_ADJ =
1357 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1358 SECONDARY_SERVER_ADJ =
1359 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001360 HOME_APP_ADJ =
1361 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 HIDDEN_APP_MIN_ADJ =
1363 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1364 CONTENT_PROVIDER_ADJ =
1365 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1366 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1367 EMPTY_APP_ADJ =
1368 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1369 FOREGROUND_APP_MEM =
1370 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1371 VISIBLE_APP_MEM =
1372 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1373 SECONDARY_SERVER_MEM =
1374 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001375 HOME_APP_MEM =
1376 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 HIDDEN_APP_MEM =
1378 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1379 EMPTY_APP_MEM =
1380 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1381
1382 mProcessStatsThread = new Thread("ProcessStats") {
1383 public void run() {
1384 while (true) {
1385 try {
1386 try {
1387 synchronized(this) {
1388 final long now = SystemClock.uptimeMillis();
1389 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1390 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1391 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1392 // + ", write delay=" + nextWriteDelay);
1393 if (nextWriteDelay < nextCpuDelay) {
1394 nextCpuDelay = nextWriteDelay;
1395 }
1396 if (nextCpuDelay > 0) {
1397 this.wait(nextCpuDelay);
1398 }
1399 }
1400 } catch (InterruptedException e) {
1401 }
1402
1403 updateCpuStatsNow();
1404 } catch (Exception e) {
1405 Log.e(TAG, "Unexpected exception collecting process stats", e);
1406 }
1407 }
1408 }
1409 };
1410 mProcessStatsThread.start();
1411 }
1412
1413 @Override
1414 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1415 throws RemoteException {
1416 try {
1417 return super.onTransact(code, data, reply, flags);
1418 } catch (RuntimeException e) {
1419 // The activity manager only throws security exceptions, so let's
1420 // log all others.
1421 if (!(e instanceof SecurityException)) {
1422 Log.e(TAG, "Activity Manager Crash", e);
1423 }
1424 throw e;
1425 }
1426 }
1427
1428 void updateCpuStats() {
1429 synchronized (mProcessStatsThread) {
1430 final long now = SystemClock.uptimeMillis();
1431 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1432 mProcessStatsThread.notify();
1433 }
1434 }
1435 }
1436
1437 void updateCpuStatsNow() {
1438 synchronized (mProcessStatsThread) {
1439 final long now = SystemClock.uptimeMillis();
1440 boolean haveNewCpuStats = false;
1441
1442 if (MONITOR_CPU_USAGE &&
1443 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1444 mLastCpuTime = now;
1445 haveNewCpuStats = true;
1446 mProcessStats.update();
1447 //Log.i(TAG, mProcessStats.printCurrentState());
1448 //Log.i(TAG, "Total CPU usage: "
1449 // + mProcessStats.getTotalCpuPercent() + "%");
1450
1451 // Log the cpu usage if the property is set.
1452 if ("true".equals(SystemProperties.get("events.cpu"))) {
1453 int user = mProcessStats.getLastUserTime();
1454 int system = mProcessStats.getLastSystemTime();
1455 int iowait = mProcessStats.getLastIoWaitTime();
1456 int irq = mProcessStats.getLastIrqTime();
1457 int softIrq = mProcessStats.getLastSoftIrqTime();
1458 int idle = mProcessStats.getLastIdleTime();
1459
1460 int total = user + system + iowait + irq + softIrq + idle;
1461 if (total == 0) total = 1;
1462
1463 EventLog.writeEvent(LOG_CPU,
1464 ((user+system+iowait+irq+softIrq) * 100) / total,
1465 (user * 100) / total,
1466 (system * 100) / total,
1467 (iowait * 100) / total,
1468 (irq * 100) / total,
1469 (softIrq * 100) / total);
1470 }
1471 }
1472
1473 synchronized(mBatteryStatsService.getActiveStatistics()) {
1474 synchronized(mPidsSelfLocked) {
1475 if (haveNewCpuStats) {
1476 if (mBatteryStatsService.isOnBattery()) {
1477 final int N = mProcessStats.countWorkingStats();
1478 for (int i=0; i<N; i++) {
1479 ProcessStats.Stats st
1480 = mProcessStats.getWorkingStats(i);
1481 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1482 if (pr != null) {
1483 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1484 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1485 }
1486 }
1487 }
1488 }
1489 }
1490
1491 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1492 mLastWriteTime = now;
1493 mBatteryStatsService.getActiveStatistics().writeLocked();
1494 }
1495 }
1496 }
1497 }
1498
1499 /**
1500 * Initialize the application bind args. These are passed to each
1501 * process when the bindApplication() IPC is sent to the process. They're
1502 * lazily setup to make sure the services are running when they're asked for.
1503 */
1504 private HashMap<String, IBinder> getCommonServicesLocked() {
1505 if (mAppBindArgs == null) {
1506 mAppBindArgs = new HashMap<String, IBinder>();
1507
1508 // Setup the application init args
1509 mAppBindArgs.put("package", ServiceManager.getService("package"));
1510 mAppBindArgs.put("window", ServiceManager.getService("window"));
1511 mAppBindArgs.put(Context.ALARM_SERVICE,
1512 ServiceManager.getService(Context.ALARM_SERVICE));
1513 }
1514 return mAppBindArgs;
1515 }
1516
1517 private final void setFocusedActivityLocked(HistoryRecord r) {
1518 if (mFocusedActivity != r) {
1519 mFocusedActivity = r;
1520 mWindowManager.setFocusedApp(r, true);
1521 }
1522 }
1523
1524 private final void updateLRUListLocked(ProcessRecord app,
1525 boolean oomAdj) {
1526 // put it on the LRU to keep track of when it should be exited.
1527 int lrui = mLRUProcesses.indexOf(app);
1528 if (lrui >= 0) mLRUProcesses.remove(lrui);
1529 mLRUProcesses.add(app);
1530 //Log.i(TAG, "Putting proc to front: " + app.processName);
1531 if (oomAdj) {
1532 updateOomAdjLocked();
1533 }
1534 }
1535
1536 private final boolean updateLRUListLocked(HistoryRecord r) {
1537 final boolean hadit = mLRUActivities.remove(r);
1538 mLRUActivities.add(r);
1539 return hadit;
1540 }
1541
1542 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1543 int i = mHistory.size()-1;
1544 while (i >= 0) {
1545 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1546 if (!r.finishing && r != notTop) {
1547 return r;
1548 }
1549 i--;
1550 }
1551 return null;
1552 }
1553
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001554 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1555 int i = mHistory.size()-1;
1556 while (i >= 0) {
1557 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1558 if (!r.finishing && !r.delayedResume && r != notTop) {
1559 return r;
1560 }
1561 i--;
1562 }
1563 return null;
1564 }
1565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 /**
1567 * This is a simplified version of topRunningActivityLocked that provides a number of
1568 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1569 *
1570 * @param token If non-null, any history records matching this token will be skipped.
1571 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1572 *
1573 * @return Returns the HistoryRecord of the next activity on the stack.
1574 */
1575 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1576 int i = mHistory.size()-1;
1577 while (i >= 0) {
1578 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1579 // Note: the taskId check depends on real taskId fields being non-zero
1580 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1581 return r;
1582 }
1583 i--;
1584 }
1585 return null;
1586 }
1587
1588 private final ProcessRecord getProcessRecordLocked(
1589 String processName, int uid) {
1590 if (uid == Process.SYSTEM_UID) {
1591 // The system gets to run in any process. If there are multiple
1592 // processes with the same uid, just pick the first (this
1593 // should never happen).
1594 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1595 processName);
1596 return procs != null ? procs.valueAt(0) : null;
1597 }
1598 ProcessRecord proc = mProcessNames.get(processName, uid);
1599 return proc;
1600 }
1601
1602 private boolean isNextTransitionForward() {
1603 int transit = mWindowManager.getPendingAppTransition();
1604 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1605 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1606 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1607 }
1608
1609 private final boolean realStartActivityLocked(HistoryRecord r,
1610 ProcessRecord app, boolean andResume, boolean checkConfig)
1611 throws RemoteException {
1612
1613 r.startFreezingScreenLocked(app, 0);
1614 mWindowManager.setAppVisibility(r, true);
1615
1616 // Have the window manager re-evaluate the orientation of
1617 // the screen based on the new activity order. Note that
1618 // as a result of this, it can call back into the activity
1619 // manager with a new orientation. We don't care about that,
1620 // because the activity is not currently running so we are
1621 // just restarting it anyway.
1622 if (checkConfig) {
1623 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001624 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 r.mayFreezeScreenLocked(app) ? r : null);
1626 updateConfigurationLocked(config, r);
1627 }
1628
1629 r.app = app;
1630
1631 if (localLOGV) Log.v(TAG, "Launching: " + r);
1632
1633 int idx = app.activities.indexOf(r);
1634 if (idx < 0) {
1635 app.activities.add(r);
1636 }
1637 updateLRUListLocked(app, true);
1638
1639 try {
1640 if (app.thread == null) {
1641 throw new RemoteException();
1642 }
1643 List<ResultInfo> results = null;
1644 List<Intent> newIntents = null;
1645 if (andResume) {
1646 results = r.results;
1647 newIntents = r.newIntents;
1648 }
1649 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1650 + " icicle=" + r.icicle
1651 + " with results=" + results + " newIntents=" + newIntents
1652 + " andResume=" + andResume);
1653 if (andResume) {
1654 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1655 System.identityHashCode(r),
1656 r.task.taskId, r.shortComponentName);
1657 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001658 if (r.isHomeActivity) {
1659 mHomeProcess = app;
1660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1662 r.info, r.icicle, results, newIntents, !andResume,
1663 isNextTransitionForward());
1664 // Update usage stats for launched activity
1665 updateUsageStats(r, true);
1666 } catch (RemoteException e) {
1667 if (r.launchFailed) {
1668 // This is the second time we failed -- finish activity
1669 // and give up.
1670 Log.e(TAG, "Second failure launching "
1671 + r.intent.getComponent().flattenToShortString()
1672 + ", giving up", e);
1673 appDiedLocked(app, app.pid, app.thread);
1674 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1675 "2nd-crash");
1676 return false;
1677 }
1678
1679 // This is the first time we failed -- restart process and
1680 // retry.
1681 app.activities.remove(r);
1682 throw e;
1683 }
1684
1685 r.launchFailed = false;
1686 if (updateLRUListLocked(r)) {
1687 Log.w(TAG, "Activity " + r
1688 + " being launched, but already in LRU list");
1689 }
1690
1691 if (andResume) {
1692 // As part of the process of launching, ActivityThread also performs
1693 // a resume.
1694 r.state = ActivityState.RESUMED;
1695 r.icicle = null;
1696 r.haveState = false;
1697 r.stopped = false;
1698 mResumedActivity = r;
1699 r.task.touchActiveTime();
1700 completeResumeLocked(r);
1701 pauseIfSleepingLocked();
1702 } else {
1703 // This activity is not starting in the resumed state... which
1704 // should look like we asked it to pause+stop (but remain visible),
1705 // and it has done so and reported back the current icicle and
1706 // other state.
1707 r.state = ActivityState.STOPPED;
1708 r.stopped = true;
1709 }
1710
1711 return true;
1712 }
1713
1714 private final void startSpecificActivityLocked(HistoryRecord r,
1715 boolean andResume, boolean checkConfig) {
1716 // Is this activity's application already running?
1717 ProcessRecord app = getProcessRecordLocked(r.processName,
1718 r.info.applicationInfo.uid);
1719
1720 if (r.startTime == 0) {
1721 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001722 if (mInitialStartTime == 0) {
1723 mInitialStartTime = r.startTime;
1724 }
1725 } else if (mInitialStartTime == 0) {
1726 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
1728
1729 if (app != null && app.thread != null) {
1730 try {
1731 realStartActivityLocked(r, app, andResume, checkConfig);
1732 return;
1733 } catch (RemoteException e) {
1734 Log.w(TAG, "Exception when starting activity "
1735 + r.intent.getComponent().flattenToShortString(), e);
1736 }
1737
1738 // If a dead object exception was thrown -- fall through to
1739 // restart the application.
1740 }
1741
1742 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1743 "activity", r.intent.getComponent());
1744 }
1745
1746 private final ProcessRecord startProcessLocked(String processName,
1747 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1748 String hostingType, ComponentName hostingName) {
1749 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1750 // We don't have to do anything more if:
1751 // (1) There is an existing application record; and
1752 // (2) The caller doesn't think it is dead, OR there is no thread
1753 // object attached to it so we know it couldn't have crashed; and
1754 // (3) There is a pid assigned to it, so it is either starting or
1755 // already running.
1756 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1757 + " app=" + app + " knownToBeDead=" + knownToBeDead
1758 + " thread=" + (app != null ? app.thread : null)
1759 + " pid=" + (app != null ? app.pid : -1));
1760 if (app != null &&
1761 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1762 return app;
1763 }
1764
1765 String hostingNameStr = hostingName != null
1766 ? hostingName.flattenToShortString() : null;
1767
1768 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1769 // If we are in the background, then check to see if this process
1770 // is bad. If so, we will just silently fail.
1771 if (mBadProcesses.get(info.processName, info.uid) != null) {
1772 return null;
1773 }
1774 } else {
1775 // When the user is explicitly starting a process, then clear its
1776 // crash count so that we won't make it bad until they see at
1777 // least one crash dialog again, and make the process good again
1778 // if it had been bad.
1779 mProcessCrashTimes.remove(info.processName, info.uid);
1780 if (mBadProcesses.get(info.processName, info.uid) != null) {
1781 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1782 info.processName);
1783 mBadProcesses.remove(info.processName, info.uid);
1784 if (app != null) {
1785 app.bad = false;
1786 }
1787 }
1788 }
1789
1790 if (app == null) {
1791 app = newProcessRecordLocked(null, info, processName);
1792 mProcessNames.put(processName, info.uid, app);
1793 } else {
1794 // If this is a new package in the process, add the package to the list
1795 app.addPackage(info.packageName);
1796 }
1797
1798 // If the system is not ready yet, then hold off on starting this
1799 // process until it is.
1800 if (!mSystemReady
1801 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1802 if (!mProcessesOnHold.contains(app)) {
1803 mProcessesOnHold.add(app);
1804 }
1805 return app;
1806 }
1807
1808 startProcessLocked(app, hostingType, hostingNameStr);
1809 return (app.pid != 0) ? app : null;
1810 }
1811
1812 private final void startProcessLocked(ProcessRecord app,
1813 String hostingType, String hostingNameStr) {
1814 if (app.pid > 0 && app.pid != MY_PID) {
1815 synchronized (mPidsSelfLocked) {
1816 mPidsSelfLocked.remove(app.pid);
1817 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1818 }
1819 app.pid = 0;
1820 }
1821
1822 mProcessesOnHold.remove(app);
1823
1824 updateCpuStats();
1825
1826 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1827 mProcDeaths[0] = 0;
1828
1829 try {
1830 int uid = app.info.uid;
1831 int[] gids = null;
1832 try {
1833 gids = mContext.getPackageManager().getPackageGids(
1834 app.info.packageName);
1835 } catch (PackageManager.NameNotFoundException e) {
1836 Log.w(TAG, "Unable to retrieve gids", e);
1837 }
1838 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1839 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1840 && mTopComponent != null
1841 && app.processName.equals(mTopComponent.getPackageName())) {
1842 uid = 0;
1843 }
1844 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1845 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1846 uid = 0;
1847 }
1848 }
1849 int debugFlags = 0;
1850 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1851 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1852 }
1853 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1854 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1855 }
1856 if ("1".equals(SystemProperties.get("debug.assert"))) {
1857 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1858 }
1859 int pid = Process.start("android.app.ActivityThread",
1860 mSimpleProcessManagement ? app.processName : null, uid, uid,
1861 gids, debugFlags, null);
1862 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1863 synchronized (bs) {
1864 if (bs.isOnBattery()) {
1865 app.batteryStats.incStartsLocked();
1866 }
1867 }
1868
1869 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1870 app.processName, hostingType,
1871 hostingNameStr != null ? hostingNameStr : "");
1872
1873 if (app.persistent) {
1874 Watchdog.getInstance().processStarted(app, app.processName, pid);
1875 }
1876
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001877 StringBuilder buf = mStringBuilder;
1878 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 buf.append("Start proc ");
1880 buf.append(app.processName);
1881 buf.append(" for ");
1882 buf.append(hostingType);
1883 if (hostingNameStr != null) {
1884 buf.append(" ");
1885 buf.append(hostingNameStr);
1886 }
1887 buf.append(": pid=");
1888 buf.append(pid);
1889 buf.append(" uid=");
1890 buf.append(uid);
1891 buf.append(" gids={");
1892 if (gids != null) {
1893 for (int gi=0; gi<gids.length; gi++) {
1894 if (gi != 0) buf.append(", ");
1895 buf.append(gids[gi]);
1896
1897 }
1898 }
1899 buf.append("}");
1900 Log.i(TAG, buf.toString());
1901 if (pid == 0 || pid == MY_PID) {
1902 // Processes are being emulated with threads.
1903 app.pid = MY_PID;
1904 app.removed = false;
1905 mStartingProcesses.add(app);
1906 } else if (pid > 0) {
1907 app.pid = pid;
1908 app.removed = false;
1909 synchronized (mPidsSelfLocked) {
1910 this.mPidsSelfLocked.put(pid, app);
1911 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1912 msg.obj = app;
1913 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1914 }
1915 } else {
1916 app.pid = 0;
1917 RuntimeException e = new RuntimeException(
1918 "Failure starting process " + app.processName
1919 + ": returned pid=" + pid);
1920 Log.e(TAG, e.getMessage(), e);
1921 }
1922 } catch (RuntimeException e) {
1923 // XXX do better error recovery.
1924 app.pid = 0;
1925 Log.e(TAG, "Failure starting process " + app.processName, e);
1926 }
1927 }
1928
1929 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1930 if (mPausingActivity != null) {
1931 RuntimeException e = new RuntimeException();
1932 Log.e(TAG, "Trying to pause when pause is already pending for "
1933 + mPausingActivity, e);
1934 }
1935 HistoryRecord prev = mResumedActivity;
1936 if (prev == null) {
1937 RuntimeException e = new RuntimeException();
1938 Log.e(TAG, "Trying to pause when nothing is resumed", e);
1939 resumeTopActivityLocked(null);
1940 return;
1941 }
1942 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
1943 mResumedActivity = null;
1944 mPausingActivity = prev;
1945 mLastPausedActivity = prev;
1946 prev.state = ActivityState.PAUSING;
1947 prev.task.touchActiveTime();
1948
1949 updateCpuStats();
1950
1951 if (prev.app != null && prev.app.thread != null) {
1952 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
1953 try {
1954 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
1955 System.identityHashCode(prev),
1956 prev.shortComponentName);
1957 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
1958 prev.configChangeFlags);
1959 updateUsageStats(prev, false);
1960 } catch (Exception e) {
1961 // Ignore exception, if process died other code will cleanup.
1962 Log.w(TAG, "Exception thrown during pause", e);
1963 mPausingActivity = null;
1964 mLastPausedActivity = null;
1965 }
1966 } else {
1967 mPausingActivity = null;
1968 mLastPausedActivity = null;
1969 }
1970
1971 // If we are not going to sleep, we want to ensure the device is
1972 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07001973 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 mLaunchingActivity.acquire();
1975 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
1976 // To be safe, don't allow the wake lock to be held for too long.
1977 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1978 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
1979 }
1980 }
1981
1982
1983 if (mPausingActivity != null) {
1984 // Have the window manager pause its key dispatching until the new
1985 // activity has started. If we're pausing the activity just because
1986 // the screen is being turned off and the UI is sleeping, don't interrupt
1987 // key dispatch; the same activity will pick it up again on wakeup.
1988 if (!uiSleeping) {
1989 prev.pauseKeyDispatchingLocked();
1990 } else {
1991 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
1992 }
1993
1994 // Schedule a pause timeout in case the app doesn't respond.
1995 // We don't give it much time because this directly impacts the
1996 // responsiveness seen by the user.
1997 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
1998 msg.obj = prev;
1999 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2000 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2001 } else {
2002 // This activity failed to schedule the
2003 // pause, so just treat it as being paused now.
2004 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2005 resumeTopActivityLocked(null);
2006 }
2007 }
2008
2009 private final void completePauseLocked() {
2010 HistoryRecord prev = mPausingActivity;
2011 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2012
2013 if (prev != null) {
2014 if (prev.finishing) {
2015 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2016 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2017 } else if (prev.app != null) {
2018 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2019 if (prev.waitingVisible) {
2020 prev.waitingVisible = false;
2021 mWaitingVisibleActivities.remove(prev);
2022 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2023 TAG, "Complete pause, no longer waiting: " + prev);
2024 }
2025 if (prev.configDestroy) {
2026 // The previous is being paused because the configuration
2027 // is changing, which means it is actually stopping...
2028 // To juggle the fact that we are also starting a new
2029 // instance right now, we need to first completely stop
2030 // the current instance before starting the new one.
2031 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2032 destroyActivityLocked(prev, true);
2033 } else {
2034 mStoppingActivities.add(prev);
2035 if (mStoppingActivities.size() > 3) {
2036 // If we already have a few activities waiting to stop,
2037 // then give up on things going idle and start clearing
2038 // them out.
2039 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2040 Message msg = Message.obtain();
2041 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2042 mHandler.sendMessage(msg);
2043 }
2044 }
2045 } else {
2046 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2047 prev = null;
2048 }
2049 mPausingActivity = null;
2050 }
2051
Dianne Hackborn55280a92009-05-07 15:53:46 -07002052 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 resumeTopActivityLocked(prev);
2054 } else {
2055 if (mGoingToSleep.isHeld()) {
2056 mGoingToSleep.release();
2057 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002058 if (mShuttingDown) {
2059 notifyAll();
2060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 }
2062
2063 if (prev != null) {
2064 prev.resumeKeyDispatchingLocked();
2065 }
2066 }
2067
2068 /**
2069 * Once we know that we have asked an application to put an activity in
2070 * the resumed state (either by launching it or explicitly telling it),
2071 * this function updates the rest of our state to match that fact.
2072 */
2073 private final void completeResumeLocked(HistoryRecord next) {
2074 next.idle = false;
2075 next.results = null;
2076 next.newIntents = null;
2077
2078 // schedule an idle timeout in case the app doesn't do it for us.
2079 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2080 msg.obj = next;
2081 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2082
2083 if (false) {
2084 // The activity was never told to pause, so just keep
2085 // things going as-is. To maintain our own state,
2086 // we need to emulate it coming back and saying it is
2087 // idle.
2088 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2089 msg.obj = next;
2090 mHandler.sendMessage(msg);
2091 }
2092
2093 next.thumbnail = null;
2094 setFocusedActivityLocked(next);
2095 next.resumeKeyDispatchingLocked();
2096 ensureActivitiesVisibleLocked(null, 0);
2097 mWindowManager.executeAppTransition();
2098 }
2099
2100 /**
2101 * Make sure that all activities that need to be visible (that is, they
2102 * currently can be seen by the user) actually are.
2103 */
2104 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2105 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2106 if (DEBUG_VISBILITY) Log.v(
2107 TAG, "ensureActivitiesVisible behind " + top
2108 + " configChanges=0x" + Integer.toHexString(configChanges));
2109
2110 // If the top activity is not fullscreen, then we need to
2111 // make sure any activities under it are now visible.
2112 final int count = mHistory.size();
2113 int i = count-1;
2114 while (mHistory.get(i) != top) {
2115 i--;
2116 }
2117 HistoryRecord r;
2118 boolean behindFullscreen = false;
2119 for (; i>=0; i--) {
2120 r = (HistoryRecord)mHistory.get(i);
2121 if (DEBUG_VISBILITY) Log.v(
2122 TAG, "Make visible? " + r + " finishing=" + r.finishing
2123 + " state=" + r.state);
2124 if (r.finishing) {
2125 continue;
2126 }
2127
2128 final boolean doThisProcess = onlyThisProcess == null
2129 || onlyThisProcess.equals(r.processName);
2130
2131 // First: if this is not the current activity being started, make
2132 // sure it matches the current configuration.
2133 if (r != starting && doThisProcess) {
2134 ensureActivityConfigurationLocked(r, 0);
2135 }
2136
2137 if (r.app == null || r.app.thread == null) {
2138 if (onlyThisProcess == null
2139 || onlyThisProcess.equals(r.processName)) {
2140 // This activity needs to be visible, but isn't even
2141 // running... get it started, but don't resume it
2142 // at this point.
2143 if (DEBUG_VISBILITY) Log.v(
2144 TAG, "Start and freeze screen for " + r);
2145 if (r != starting) {
2146 r.startFreezingScreenLocked(r.app, configChanges);
2147 }
2148 if (!r.visible) {
2149 if (DEBUG_VISBILITY) Log.v(
2150 TAG, "Starting and making visible: " + r);
2151 mWindowManager.setAppVisibility(r, true);
2152 }
2153 if (r != starting) {
2154 startSpecificActivityLocked(r, false, false);
2155 }
2156 }
2157
2158 } else if (r.visible) {
2159 // If this activity is already visible, then there is nothing
2160 // else to do here.
2161 if (DEBUG_VISBILITY) Log.v(
2162 TAG, "Skipping: already visible at " + r);
2163 r.stopFreezingScreenLocked(false);
2164
2165 } else if (onlyThisProcess == null) {
2166 // This activity is not currently visible, but is running.
2167 // Tell it to become visible.
2168 r.visible = true;
2169 if (r.state != ActivityState.RESUMED && r != starting) {
2170 // If this activity is paused, tell it
2171 // to now show its window.
2172 if (DEBUG_VISBILITY) Log.v(
2173 TAG, "Making visible and scheduling visibility: " + r);
2174 try {
2175 mWindowManager.setAppVisibility(r, true);
2176 r.app.thread.scheduleWindowVisibility(r, true);
2177 r.stopFreezingScreenLocked(false);
2178 } catch (Exception e) {
2179 // Just skip on any failure; we'll make it
2180 // visible when it next restarts.
2181 Log.w(TAG, "Exception thrown making visibile: "
2182 + r.intent.getComponent(), e);
2183 }
2184 }
2185 }
2186
2187 // Aggregate current change flags.
2188 configChanges |= r.configChangeFlags;
2189
2190 if (r.fullscreen) {
2191 // At this point, nothing else needs to be shown
2192 if (DEBUG_VISBILITY) Log.v(
2193 TAG, "Stopping: fullscreen at " + r);
2194 behindFullscreen = true;
2195 i--;
2196 break;
2197 }
2198 }
2199
2200 // Now for any activities that aren't visible to the user, make
2201 // sure they no longer are keeping the screen frozen.
2202 while (i >= 0) {
2203 r = (HistoryRecord)mHistory.get(i);
2204 if (DEBUG_VISBILITY) Log.v(
2205 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2206 + " state=" + r.state
2207 + " behindFullscreen=" + behindFullscreen);
2208 if (!r.finishing) {
2209 if (behindFullscreen) {
2210 if (r.visible) {
2211 if (DEBUG_VISBILITY) Log.v(
2212 TAG, "Making invisible: " + r);
2213 r.visible = false;
2214 try {
2215 mWindowManager.setAppVisibility(r, false);
2216 if ((r.state == ActivityState.STOPPING
2217 || r.state == ActivityState.STOPPED)
2218 && r.app != null && r.app.thread != null) {
2219 if (DEBUG_VISBILITY) Log.v(
2220 TAG, "Scheduling invisibility: " + r);
2221 r.app.thread.scheduleWindowVisibility(r, false);
2222 }
2223 } catch (Exception e) {
2224 // Just skip on any failure; we'll make it
2225 // visible when it next restarts.
2226 Log.w(TAG, "Exception thrown making hidden: "
2227 + r.intent.getComponent(), e);
2228 }
2229 } else {
2230 if (DEBUG_VISBILITY) Log.v(
2231 TAG, "Already invisible: " + r);
2232 }
2233 } else if (r.fullscreen) {
2234 if (DEBUG_VISBILITY) Log.v(
2235 TAG, "Now behindFullscreen: " + r);
2236 behindFullscreen = true;
2237 }
2238 }
2239 i--;
2240 }
2241 }
2242
2243 /**
2244 * Version of ensureActivitiesVisible that can easily be called anywhere.
2245 */
2246 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2247 int configChanges) {
2248 HistoryRecord r = topRunningActivityLocked(null);
2249 if (r != null) {
2250 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2251 }
2252 }
2253
2254 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2255 if (resumed) {
2256 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2257 } else {
2258 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2259 }
2260 }
2261
2262 /**
2263 * Ensure that the top activity in the stack is resumed.
2264 *
2265 * @param prev The previously resumed activity, for when in the process
2266 * of pausing; can be null to call from elsewhere.
2267 *
2268 * @return Returns true if something is being resumed, or false if
2269 * nothing happened.
2270 */
2271 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2272 // Find the first activity that is not finishing.
2273 HistoryRecord next = topRunningActivityLocked(null);
2274
2275 // Remember how we'll process this pause/resume situation, and ensure
2276 // that the state is reset however we wind up proceeding.
2277 final boolean userLeaving = mUserLeaving;
2278 mUserLeaving = false;
2279
2280 if (next == null) {
2281 // There are no more activities! Let's just start up the
2282 // Launcher...
2283 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2284 && mTopAction == null) {
2285 // We are running in factory test mode, but unable to find
2286 // the factory test app, so just sit around displaying the
2287 // error message and don't try to start anything.
2288 return false;
2289 }
2290 Intent intent = new Intent(
2291 mTopAction,
2292 mTopData != null ? Uri.parse(mTopData) : null);
2293 intent.setComponent(mTopComponent);
2294 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2295 intent.addCategory(Intent.CATEGORY_HOME);
2296 }
2297 ActivityInfo aInfo =
2298 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002299 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 if (aInfo != null) {
2301 intent.setComponent(new ComponentName(
2302 aInfo.applicationInfo.packageName, aInfo.name));
2303 // Don't do this if the home app is currently being
2304 // instrumented.
2305 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2306 aInfo.applicationInfo.uid);
2307 if (app == null || app.instrumentationClass == null) {
2308 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2309 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002310 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 }
2312 }
2313 return true;
2314 }
2315
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002316 next.delayedResume = false;
2317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002318 // If the top activity is the resumed one, nothing to do.
2319 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2320 // Make sure we have executed any pending transitions, since there
2321 // should be nothing left to do at this point.
2322 mWindowManager.executeAppTransition();
2323 return false;
2324 }
2325
2326 // If we are sleeping, and there is no resumed activity, and the top
2327 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002328 if ((mSleeping || mShuttingDown)
2329 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002330 // Make sure we have executed any pending transitions, since there
2331 // should be nothing left to do at this point.
2332 mWindowManager.executeAppTransition();
2333 return false;
2334 }
2335
2336 // The activity may be waiting for stop, but that is no longer
2337 // appropriate for it.
2338 mStoppingActivities.remove(next);
2339 mWaitingVisibleActivities.remove(next);
2340
2341 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2342
2343 // If we are currently pausing an activity, then don't do anything
2344 // until that is done.
2345 if (mPausingActivity != null) {
2346 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2347 return false;
2348 }
2349
2350 // We need to start pausing the current activity so the top one
2351 // can be resumed...
2352 if (mResumedActivity != null) {
2353 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2354 startPausingLocked(userLeaving, false);
2355 return true;
2356 }
2357
2358 if (prev != null && prev != next) {
2359 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2360 prev.waitingVisible = true;
2361 mWaitingVisibleActivities.add(prev);
2362 if (DEBUG_SWITCH) Log.v(
2363 TAG, "Resuming top, waiting visible to hide: " + prev);
2364 } else {
2365 // The next activity is already visible, so hide the previous
2366 // activity's windows right now so we can show the new one ASAP.
2367 // We only do this if the previous is finishing, which should mean
2368 // it is on top of the one being resumed so hiding it quickly
2369 // is good. Otherwise, we want to do the normal route of allowing
2370 // the resumed activity to be shown so we can decide if the
2371 // previous should actually be hidden depending on whether the
2372 // new one is found to be full-screen or not.
2373 if (prev.finishing) {
2374 mWindowManager.setAppVisibility(prev, false);
2375 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2376 + prev + ", waitingVisible="
2377 + (prev != null ? prev.waitingVisible : null)
2378 + ", nowVisible=" + next.nowVisible);
2379 } else {
2380 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2381 + prev + ", waitingVisible="
2382 + (prev != null ? prev.waitingVisible : null)
2383 + ", nowVisible=" + next.nowVisible);
2384 }
2385 }
2386 }
2387
2388 // We are starting up the next activity, so tell the window manager
2389 // that the previous one will be hidden soon. This way it can know
2390 // to ignore it when computing the desired screen orientation.
2391 if (prev != null) {
2392 if (prev.finishing) {
2393 if (DEBUG_TRANSITION) Log.v(TAG,
2394 "Prepare close transition: prev=" + prev);
2395 mWindowManager.prepareAppTransition(prev.task == next.task
2396 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2397 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2398 mWindowManager.setAppWillBeHidden(prev);
2399 mWindowManager.setAppVisibility(prev, false);
2400 } else {
2401 if (DEBUG_TRANSITION) Log.v(TAG,
2402 "Prepare open transition: prev=" + prev);
2403 mWindowManager.prepareAppTransition(prev.task == next.task
2404 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2405 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2406 }
2407 if (false) {
2408 mWindowManager.setAppWillBeHidden(prev);
2409 mWindowManager.setAppVisibility(prev, false);
2410 }
2411 } else if (mHistory.size() > 1) {
2412 if (DEBUG_TRANSITION) Log.v(TAG,
2413 "Prepare open transition: no previous");
2414 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2415 }
2416
2417 if (next.app != null && next.app.thread != null) {
2418 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2419
2420 // This activity is now becoming visible.
2421 mWindowManager.setAppVisibility(next, true);
2422
2423 HistoryRecord lastResumedActivity = mResumedActivity;
2424 ActivityState lastState = next.state;
2425
2426 updateCpuStats();
2427
2428 next.state = ActivityState.RESUMED;
2429 mResumedActivity = next;
2430 next.task.touchActiveTime();
2431 updateLRUListLocked(next.app, true);
2432 updateLRUListLocked(next);
2433
2434 // Have the window manager re-evaluate the orientation of
2435 // the screen based on the new activity order.
2436 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002437 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002438 next.mayFreezeScreenLocked(next.app) ? next : null);
2439 if (config != null) {
2440 next.frozenBeforeDestroy = true;
2441 }
2442 if (!updateConfigurationLocked(config, next)) {
2443 // The configuration update wasn't able to keep the existing
2444 // instance of the activity, and instead started a new one.
2445 // We should be all done, but let's just make sure our activity
2446 // is still at the top and schedule another run if something
2447 // weird happened.
2448 HistoryRecord nextNext = topRunningActivityLocked(null);
2449 if (DEBUG_SWITCH) Log.i(TAG,
2450 "Activity config changed during resume: " + next
2451 + ", new next: " + nextNext);
2452 if (nextNext != next) {
2453 // Do over!
2454 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2455 }
2456 mWindowManager.executeAppTransition();
2457 return true;
2458 }
2459
2460 try {
2461 // Deliver all pending results.
2462 ArrayList a = next.results;
2463 if (a != null) {
2464 final int N = a.size();
2465 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002466 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 TAG, "Delivering results to " + next
2468 + ": " + a);
2469 next.app.thread.scheduleSendResult(next, a);
2470 }
2471 }
2472
2473 if (next.newIntents != null) {
2474 next.app.thread.scheduleNewIntent(next.newIntents, next);
2475 }
2476
2477 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2478 System.identityHashCode(next),
2479 next.task.taskId, next.shortComponentName);
2480 updateUsageStats(next, true);
2481
2482 next.app.thread.scheduleResumeActivity(next,
2483 isNextTransitionForward());
2484 pauseIfSleepingLocked();
2485
2486 } catch (Exception e) {
2487 // Whoops, need to restart this activity!
2488 next.state = lastState;
2489 mResumedActivity = lastResumedActivity;
2490 if (Config.LOGD) Log.d(TAG,
2491 "Restarting because process died: " + next);
2492 if (!next.hasBeenLaunched) {
2493 next.hasBeenLaunched = true;
2494 } else {
2495 if (SHOW_APP_STARTING_ICON) {
2496 mWindowManager.setAppStartingWindow(
2497 next, next.packageName, next.theme,
2498 next.nonLocalizedLabel,
2499 next.labelRes, next.icon, null, true);
2500 }
2501 }
2502 startSpecificActivityLocked(next, true, false);
2503 return true;
2504 }
2505
2506 // From this point on, if something goes wrong there is no way
2507 // to recover the activity.
2508 try {
2509 next.visible = true;
2510 completeResumeLocked(next);
2511 } catch (Exception e) {
2512 // If any exception gets thrown, toss away this
2513 // activity and try the next one.
2514 Log.w(TAG, "Exception thrown during resume of " + next, e);
2515 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2516 "resume-exception");
2517 return true;
2518 }
2519
2520 // Didn't need to use the icicle, and it is now out of date.
2521 next.icicle = null;
2522 next.haveState = false;
2523 next.stopped = false;
2524
2525 } else {
2526 // Whoops, need to restart this activity!
2527 if (!next.hasBeenLaunched) {
2528 next.hasBeenLaunched = true;
2529 } else {
2530 if (SHOW_APP_STARTING_ICON) {
2531 mWindowManager.setAppStartingWindow(
2532 next, next.packageName, next.theme,
2533 next.nonLocalizedLabel,
2534 next.labelRes, next.icon, null, true);
2535 }
2536 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2537 }
2538 startSpecificActivityLocked(next, true, true);
2539 }
2540
2541 return true;
2542 }
2543
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002544 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2545 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 final int NH = mHistory.size();
2547
2548 int addPos = -1;
2549
2550 if (!newTask) {
2551 // If starting in an existing task, find where that is...
2552 HistoryRecord next = null;
2553 boolean startIt = true;
2554 for (int i = NH-1; i >= 0; i--) {
2555 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2556 if (p.finishing) {
2557 continue;
2558 }
2559 if (p.task == r.task) {
2560 // Here it is! Now, if this is not yet visible to the
2561 // user, then just add it without starting; it will
2562 // get started when the user navigates back to it.
2563 addPos = i+1;
2564 if (!startIt) {
2565 mHistory.add(addPos, r);
2566 r.inHistory = true;
2567 r.task.numActivities++;
2568 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2569 r.info.screenOrientation, r.fullscreen);
2570 if (VALIDATE_TOKENS) {
2571 mWindowManager.validateAppTokens(mHistory);
2572 }
2573 return;
2574 }
2575 break;
2576 }
2577 if (p.fullscreen) {
2578 startIt = false;
2579 }
2580 next = p;
2581 }
2582 }
2583
2584 // Place a new activity at top of stack, so it is next to interact
2585 // with the user.
2586 if (addPos < 0) {
2587 addPos = mHistory.size();
2588 }
2589
2590 // If we are not placing the new activity frontmost, we do not want
2591 // to deliver the onUserLeaving callback to the actual frontmost
2592 // activity
2593 if (addPos < NH) {
2594 mUserLeaving = false;
2595 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2596 }
2597
2598 // Slot the activity into the history stack and proceed
2599 mHistory.add(addPos, r);
2600 r.inHistory = true;
2601 r.frontOfTask = newTask;
2602 r.task.numActivities++;
2603 if (NH > 0) {
2604 // We want to show the starting preview window if we are
2605 // switching to a new task, or the next activity's process is
2606 // not currently running.
2607 boolean showStartingIcon = newTask;
2608 ProcessRecord proc = r.app;
2609 if (proc == null) {
2610 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2611 }
2612 if (proc == null || proc.thread == null) {
2613 showStartingIcon = true;
2614 }
2615 if (DEBUG_TRANSITION) Log.v(TAG,
2616 "Prepare open transition: starting " + r);
2617 mWindowManager.prepareAppTransition(newTask
2618 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2619 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2620 mWindowManager.addAppToken(
2621 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2622 boolean doShow = true;
2623 if (newTask) {
2624 // Even though this activity is starting fresh, we still need
2625 // to reset it to make sure we apply affinities to move any
2626 // existing activities from other tasks in to it.
2627 // If the caller has requested that the target task be
2628 // reset, then do so.
2629 if ((r.intent.getFlags()
2630 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2631 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002632 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002633 }
2634 }
2635 if (SHOW_APP_STARTING_ICON && doShow) {
2636 // Figure out if we are transitioning from another activity that is
2637 // "has the same starting icon" as the next one. This allows the
2638 // window manager to keep the previous window it had previously
2639 // created, if it still had one.
2640 HistoryRecord prev = mResumedActivity;
2641 if (prev != null) {
2642 // We don't want to reuse the previous starting preview if:
2643 // (1) The current activity is in a different task.
2644 if (prev.task != r.task) prev = null;
2645 // (2) The current activity is already displayed.
2646 else if (prev.nowVisible) prev = null;
2647 }
2648 mWindowManager.setAppStartingWindow(
2649 r, r.packageName, r.theme, r.nonLocalizedLabel,
2650 r.labelRes, r.icon, prev, showStartingIcon);
2651 }
2652 } else {
2653 // If this is the first activity, don't do any fancy animations,
2654 // because there is nothing for it to animate on top of.
2655 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2656 r.info.screenOrientation, r.fullscreen);
2657 }
2658 if (VALIDATE_TOKENS) {
2659 mWindowManager.validateAppTokens(mHistory);
2660 }
2661
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002662 if (doResume) {
2663 resumeTopActivityLocked(null);
2664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002665 }
2666
2667 /**
2668 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002669 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2670 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 * an instance of that activity in the stack and, if found, finish all
2672 * activities on top of it and return the instance.
2673 *
2674 * @param newR Description of the new activity being started.
2675 * @return Returns the old activity that should be continue to be used,
2676 * or null if none was found.
2677 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002678 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679 HistoryRecord newR, boolean doClear) {
2680 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002681
2682 // First find the requested task.
2683 while (i > 0) {
2684 i--;
2685 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2686 if (r.task.taskId == taskId) {
2687 i++;
2688 break;
2689 }
2690 }
2691
2692 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002693 while (i > 0) {
2694 i--;
2695 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2696 if (r.finishing) {
2697 continue;
2698 }
2699 if (r.task.taskId != taskId) {
2700 return null;
2701 }
2702 if (r.realActivity.equals(newR.realActivity)) {
2703 // Here it is! Now finish everything in front...
2704 HistoryRecord ret = r;
2705 if (doClear) {
2706 while (i < (mHistory.size()-1)) {
2707 i++;
2708 r = (HistoryRecord)mHistory.get(i);
2709 if (r.finishing) {
2710 continue;
2711 }
2712 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2713 null, "clear")) {
2714 i--;
2715 }
2716 }
2717 }
2718
2719 // Finally, if this is a normal launch mode (that is, not
2720 // expecting onNewIntent()), then we will finish the current
2721 // instance of the activity so a new fresh one can be started.
2722 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2723 if (!ret.finishing) {
2724 int index = indexOfTokenLocked(ret, false);
2725 if (index >= 0) {
2726 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2727 null, "clear");
2728 }
2729 return null;
2730 }
2731 }
2732
2733 return ret;
2734 }
2735 }
2736
2737 return null;
2738 }
2739
2740 /**
2741 * Find the activity in the history stack within the given task. Returns
2742 * the index within the history at which it's found, or < 0 if not found.
2743 */
2744 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2745 int i = mHistory.size();
2746 while (i > 0) {
2747 i--;
2748 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2749 if (candidate.task.taskId != task) {
2750 break;
2751 }
2752 if (candidate.realActivity.equals(r.realActivity)) {
2753 return i;
2754 }
2755 }
2756
2757 return -1;
2758 }
2759
2760 /**
2761 * Reorder the history stack so that the activity at the given index is
2762 * brought to the front.
2763 */
2764 private final HistoryRecord moveActivityToFrontLocked(int where) {
2765 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2766 int top = mHistory.size();
2767 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2768 mHistory.add(top, newTop);
2769 oldTop.frontOfTask = false;
2770 newTop.frontOfTask = true;
2771 return newTop;
2772 }
2773
2774 /**
2775 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2776 * method will be called at the proper time.
2777 */
2778 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2779 boolean sent = false;
2780 if (r.state == ActivityState.RESUMED
2781 && r.app != null && r.app.thread != null) {
2782 try {
2783 ArrayList<Intent> ar = new ArrayList<Intent>();
2784 ar.add(new Intent(intent));
2785 r.app.thread.scheduleNewIntent(ar, r);
2786 sent = true;
2787 } catch (Exception e) {
2788 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2789 }
2790 }
2791 if (!sent) {
2792 r.addNewIntentLocked(new Intent(intent));
2793 }
2794 }
2795
2796 private final void logStartActivity(int tag, HistoryRecord r,
2797 TaskRecord task) {
2798 EventLog.writeEvent(tag,
2799 System.identityHashCode(r), task.taskId,
2800 r.shortComponentName, r.intent.getAction(),
2801 r.intent.getType(), r.intent.getDataString(),
2802 r.intent.getFlags());
2803 }
2804
2805 private final int startActivityLocked(IApplicationThread caller,
2806 Intent intent, String resolvedType,
2807 Uri[] grantedUriPermissions,
2808 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2809 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002810 int callingPid, int callingUid, boolean onlyIfNeeded,
2811 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002812 Log.i(TAG, "Starting activity: " + intent);
2813
2814 HistoryRecord sourceRecord = null;
2815 HistoryRecord resultRecord = null;
2816 if (resultTo != null) {
2817 int index = indexOfTokenLocked(resultTo, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002818 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002819 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2820 if (index >= 0) {
2821 sourceRecord = (HistoryRecord)mHistory.get(index);
2822 if (requestCode >= 0 && !sourceRecord.finishing) {
2823 resultRecord = sourceRecord;
2824 }
2825 }
2826 }
2827
2828 int launchFlags = intent.getFlags();
2829
2830 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2831 && sourceRecord != null) {
2832 // Transfer the result target from the source activity to the new
2833 // one being started, including any failures.
2834 if (requestCode >= 0) {
2835 return START_FORWARD_AND_REQUEST_CONFLICT;
2836 }
2837 resultRecord = sourceRecord.resultTo;
2838 resultWho = sourceRecord.resultWho;
2839 requestCode = sourceRecord.requestCode;
2840 sourceRecord.resultTo = null;
2841 if (resultRecord != null) {
2842 resultRecord.removeResultsLocked(
2843 sourceRecord, resultWho, requestCode);
2844 }
2845 }
2846
2847 int err = START_SUCCESS;
2848
2849 if (intent.getComponent() == null) {
2850 // We couldn't find a class that can handle the given Intent.
2851 // That's the end of that!
2852 err = START_INTENT_NOT_RESOLVED;
2853 }
2854
2855 if (err == START_SUCCESS && aInfo == null) {
2856 // We couldn't find the specific class specified in the Intent.
2857 // Also the end of the line.
2858 err = START_CLASS_NOT_FOUND;
2859 }
2860
2861 ProcessRecord callerApp = null;
2862 if (err == START_SUCCESS && caller != null) {
2863 callerApp = getRecordForAppLocked(caller);
2864 if (callerApp != null) {
2865 callingPid = callerApp.pid;
2866 callingUid = callerApp.info.uid;
2867 } else {
2868 Log.w(TAG, "Unable to find app for caller " + caller
2869 + " (pid=" + callingPid + ") when starting: "
2870 + intent.toString());
2871 err = START_PERMISSION_DENIED;
2872 }
2873 }
2874
2875 if (err != START_SUCCESS) {
2876 if (resultRecord != null) {
2877 sendActivityResultLocked(-1,
2878 resultRecord, resultWho, requestCode,
2879 Activity.RESULT_CANCELED, null);
2880 }
2881 return err;
2882 }
2883
2884 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2885 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2886 if (perm != PackageManager.PERMISSION_GRANTED) {
2887 if (resultRecord != null) {
2888 sendActivityResultLocked(-1,
2889 resultRecord, resultWho, requestCode,
2890 Activity.RESULT_CANCELED, null);
2891 }
2892 String msg = "Permission Denial: starting " + intent.toString()
2893 + " from " + callerApp + " (pid=" + callingPid
2894 + ", uid=" + callingUid + ")"
2895 + " requires " + aInfo.permission;
2896 Log.w(TAG, msg);
2897 throw new SecurityException(msg);
2898 }
2899
2900 if (mWatcher != null) {
2901 boolean abort = false;
2902 try {
2903 // The Intent we give to the watcher has the extra data
2904 // stripped off, since it can contain private information.
2905 Intent watchIntent = intent.cloneFilter();
2906 abort = !mWatcher.activityStarting(watchIntent,
2907 aInfo.applicationInfo.packageName);
2908 } catch (RemoteException e) {
2909 mWatcher = null;
2910 }
2911
2912 if (abort) {
2913 if (resultRecord != null) {
2914 sendActivityResultLocked(-1,
2915 resultRecord, resultWho, requestCode,
2916 Activity.RESULT_CANCELED, null);
2917 }
2918 // We pretend to the caller that it was really started, but
2919 // they will just get a cancel result.
2920 return START_SUCCESS;
2921 }
2922 }
2923
2924 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
2925 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002926 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002927
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002928 if (mResumedActivity == null
2929 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2930 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2931 PendingActivityLaunch pal = new PendingActivityLaunch();
2932 pal.r = r;
2933 pal.sourceRecord = sourceRecord;
2934 pal.grantedUriPermissions = grantedUriPermissions;
2935 pal.grantedMode = grantedMode;
2936 pal.onlyIfNeeded = onlyIfNeeded;
2937 mPendingActivityLaunches.add(pal);
2938 return START_SWITCHES_CANCELED;
2939 }
2940 }
2941
2942 if (mDidAppSwitch) {
2943 // This is the second allowed switch since we stopped switches,
2944 // so now just generally allow switches. Use case: user presses
2945 // home (switches disabled, switch to home, mDidAppSwitch now true);
2946 // user taps a home icon (coming from home so allowed, we hit here
2947 // and now allow anyone to switch again).
2948 mAppSwitchesAllowedTime = 0;
2949 } else {
2950 mDidAppSwitch = true;
2951 }
2952
2953 doPendingActivityLaunchesLocked(false);
2954
2955 return startActivityUncheckedLocked(r, sourceRecord,
2956 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
2957 }
2958
2959 private final void doPendingActivityLaunchesLocked(boolean doResume) {
2960 final int N = mPendingActivityLaunches.size();
2961 if (N <= 0) {
2962 return;
2963 }
2964 for (int i=0; i<N; i++) {
2965 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
2966 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
2967 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
2968 doResume && i == (N-1));
2969 }
2970 mPendingActivityLaunches.clear();
2971 }
2972
2973 private final int startActivityUncheckedLocked(HistoryRecord r,
2974 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
2975 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
2976 final Intent intent = r.intent;
2977 final int callingUid = r.launchedFromUid;
2978
2979 int launchFlags = intent.getFlags();
2980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002981 // We'll invoke onUserLeaving before onPause only if the launching
2982 // activity did not explicitly state that this is an automated launch.
2983 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
2984 if (DEBUG_USER_LEAVING) Log.v(TAG,
2985 "startActivity() => mUserLeaving=" + mUserLeaving);
2986
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002987 // If the caller has asked not to resume at this point, we make note
2988 // of this in the record so that we can skip it when trying to find
2989 // the top running activity.
2990 if (!doResume) {
2991 r.delayedResume = true;
2992 }
2993
2994 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
2995 != 0 ? r : null;
2996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002997 // If the onlyIfNeeded flag is set, then we can do this if the activity
2998 // being launched is the same as the one making the call... or, as
2999 // a special case, if we do not know the caller then we count the
3000 // current top activity as the caller.
3001 if (onlyIfNeeded) {
3002 HistoryRecord checkedCaller = sourceRecord;
3003 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003004 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003005 }
3006 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3007 // Caller is not the same as launcher, so always needed.
3008 onlyIfNeeded = false;
3009 }
3010 }
3011
3012 if (grantedUriPermissions != null && callingUid > 0) {
3013 for (int i=0; i<grantedUriPermissions.length; i++) {
3014 grantUriPermissionLocked(callingUid, r.packageName,
3015 grantedUriPermissions[i], grantedMode, r);
3016 }
3017 }
3018
3019 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3020 intent, r);
3021
3022 if (sourceRecord == null) {
3023 // This activity is not being started from another... in this
3024 // case we -always- start a new task.
3025 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3026 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3027 + intent);
3028 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3029 }
3030 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3031 // The original activity who is starting us is running as a single
3032 // instance... this new activity it is starting must go on its
3033 // own task.
3034 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3035 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3036 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3037 // The activity being started is a single instance... it always
3038 // gets launched into its own task.
3039 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3040 }
3041
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003042 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 // For whatever reason this activity is being launched into a new
3044 // task... yet the caller has requested a result back. Well, that
3045 // is pretty messed up, so instead immediately send back a cancel
3046 // and let the new task continue launched as normal without a
3047 // dependency on its originator.
3048 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3049 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003050 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 Activity.RESULT_CANCELED, null);
3052 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003053 }
3054
3055 boolean addingToTask = false;
3056 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3057 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3058 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3059 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3060 // If bring to front is requested, and no result is requested, and
3061 // we can find a task that was started with this same
3062 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003063 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003064 // See if there is a task to bring to the front. If this is
3065 // a SINGLE_INSTANCE activity, there can be one and only one
3066 // instance of it in the history, and it is always in its own
3067 // unique task, so we do a special search.
3068 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3069 ? findTaskLocked(intent, r.info)
3070 : findActivityLocked(intent, r.info);
3071 if (taskTop != null) {
3072 if (taskTop.task.intent == null) {
3073 // This task was started because of movement of
3074 // the activity based on affinity... now that we
3075 // are actually launching it, we can assign the
3076 // base intent.
3077 taskTop.task.setIntent(intent, r.info);
3078 }
3079 // If the target task is not in the front, then we need
3080 // to bring it to the front... except... well, with
3081 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3082 // to have the same behavior as if a new instance was
3083 // being started, which means not bringing it to the front
3084 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003085 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003086 if (curTop.task != taskTop.task) {
3087 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3088 boolean callerAtFront = sourceRecord == null
3089 || curTop.task == sourceRecord.task;
3090 if (callerAtFront) {
3091 // We really do want to push this one into the
3092 // user's face, right now.
3093 moveTaskToFrontLocked(taskTop.task);
3094 }
3095 }
3096 // If the caller has requested that the target task be
3097 // reset, then do so.
3098 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3099 taskTop = resetTaskIfNeededLocked(taskTop, r);
3100 }
3101 if (onlyIfNeeded) {
3102 // We don't need to start a new activity, and
3103 // the client said not to do anything if that
3104 // is the case, so this is it! And for paranoia, make
3105 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003106 if (doResume) {
3107 resumeTopActivityLocked(null);
3108 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003109 return START_RETURN_INTENT_TO_CALLER;
3110 }
3111 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3112 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3113 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3114 // In this situation we want to remove all activities
3115 // from the task up to the one being started. In most
3116 // cases this means we are resetting the task to its
3117 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003118 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003119 taskTop.task.taskId, r, true);
3120 if (top != null) {
3121 if (top.frontOfTask) {
3122 // Activity aliases may mean we use different
3123 // intents for the top activity, so make sure
3124 // the task now has the identity of the new
3125 // intent.
3126 top.task.setIntent(r.intent, r.info);
3127 }
3128 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3129 deliverNewIntentLocked(top, r.intent);
3130 } else {
3131 // A special case: we need to
3132 // start the activity because it is not currently
3133 // running, and the caller has asked to clear the
3134 // current task to have this activity at the top.
3135 addingToTask = true;
3136 // Now pretend like this activity is being started
3137 // by the top of its task, so it is put in the
3138 // right place.
3139 sourceRecord = taskTop;
3140 }
3141 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3142 // In this case the top activity on the task is the
3143 // same as the one being launched, so we take that
3144 // as a request to bring the task to the foreground.
3145 // If the top activity in the task is the root
3146 // activity, deliver this new intent to it if it
3147 // desires.
3148 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3149 && taskTop.realActivity.equals(r.realActivity)) {
3150 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3151 if (taskTop.frontOfTask) {
3152 taskTop.task.setIntent(r.intent, r.info);
3153 }
3154 deliverNewIntentLocked(taskTop, r.intent);
3155 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3156 // In this case we are launching the root activity
3157 // of the task, but with a different intent. We
3158 // should start a new instance on top.
3159 addingToTask = true;
3160 sourceRecord = taskTop;
3161 }
3162 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3163 // In this case an activity is being launched in to an
3164 // existing task, without resetting that task. This
3165 // is typically the situation of launching an activity
3166 // from a notification or shortcut. We want to place
3167 // the new activity on top of the current task.
3168 addingToTask = true;
3169 sourceRecord = taskTop;
3170 } else if (!taskTop.task.rootWasReset) {
3171 // In this case we are launching in to an existing task
3172 // that has not yet been started from its front door.
3173 // The current task has been brought to the front.
3174 // Ideally, we'd probably like to place this new task
3175 // at the bottom of its stack, but that's a little hard
3176 // to do with the current organization of the code so
3177 // for now we'll just drop it.
3178 taskTop.task.setIntent(r.intent, r.info);
3179 }
3180 if (!addingToTask) {
3181 // We didn't do anything... but it was needed (a.k.a., client
3182 // don't use that intent!) And for paranoia, make
3183 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003184 if (doResume) {
3185 resumeTopActivityLocked(null);
3186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 return START_TASK_TO_FRONT;
3188 }
3189 }
3190 }
3191 }
3192
3193 //String uri = r.intent.toURI();
3194 //Intent intent2 = new Intent(uri);
3195 //Log.i(TAG, "Given intent: " + r.intent);
3196 //Log.i(TAG, "URI is: " + uri);
3197 //Log.i(TAG, "To intent: " + intent2);
3198
3199 if (r.packageName != null) {
3200 // If the activity being launched is the same as the one currently
3201 // at the top, then we need to check if it should only be launched
3202 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003203 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3204 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003205 if (top.realActivity.equals(r.realActivity)) {
3206 if (top.app != null && top.app.thread != null) {
3207 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3208 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3209 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3210 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3211 // For paranoia, make sure we have correctly
3212 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003213 if (doResume) {
3214 resumeTopActivityLocked(null);
3215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003216 if (onlyIfNeeded) {
3217 // We don't need to start a new activity, and
3218 // the client said not to do anything if that
3219 // is the case, so this is it!
3220 return START_RETURN_INTENT_TO_CALLER;
3221 }
3222 deliverNewIntentLocked(top, r.intent);
3223 return START_DELIVERED_TO_TOP;
3224 }
3225 }
3226 }
3227 }
3228
3229 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003230 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003232 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 Activity.RESULT_CANCELED, null);
3234 }
3235 return START_CLASS_NOT_FOUND;
3236 }
3237
3238 boolean newTask = false;
3239
3240 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003241 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003242 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3243 // todo: should do better management of integers.
3244 mCurTask++;
3245 if (mCurTask <= 0) {
3246 mCurTask = 1;
3247 }
3248 r.task = new TaskRecord(mCurTask, r.info, intent,
3249 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3250 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3251 + " in new task " + r.task);
3252 newTask = true;
3253 addRecentTask(r.task);
3254
3255 } else if (sourceRecord != null) {
3256 if (!addingToTask &&
3257 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3258 // In this case, we are adding the activity to an existing
3259 // task, but the caller has asked to clear that task if the
3260 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003261 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 sourceRecord.task.taskId, r, true);
3263 if (top != null) {
3264 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3265 deliverNewIntentLocked(top, r.intent);
3266 // For paranoia, make sure we have correctly
3267 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003268 if (doResume) {
3269 resumeTopActivityLocked(null);
3270 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271 return START_DELIVERED_TO_TOP;
3272 }
3273 } else if (!addingToTask &&
3274 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3275 // In this case, we are launching an activity in our own task
3276 // that may already be running somewhere in the history, and
3277 // we want to shuffle it to the front of the stack if so.
3278 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3279 if (where >= 0) {
3280 HistoryRecord top = moveActivityToFrontLocked(where);
3281 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3282 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003283 if (doResume) {
3284 resumeTopActivityLocked(null);
3285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 return START_DELIVERED_TO_TOP;
3287 }
3288 }
3289 // An existing activity is starting this new activity, so we want
3290 // to keep the new one in the same task as the one that is starting
3291 // it.
3292 r.task = sourceRecord.task;
3293 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3294 + " in existing task " + r.task);
3295
3296 } else {
3297 // This not being started from an existing activity, and not part
3298 // of a new task... just put it in the top task, though these days
3299 // this case should never happen.
3300 final int N = mHistory.size();
3301 HistoryRecord prev =
3302 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3303 r.task = prev != null
3304 ? prev.task
3305 : new TaskRecord(mCurTask, r.info, intent,
3306 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3307 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3308 + " in new guessed " + r.task);
3309 }
3310 if (newTask) {
3311 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3312 }
3313 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003314 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 return START_SUCCESS;
3316 }
3317
3318 public final int startActivity(IApplicationThread caller,
3319 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3320 int grantedMode, IBinder resultTo,
3321 String resultWho, int requestCode, boolean onlyIfNeeded,
3322 boolean debug) {
3323 // Refuse possible leaked file descriptors
3324 if (intent != null && intent.hasFileDescriptors()) {
3325 throw new IllegalArgumentException("File descriptors passed in Intent");
3326 }
3327
The Android Open Source Project4df24232009-03-05 14:34:35 -08003328 final boolean componentSpecified = intent.getComponent() != null;
3329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003330 // Don't modify the client's object!
3331 intent = new Intent(intent);
3332
3333 // Collect information about the target of the Intent.
3334 // Must do this before locking, because resolving the intent
3335 // may require launching a process to run its content provider.
3336 ActivityInfo aInfo;
3337 try {
3338 ResolveInfo rInfo =
3339 ActivityThread.getPackageManager().resolveIntent(
3340 intent, resolvedType,
3341 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003342 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 aInfo = rInfo != null ? rInfo.activityInfo : null;
3344 } catch (RemoteException e) {
3345 aInfo = null;
3346 }
3347
3348 if (aInfo != null) {
3349 // Store the found target back into the intent, because now that
3350 // we have it we never want to do this again. For example, if the
3351 // user navigates back to this point in the history, we should
3352 // always restart the exact same activity.
3353 intent.setComponent(new ComponentName(
3354 aInfo.applicationInfo.packageName, aInfo.name));
3355
3356 // Don't debug things in the system process
3357 if (debug) {
3358 if (!aInfo.processName.equals("system")) {
3359 setDebugApp(aInfo.processName, true, false);
3360 }
3361 }
3362 }
3363
3364 synchronized(this) {
3365 final long origId = Binder.clearCallingIdentity();
3366 int res = startActivityLocked(caller, intent, resolvedType,
3367 grantedUriPermissions, grantedMode, aInfo,
3368 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003369 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003370 Binder.restoreCallingIdentity(origId);
3371 return res;
3372 }
3373 }
3374
3375 public boolean startNextMatchingActivity(IBinder callingActivity,
3376 Intent intent) {
3377 // Refuse possible leaked file descriptors
3378 if (intent != null && intent.hasFileDescriptors() == true) {
3379 throw new IllegalArgumentException("File descriptors passed in Intent");
3380 }
3381
3382 synchronized (this) {
3383 int index = indexOfTokenLocked(callingActivity, false);
3384 if (index < 0) {
3385 return false;
3386 }
3387 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3388 if (r.app == null || r.app.thread == null) {
3389 // The caller is not running... d'oh!
3390 return false;
3391 }
3392 intent = new Intent(intent);
3393 // The caller is not allowed to change the data.
3394 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3395 // And we are resetting to find the next component...
3396 intent.setComponent(null);
3397
3398 ActivityInfo aInfo = null;
3399 try {
3400 List<ResolveInfo> resolves =
3401 ActivityThread.getPackageManager().queryIntentActivities(
3402 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003403 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003404
3405 // Look for the original activity in the list...
3406 final int N = resolves != null ? resolves.size() : 0;
3407 for (int i=0; i<N; i++) {
3408 ResolveInfo rInfo = resolves.get(i);
3409 if (rInfo.activityInfo.packageName.equals(r.packageName)
3410 && rInfo.activityInfo.name.equals(r.info.name)) {
3411 // We found the current one... the next matching is
3412 // after it.
3413 i++;
3414 if (i<N) {
3415 aInfo = resolves.get(i).activityInfo;
3416 }
3417 break;
3418 }
3419 }
3420 } catch (RemoteException e) {
3421 }
3422
3423 if (aInfo == null) {
3424 // Nobody who is next!
3425 return false;
3426 }
3427
3428 intent.setComponent(new ComponentName(
3429 aInfo.applicationInfo.packageName, aInfo.name));
3430 intent.setFlags(intent.getFlags()&~(
3431 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3432 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3433 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3434 Intent.FLAG_ACTIVITY_NEW_TASK));
3435
3436 // Okay now we need to start the new activity, replacing the
3437 // currently running activity. This is a little tricky because
3438 // we want to start the new one as if the current one is finished,
3439 // but not finish the current one first so that there is no flicker.
3440 // And thus...
3441 final boolean wasFinishing = r.finishing;
3442 r.finishing = true;
3443
3444 // Propagate reply information over to the new activity.
3445 final HistoryRecord resultTo = r.resultTo;
3446 final String resultWho = r.resultWho;
3447 final int requestCode = r.requestCode;
3448 r.resultTo = null;
3449 if (resultTo != null) {
3450 resultTo.removeResultsLocked(r, resultWho, requestCode);
3451 }
3452
3453 final long origId = Binder.clearCallingIdentity();
3454 // XXX we are not dealing with propagating grantedUriPermissions...
3455 // those are not yet exposed to user code, so there is no need.
3456 int res = startActivityLocked(r.app.thread, intent,
3457 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003458 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 Binder.restoreCallingIdentity(origId);
3460
3461 r.finishing = wasFinishing;
3462 if (res != START_SUCCESS) {
3463 return false;
3464 }
3465 return true;
3466 }
3467 }
3468
3469 final int startActivityInPackage(int uid,
3470 Intent intent, String resolvedType, IBinder resultTo,
3471 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003472 final boolean componentSpecified = intent.getComponent() != null;
3473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 // Don't modify the client's object!
3475 intent = new Intent(intent);
3476
3477 // Collect information about the target of the Intent.
3478 // Must do this before locking, because resolving the intent
3479 // may require launching a process to run its content provider.
3480 ActivityInfo aInfo;
3481 try {
3482 ResolveInfo rInfo =
3483 ActivityThread.getPackageManager().resolveIntent(
3484 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003485 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 aInfo = rInfo != null ? rInfo.activityInfo : null;
3487 } catch (RemoteException e) {
3488 aInfo = null;
3489 }
3490
3491 if (aInfo != null) {
3492 // Store the found target back into the intent, because now that
3493 // we have it we never want to do this again. For example, if the
3494 // user navigates back to this point in the history, we should
3495 // always restart the exact same activity.
3496 intent.setComponent(new ComponentName(
3497 aInfo.applicationInfo.packageName, aInfo.name));
3498 }
3499
3500 synchronized(this) {
3501 return startActivityLocked(null, intent, resolvedType,
3502 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003503 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504 }
3505 }
3506
3507 private final void addRecentTask(TaskRecord task) {
3508 // Remove any existing entries that are the same kind of task.
3509 int N = mRecentTasks.size();
3510 for (int i=0; i<N; i++) {
3511 TaskRecord tr = mRecentTasks.get(i);
3512 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3513 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3514 mRecentTasks.remove(i);
3515 i--;
3516 N--;
3517 if (task.intent == null) {
3518 // If the new recent task we are adding is not fully
3519 // specified, then replace it with the existing recent task.
3520 task = tr;
3521 }
3522 }
3523 }
3524 if (N >= MAX_RECENT_TASKS) {
3525 mRecentTasks.remove(N-1);
3526 }
3527 mRecentTasks.add(0, task);
3528 }
3529
3530 public void setRequestedOrientation(IBinder token,
3531 int requestedOrientation) {
3532 synchronized (this) {
3533 int index = indexOfTokenLocked(token, false);
3534 if (index < 0) {
3535 return;
3536 }
3537 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3538 final long origId = Binder.clearCallingIdentity();
3539 mWindowManager.setAppOrientation(r, requestedOrientation);
3540 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003541 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 r.mayFreezeScreenLocked(r.app) ? r : null);
3543 if (config != null) {
3544 r.frozenBeforeDestroy = true;
3545 if (!updateConfigurationLocked(config, r)) {
3546 resumeTopActivityLocked(null);
3547 }
3548 }
3549 Binder.restoreCallingIdentity(origId);
3550 }
3551 }
3552
3553 public int getRequestedOrientation(IBinder token) {
3554 synchronized (this) {
3555 int index = indexOfTokenLocked(token, false);
3556 if (index < 0) {
3557 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3558 }
3559 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3560 return mWindowManager.getAppOrientation(r);
3561 }
3562 }
3563
3564 private final void stopActivityLocked(HistoryRecord r) {
3565 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3566 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3567 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3568 if (!r.finishing) {
3569 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3570 "no-history");
3571 }
3572 } else if (r.app != null && r.app.thread != null) {
3573 if (mFocusedActivity == r) {
3574 setFocusedActivityLocked(topRunningActivityLocked(null));
3575 }
3576 r.resumeKeyDispatchingLocked();
3577 try {
3578 r.stopped = false;
3579 r.state = ActivityState.STOPPING;
3580 if (DEBUG_VISBILITY) Log.v(
3581 TAG, "Stopping visible=" + r.visible + " for " + r);
3582 if (!r.visible) {
3583 mWindowManager.setAppVisibility(r, false);
3584 }
3585 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3586 } catch (Exception e) {
3587 // Maybe just ignore exceptions here... if the process
3588 // has crashed, our death notification will clean things
3589 // up.
3590 Log.w(TAG, "Exception thrown during pause", e);
3591 // Just in case, assume it to be stopped.
3592 r.stopped = true;
3593 r.state = ActivityState.STOPPED;
3594 if (r.configDestroy) {
3595 destroyActivityLocked(r, true);
3596 }
3597 }
3598 }
3599 }
3600
3601 /**
3602 * @return Returns true if the activity is being finished, false if for
3603 * some reason it is being left as-is.
3604 */
3605 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3606 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003607 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003608 TAG, "Finishing activity: token=" + token
3609 + ", result=" + resultCode + ", data=" + resultData);
3610
3611 int index = indexOfTokenLocked(token, false);
3612 if (index < 0) {
3613 return false;
3614 }
3615 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3616
3617 // Is this the last activity left?
3618 boolean lastActivity = true;
3619 for (int i=mHistory.size()-1; i>=0; i--) {
3620 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3621 if (!p.finishing && p != r) {
3622 lastActivity = false;
3623 break;
3624 }
3625 }
3626
3627 // If this is the last activity, but it is the home activity, then
3628 // just don't finish it.
3629 if (lastActivity) {
3630 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3631 return false;
3632 }
3633 }
3634
3635 finishActivityLocked(r, index, resultCode, resultData, reason);
3636 return true;
3637 }
3638
3639 /**
3640 * @return Returns true if this activity has been removed from the history
3641 * list, or false if it is still in the list and will be removed later.
3642 */
3643 private final boolean finishActivityLocked(HistoryRecord r, int index,
3644 int resultCode, Intent resultData, String reason) {
3645 if (r.finishing) {
3646 Log.w(TAG, "Duplicate finish request for " + r);
3647 return false;
3648 }
3649
3650 r.finishing = true;
3651 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3652 System.identityHashCode(r),
3653 r.task.taskId, r.shortComponentName, reason);
3654 r.task.numActivities--;
3655 if (r.frontOfTask && index < (mHistory.size()-1)) {
3656 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3657 if (next.task == r.task) {
3658 next.frontOfTask = true;
3659 }
3660 }
3661
3662 r.pauseKeyDispatchingLocked();
3663 if (mFocusedActivity == r) {
3664 setFocusedActivityLocked(topRunningActivityLocked(null));
3665 }
3666
3667 // send the result
3668 HistoryRecord resultTo = r.resultTo;
3669 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003670 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3671 + " who=" + r.resultWho + " req=" + r.requestCode
3672 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003673 if (r.info.applicationInfo.uid > 0) {
3674 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3675 r.packageName, resultData, r);
3676 }
3677 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3678 resultData);
3679 r.resultTo = null;
3680 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003681 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682
3683 // Make sure this HistoryRecord is not holding on to other resources,
3684 // because clients have remote IPC references to this object so we
3685 // can't assume that will go away and want to avoid circular IPC refs.
3686 r.results = null;
3687 r.pendingResults = null;
3688 r.newIntents = null;
3689 r.icicle = null;
3690
3691 if (mPendingThumbnails.size() > 0) {
3692 // There are clients waiting to receive thumbnails so, in case
3693 // this is an activity that someone is waiting for, add it
3694 // to the pending list so we can correctly update the clients.
3695 mCancelledThumbnails.add(r);
3696 }
3697
3698 if (mResumedActivity == r) {
3699 boolean endTask = index <= 0
3700 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3701 if (DEBUG_TRANSITION) Log.v(TAG,
3702 "Prepare close transition: finishing " + r);
3703 mWindowManager.prepareAppTransition(endTask
3704 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3705 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3706
3707 // Tell window manager to prepare for this one to be removed.
3708 mWindowManager.setAppVisibility(r, false);
3709
3710 if (mPausingActivity == null) {
3711 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3712 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3713 startPausingLocked(false, false);
3714 }
3715
3716 } else if (r.state != ActivityState.PAUSING) {
3717 // If the activity is PAUSING, we will complete the finish once
3718 // it is done pausing; else we can just directly finish it here.
3719 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3720 return finishCurrentActivityLocked(r, index,
3721 FINISH_AFTER_PAUSE) == null;
3722 } else {
3723 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3724 }
3725
3726 return false;
3727 }
3728
3729 private static final int FINISH_IMMEDIATELY = 0;
3730 private static final int FINISH_AFTER_PAUSE = 1;
3731 private static final int FINISH_AFTER_VISIBLE = 2;
3732
3733 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3734 int mode) {
3735 final int index = indexOfTokenLocked(r, false);
3736 if (index < 0) {
3737 return null;
3738 }
3739
3740 return finishCurrentActivityLocked(r, index, mode);
3741 }
3742
3743 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3744 int index, int mode) {
3745 // First things first: if this activity is currently visible,
3746 // and the resumed activity is not yet visible, then hold off on
3747 // finishing until the resumed one becomes visible.
3748 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3749 if (!mStoppingActivities.contains(r)) {
3750 mStoppingActivities.add(r);
3751 if (mStoppingActivities.size() > 3) {
3752 // If we already have a few activities waiting to stop,
3753 // then give up on things going idle and start clearing
3754 // them out.
3755 Message msg = Message.obtain();
3756 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3757 mHandler.sendMessage(msg);
3758 }
3759 }
3760 r.state = ActivityState.STOPPING;
3761 updateOomAdjLocked();
3762 return r;
3763 }
3764
3765 // make sure the record is cleaned out of other places.
3766 mStoppingActivities.remove(r);
3767 mWaitingVisibleActivities.remove(r);
3768 if (mResumedActivity == r) {
3769 mResumedActivity = null;
3770 }
3771 final ActivityState prevState = r.state;
3772 r.state = ActivityState.FINISHING;
3773
3774 if (mode == FINISH_IMMEDIATELY
3775 || prevState == ActivityState.STOPPED
3776 || prevState == ActivityState.INITIALIZING) {
3777 // If this activity is already stopped, we can just finish
3778 // it right now.
3779 return destroyActivityLocked(r, true) ? null : r;
3780 } else {
3781 // Need to go through the full pause cycle to get this
3782 // activity into the stopped state and then finish it.
3783 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3784 mFinishingActivities.add(r);
3785 resumeTopActivityLocked(null);
3786 }
3787 return r;
3788 }
3789
3790 /**
3791 * This is the internal entry point for handling Activity.finish().
3792 *
3793 * @param token The Binder token referencing the Activity we want to finish.
3794 * @param resultCode Result code, if any, from this Activity.
3795 * @param resultData Result data (Intent), if any, from this Activity.
3796 *
3797 * @result Returns true if the activity successfully finished, or false if it is still running.
3798 */
3799 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3800 // Refuse possible leaked file descriptors
3801 if (resultData != null && resultData.hasFileDescriptors() == true) {
3802 throw new IllegalArgumentException("File descriptors passed in Intent");
3803 }
3804
3805 synchronized(this) {
3806 if (mWatcher != null) {
3807 // Find the first activity that is not finishing.
3808 HistoryRecord next = topRunningActivityLocked(token, 0);
3809 if (next != null) {
3810 // ask watcher if this is allowed
3811 boolean resumeOK = true;
3812 try {
3813 resumeOK = mWatcher.activityResuming(next.packageName);
3814 } catch (RemoteException e) {
3815 mWatcher = null;
3816 }
3817
3818 if (!resumeOK) {
3819 return false;
3820 }
3821 }
3822 }
3823 final long origId = Binder.clearCallingIdentity();
3824 boolean res = requestFinishActivityLocked(token, resultCode,
3825 resultData, "app-request");
3826 Binder.restoreCallingIdentity(origId);
3827 return res;
3828 }
3829 }
3830
3831 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3832 String resultWho, int requestCode, int resultCode, Intent data) {
3833
3834 if (callingUid > 0) {
3835 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3836 data, r);
3837 }
3838
The Android Open Source Project10592532009-03-18 17:39:46 -07003839 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3840 + " : who=" + resultWho + " req=" + requestCode
3841 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003842 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3843 try {
3844 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3845 list.add(new ResultInfo(resultWho, requestCode,
3846 resultCode, data));
3847 r.app.thread.scheduleSendResult(r, list);
3848 return;
3849 } catch (Exception e) {
3850 Log.w(TAG, "Exception thrown sending result to " + r, e);
3851 }
3852 }
3853
3854 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3855 }
3856
3857 public final void finishSubActivity(IBinder token, String resultWho,
3858 int requestCode) {
3859 synchronized(this) {
3860 int index = indexOfTokenLocked(token, false);
3861 if (index < 0) {
3862 return;
3863 }
3864 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3865
3866 final long origId = Binder.clearCallingIdentity();
3867
3868 int i;
3869 for (i=mHistory.size()-1; i>=0; i--) {
3870 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3871 if (r.resultTo == self && r.requestCode == requestCode) {
3872 if ((r.resultWho == null && resultWho == null) ||
3873 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3874 finishActivityLocked(r, i,
3875 Activity.RESULT_CANCELED, null, "request-sub");
3876 }
3877 }
3878 }
3879
3880 Binder.restoreCallingIdentity(origId);
3881 }
3882 }
3883
3884 /**
3885 * Perform clean-up of service connections in an activity record.
3886 */
3887 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3888 // Throw away any services that have been bound by this activity.
3889 if (r.connections != null) {
3890 Iterator<ConnectionRecord> it = r.connections.iterator();
3891 while (it.hasNext()) {
3892 ConnectionRecord c = it.next();
3893 removeConnectionLocked(c, null, r);
3894 }
3895 r.connections = null;
3896 }
3897 }
3898
3899 /**
3900 * Perform the common clean-up of an activity record. This is called both
3901 * as part of destroyActivityLocked() (when destroying the client-side
3902 * representation) and cleaning things up as a result of its hosting
3903 * processing going away, in which case there is no remaining client-side
3904 * state to destroy so only the cleanup here is needed.
3905 */
3906 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
3907 if (mResumedActivity == r) {
3908 mResumedActivity = null;
3909 }
3910 if (mFocusedActivity == r) {
3911 mFocusedActivity = null;
3912 }
3913
3914 r.configDestroy = false;
3915 r.frozenBeforeDestroy = false;
3916
3917 // Make sure this record is no longer in the pending finishes list.
3918 // This could happen, for example, if we are trimming activities
3919 // down to the max limit while they are still waiting to finish.
3920 mFinishingActivities.remove(r);
3921 mWaitingVisibleActivities.remove(r);
3922
3923 // Remove any pending results.
3924 if (r.finishing && r.pendingResults != null) {
3925 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3926 PendingIntentRecord rec = apr.get();
3927 if (rec != null) {
3928 cancelIntentSenderLocked(rec, false);
3929 }
3930 }
3931 r.pendingResults = null;
3932 }
3933
3934 if (cleanServices) {
3935 cleanUpActivityServicesLocked(r);
3936 }
3937
3938 if (mPendingThumbnails.size() > 0) {
3939 // There are clients waiting to receive thumbnails so, in case
3940 // this is an activity that someone is waiting for, add it
3941 // to the pending list so we can correctly update the clients.
3942 mCancelledThumbnails.add(r);
3943 }
3944
3945 // Get rid of any pending idle timeouts.
3946 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3947 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3948 }
3949
3950 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
3951 if (r.state != ActivityState.DESTROYED) {
3952 mHistory.remove(r);
3953 r.inHistory = false;
3954 r.state = ActivityState.DESTROYED;
3955 mWindowManager.removeAppToken(r);
3956 if (VALIDATE_TOKENS) {
3957 mWindowManager.validateAppTokens(mHistory);
3958 }
3959 cleanUpActivityServicesLocked(r);
3960 removeActivityUriPermissionsLocked(r);
3961 }
3962 }
3963
3964 /**
3965 * Destroy the current CLIENT SIDE instance of an activity. This may be
3966 * called both when actually finishing an activity, or when performing
3967 * a configuration switch where we destroy the current client-side object
3968 * but then create a new client-side object for this same HistoryRecord.
3969 */
3970 private final boolean destroyActivityLocked(HistoryRecord r,
3971 boolean removeFromApp) {
3972 if (DEBUG_SWITCH) Log.v(
3973 TAG, "Removing activity: token=" + r
3974 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
3975 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
3976 System.identityHashCode(r),
3977 r.task.taskId, r.shortComponentName);
3978
3979 boolean removedFromHistory = false;
3980
3981 cleanUpActivityLocked(r, false);
3982
3983 if (r.app != null) {
3984 if (removeFromApp) {
3985 int idx = r.app.activities.indexOf(r);
3986 if (idx >= 0) {
3987 r.app.activities.remove(idx);
3988 }
3989 if (r.persistent) {
3990 decPersistentCountLocked(r.app);
3991 }
3992 }
3993
3994 boolean skipDestroy = false;
3995
3996 try {
3997 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
3998 r.app.thread.scheduleDestroyActivity(r, r.finishing,
3999 r.configChangeFlags);
4000 } catch (Exception e) {
4001 // We can just ignore exceptions here... if the process
4002 // has crashed, our death notification will clean things
4003 // up.
4004 //Log.w(TAG, "Exception thrown during finish", e);
4005 if (r.finishing) {
4006 removeActivityFromHistoryLocked(r);
4007 removedFromHistory = true;
4008 skipDestroy = true;
4009 }
4010 }
4011
4012 r.app = null;
4013 r.nowVisible = false;
4014
4015 if (r.finishing && !skipDestroy) {
4016 r.state = ActivityState.DESTROYING;
4017 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4018 msg.obj = r;
4019 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4020 } else {
4021 r.state = ActivityState.DESTROYED;
4022 }
4023 } else {
4024 // remove this record from the history.
4025 if (r.finishing) {
4026 removeActivityFromHistoryLocked(r);
4027 removedFromHistory = true;
4028 } else {
4029 r.state = ActivityState.DESTROYED;
4030 }
4031 }
4032
4033 r.configChangeFlags = 0;
4034
4035 if (!mLRUActivities.remove(r)) {
4036 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4037 }
4038
4039 return removedFromHistory;
4040 }
4041
4042 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4043 ProcessRecord app)
4044 {
4045 int i = list.size();
4046 if (localLOGV) Log.v(
4047 TAG, "Removing app " + app + " from list " + list
4048 + " with " + i + " entries");
4049 while (i > 0) {
4050 i--;
4051 HistoryRecord r = (HistoryRecord)list.get(i);
4052 if (localLOGV) Log.v(
4053 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4054 if (r.app == app) {
4055 if (localLOGV) Log.v(TAG, "Removing this entry!");
4056 list.remove(i);
4057 }
4058 }
4059 }
4060
4061 /**
4062 * Main function for removing an existing process from the activity manager
4063 * as a result of that process going away. Clears out all connections
4064 * to the process.
4065 */
4066 private final void handleAppDiedLocked(ProcessRecord app,
4067 boolean restarting) {
4068 cleanUpApplicationRecordLocked(app, restarting, -1);
4069 if (!restarting) {
4070 mLRUProcesses.remove(app);
4071 }
4072
4073 // Just in case...
4074 if (mPausingActivity != null && mPausingActivity.app == app) {
4075 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4076 mPausingActivity = null;
4077 }
4078 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4079 mLastPausedActivity = null;
4080 }
4081
4082 // Remove this application's activities from active lists.
4083 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4084 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4085 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4086 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4087
4088 boolean atTop = true;
4089 boolean hasVisibleActivities = false;
4090
4091 // Clean out the history list.
4092 int i = mHistory.size();
4093 if (localLOGV) Log.v(
4094 TAG, "Removing app " + app + " from history with " + i + " entries");
4095 while (i > 0) {
4096 i--;
4097 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4098 if (localLOGV) Log.v(
4099 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4100 if (r.app == app) {
4101 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4102 if (localLOGV) Log.v(
4103 TAG, "Removing this entry! frozen=" + r.haveState
4104 + " finishing=" + r.finishing);
4105 mHistory.remove(i);
4106
4107 r.inHistory = false;
4108 mWindowManager.removeAppToken(r);
4109 if (VALIDATE_TOKENS) {
4110 mWindowManager.validateAppTokens(mHistory);
4111 }
4112 removeActivityUriPermissionsLocked(r);
4113
4114 } else {
4115 // We have the current state for this activity, so
4116 // it can be restarted later when needed.
4117 if (localLOGV) Log.v(
4118 TAG, "Keeping entry, setting app to null");
4119 if (r.visible) {
4120 hasVisibleActivities = true;
4121 }
4122 r.app = null;
4123 r.nowVisible = false;
4124 if (!r.haveState) {
4125 r.icicle = null;
4126 }
4127 }
4128
4129 cleanUpActivityLocked(r, true);
4130 r.state = ActivityState.STOPPED;
4131 }
4132 atTop = false;
4133 }
4134
4135 app.activities.clear();
4136
4137 if (app.instrumentationClass != null) {
4138 Log.w(TAG, "Crash of app " + app.processName
4139 + " running instrumentation " + app.instrumentationClass);
4140 Bundle info = new Bundle();
4141 info.putString("shortMsg", "Process crashed.");
4142 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4143 }
4144
4145 if (!restarting) {
4146 if (!resumeTopActivityLocked(null)) {
4147 // If there was nothing to resume, and we are not already
4148 // restarting this process, but there is a visible activity that
4149 // is hosted by the process... then make sure all visible
4150 // activities are running, taking care of restarting this
4151 // process.
4152 if (hasVisibleActivities) {
4153 ensureActivitiesVisibleLocked(null, 0);
4154 }
4155 }
4156 }
4157 }
4158
4159 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4160 IBinder threadBinder = thread.asBinder();
4161
4162 // Find the application record.
4163 int count = mLRUProcesses.size();
4164 int i;
4165 for (i=0; i<count; i++) {
4166 ProcessRecord rec = mLRUProcesses.get(i);
4167 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4168 return i;
4169 }
4170 }
4171 return -1;
4172 }
4173
4174 private final ProcessRecord getRecordForAppLocked(
4175 IApplicationThread thread) {
4176 if (thread == null) {
4177 return null;
4178 }
4179
4180 int appIndex = getLRURecordIndexForAppLocked(thread);
4181 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4182 }
4183
4184 private final void appDiedLocked(ProcessRecord app, int pid,
4185 IApplicationThread thread) {
4186
4187 mProcDeaths[0]++;
4188
4189 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4190 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4191 + ") has died.");
4192 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4193 if (localLOGV) Log.v(
4194 TAG, "Dying app: " + app + ", pid: " + pid
4195 + ", thread: " + thread.asBinder());
4196 boolean doLowMem = app.instrumentationClass == null;
4197 handleAppDiedLocked(app, false);
4198
4199 if (doLowMem) {
4200 // If there are no longer any background processes running,
4201 // and the app that died was not running instrumentation,
4202 // then tell everyone we are now low on memory.
4203 boolean haveBg = false;
4204 int count = mLRUProcesses.size();
4205 int i;
4206 for (i=0; i<count; i++) {
4207 ProcessRecord rec = mLRUProcesses.get(i);
4208 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4209 haveBg = true;
4210 break;
4211 }
4212 }
4213
4214 if (!haveBg) {
4215 Log.i(TAG, "Low Memory: No more background processes.");
4216 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4217 for (i=0; i<count; i++) {
4218 ProcessRecord rec = mLRUProcesses.get(i);
4219 if (rec.thread != null) {
4220 rec.lastRequestedGc = SystemClock.uptimeMillis();
4221 try {
4222 rec.thread.scheduleLowMemory();
4223 } catch (RemoteException e) {
4224 // Don't care if the process is gone.
4225 }
4226 }
4227 }
4228 }
4229 }
4230 } else if (Config.LOGD) {
4231 Log.d(TAG, "Received spurious death notification for thread "
4232 + thread.asBinder());
4233 }
4234 }
4235
4236 final String readFile(String filename) {
4237 try {
4238 FileInputStream fs = new FileInputStream(filename);
4239 byte[] inp = new byte[8192];
4240 int size = fs.read(inp);
4241 fs.close();
4242 return new String(inp, 0, 0, size);
4243 } catch (java.io.IOException e) {
4244 }
4245 return "";
4246 }
4247
4248 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4249 final String annotation) {
4250 if (app.notResponding || app.crashing) {
4251 return;
4252 }
4253
4254 // Log the ANR to the event log.
4255 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4256
4257 // If we are on a secure build and the application is not interesting to the user (it is
4258 // not visible or in the background), just kill it instead of displaying a dialog.
4259 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4260 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4261 Process.killProcess(app.pid);
4262 return;
4263 }
4264
4265 // DeviceMonitor.start();
4266
4267 String processInfo = null;
4268 if (MONITOR_CPU_USAGE) {
4269 updateCpuStatsNow();
4270 synchronized (mProcessStatsThread) {
4271 processInfo = mProcessStats.printCurrentState();
4272 }
4273 }
4274
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004275 StringBuilder info = mStringBuilder;
4276 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004277 info.append("ANR (application not responding) in process: ");
4278 info.append(app.processName);
4279 if (annotation != null) {
4280 info.append("\nAnnotation: ");
4281 info.append(annotation);
4282 }
4283 if (MONITOR_CPU_USAGE) {
4284 info.append("\nCPU usage:\n");
4285 info.append(processInfo);
4286 }
4287 Log.i(TAG, info.toString());
4288
4289 // The application is not responding. Dump as many thread traces as we can.
4290 boolean fileDump = prepareTraceFile(true);
4291 if (!fileDump) {
4292 // Dumping traces to the log, just dump the process that isn't responding so
4293 // we don't overflow the log
4294 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4295 } else {
4296 // Dumping traces to a file so dump all active processes we know about
4297 synchronized (this) {
4298 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4299 ProcessRecord r = mLRUProcesses.get(i);
4300 if (r.thread != null) {
4301 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4302 }
4303 }
4304 }
4305 }
4306
4307 if (mWatcher != null) {
4308 try {
4309 int res = mWatcher.appNotResponding(app.processName,
4310 app.pid, info.toString());
4311 if (res != 0) {
4312 if (res < 0) {
4313 // wait until the SIGQUIT has had a chance to process before killing the
4314 // process.
4315 try {
4316 wait(2000);
4317 } catch (InterruptedException e) {
4318 }
4319
4320 Process.killProcess(app.pid);
4321 return;
4322 }
4323 }
4324 } catch (RemoteException e) {
4325 mWatcher = null;
4326 }
4327 }
4328
4329 makeAppNotRespondingLocked(app,
4330 activity != null ? activity.shortComponentName : null,
4331 annotation != null ? "ANR " + annotation : "ANR",
4332 info.toString(), null);
4333 Message msg = Message.obtain();
4334 HashMap map = new HashMap();
4335 msg.what = SHOW_NOT_RESPONDING_MSG;
4336 msg.obj = map;
4337 map.put("app", app);
4338 if (activity != null) {
4339 map.put("activity", activity);
4340 }
4341
4342 mHandler.sendMessage(msg);
4343 return;
4344 }
4345
4346 /**
4347 * If a stack trace file has been configured, prepare the filesystem
4348 * by creating the directory if it doesn't exist and optionally
4349 * removing the old trace file.
4350 *
4351 * @param removeExisting If set, the existing trace file will be removed.
4352 * @return Returns true if the trace file preparations succeeded
4353 */
4354 public static boolean prepareTraceFile(boolean removeExisting) {
4355 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4356 boolean fileReady = false;
4357 if (!TextUtils.isEmpty(tracesPath)) {
4358 File f = new File(tracesPath);
4359 if (!f.exists()) {
4360 // Ensure the enclosing directory exists
4361 File dir = f.getParentFile();
4362 if (!dir.exists()) {
4363 fileReady = dir.mkdirs();
4364 FileUtils.setPermissions(dir.getAbsolutePath(),
4365 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4366 } else if (dir.isDirectory()) {
4367 fileReady = true;
4368 }
4369 } else if (removeExisting) {
4370 // Remove the previous traces file, so we don't fill the disk.
4371 // The VM will recreate it
4372 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4373 fileReady = f.delete();
4374 }
4375 }
4376
4377 return fileReady;
4378 }
4379
4380
4381 private final void decPersistentCountLocked(ProcessRecord app)
4382 {
4383 app.persistentActivities--;
4384 if (app.persistentActivities > 0) {
4385 // Still more of 'em...
4386 return;
4387 }
4388 if (app.persistent) {
4389 // Ah, but the application itself is persistent. Whatever!
4390 return;
4391 }
4392
4393 // App is no longer persistent... make sure it and the ones
4394 // following it in the LRU list have the correc oom_adj.
4395 updateOomAdjLocked();
4396 }
4397
4398 public void setPersistent(IBinder token, boolean isPersistent) {
4399 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4400 != PackageManager.PERMISSION_GRANTED) {
4401 String msg = "Permission Denial: setPersistent() from pid="
4402 + Binder.getCallingPid()
4403 + ", uid=" + Binder.getCallingUid()
4404 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4405 Log.w(TAG, msg);
4406 throw new SecurityException(msg);
4407 }
4408
4409 synchronized(this) {
4410 int index = indexOfTokenLocked(token, true);
4411 if (index < 0) {
4412 return;
4413 }
4414 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4415 ProcessRecord app = r.app;
4416
4417 if (localLOGV) Log.v(
4418 TAG, "Setting persistence " + isPersistent + ": " + r);
4419
4420 if (isPersistent) {
4421 if (r.persistent) {
4422 // Okay okay, I heard you already!
4423 if (localLOGV) Log.v(TAG, "Already persistent!");
4424 return;
4425 }
4426 r.persistent = true;
4427 app.persistentActivities++;
4428 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4429 if (app.persistentActivities > 1) {
4430 // We aren't the first...
4431 if (localLOGV) Log.v(TAG, "Not the first!");
4432 return;
4433 }
4434 if (app.persistent) {
4435 // This would be redundant.
4436 if (localLOGV) Log.v(TAG, "App is persistent!");
4437 return;
4438 }
4439
4440 // App is now persistent... make sure it and the ones
4441 // following it now have the correct oom_adj.
4442 final long origId = Binder.clearCallingIdentity();
4443 updateOomAdjLocked();
4444 Binder.restoreCallingIdentity(origId);
4445
4446 } else {
4447 if (!r.persistent) {
4448 // Okay okay, I heard you already!
4449 return;
4450 }
4451 r.persistent = false;
4452 final long origId = Binder.clearCallingIdentity();
4453 decPersistentCountLocked(app);
4454 Binder.restoreCallingIdentity(origId);
4455
4456 }
4457 }
4458 }
4459
4460 public boolean clearApplicationUserData(final String packageName,
4461 final IPackageDataObserver observer) {
4462 int uid = Binder.getCallingUid();
4463 int pid = Binder.getCallingPid();
4464 long callingId = Binder.clearCallingIdentity();
4465 try {
4466 IPackageManager pm = ActivityThread.getPackageManager();
4467 int pkgUid = -1;
4468 synchronized(this) {
4469 try {
4470 pkgUid = pm.getPackageUid(packageName);
4471 } catch (RemoteException e) {
4472 }
4473 if (pkgUid == -1) {
4474 Log.w(TAG, "Invalid packageName:" + packageName);
4475 return false;
4476 }
4477 if (uid == pkgUid || checkComponentPermission(
4478 android.Manifest.permission.CLEAR_APP_USER_DATA,
4479 pid, uid, -1)
4480 == PackageManager.PERMISSION_GRANTED) {
4481 restartPackageLocked(packageName, pkgUid);
4482 } else {
4483 throw new SecurityException(pid+" does not have permission:"+
4484 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4485 "for process:"+packageName);
4486 }
4487 }
4488
4489 try {
4490 //clear application user data
4491 pm.clearApplicationUserData(packageName, observer);
4492 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4493 Uri.fromParts("package", packageName, null));
4494 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4495 broadcastIntentLocked(null, null, intent,
4496 null, null, 0, null, null, null,
4497 false, false, MY_PID, Process.SYSTEM_UID);
4498 } catch (RemoteException e) {
4499 }
4500 } finally {
4501 Binder.restoreCallingIdentity(callingId);
4502 }
4503 return true;
4504 }
4505
4506 public void restartPackage(final String packageName) {
4507 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4508 != PackageManager.PERMISSION_GRANTED) {
4509 String msg = "Permission Denial: restartPackage() from pid="
4510 + Binder.getCallingPid()
4511 + ", uid=" + Binder.getCallingUid()
4512 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4513 Log.w(TAG, msg);
4514 throw new SecurityException(msg);
4515 }
4516
4517 long callingId = Binder.clearCallingIdentity();
4518 try {
4519 IPackageManager pm = ActivityThread.getPackageManager();
4520 int pkgUid = -1;
4521 synchronized(this) {
4522 try {
4523 pkgUid = pm.getPackageUid(packageName);
4524 } catch (RemoteException e) {
4525 }
4526 if (pkgUid == -1) {
4527 Log.w(TAG, "Invalid packageName: " + packageName);
4528 return;
4529 }
4530 restartPackageLocked(packageName, pkgUid);
4531 }
4532 } finally {
4533 Binder.restoreCallingIdentity(callingId);
4534 }
4535 }
4536
4537 private void restartPackageLocked(final String packageName, int uid) {
4538 uninstallPackageLocked(packageName, uid, false);
4539 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4540 Uri.fromParts("package", packageName, null));
4541 intent.putExtra(Intent.EXTRA_UID, uid);
4542 broadcastIntentLocked(null, null, intent,
4543 null, null, 0, null, null, null,
4544 false, false, MY_PID, Process.SYSTEM_UID);
4545 }
4546
4547 private final void uninstallPackageLocked(String name, int uid,
4548 boolean callerWillRestart) {
4549 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4550
4551 int i, N;
4552
4553 final String procNamePrefix = name + ":";
4554 if (uid < 0) {
4555 try {
4556 uid = ActivityThread.getPackageManager().getPackageUid(name);
4557 } catch (RemoteException e) {
4558 }
4559 }
4560
4561 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4562 while (badApps.hasNext()) {
4563 SparseArray<Long> ba = badApps.next();
4564 if (ba.get(uid) != null) {
4565 badApps.remove();
4566 }
4567 }
4568
4569 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4570
4571 // Remove all processes this package may have touched: all with the
4572 // same UID (except for the system or root user), and all whose name
4573 // matches the package name.
4574 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4575 final int NA = apps.size();
4576 for (int ia=0; ia<NA; ia++) {
4577 ProcessRecord app = apps.valueAt(ia);
4578 if (app.removed) {
4579 procs.add(app);
4580 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4581 || app.processName.equals(name)
4582 || app.processName.startsWith(procNamePrefix)) {
4583 app.removed = true;
4584 procs.add(app);
4585 }
4586 }
4587 }
4588
4589 N = procs.size();
4590 for (i=0; i<N; i++) {
4591 removeProcessLocked(procs.get(i), callerWillRestart);
4592 }
4593
4594 for (i=mHistory.size()-1; i>=0; i--) {
4595 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4596 if (r.packageName.equals(name)) {
4597 if (Config.LOGD) Log.d(
4598 TAG, " Force finishing activity "
4599 + r.intent.getComponent().flattenToShortString());
4600 if (r.app != null) {
4601 r.app.removed = true;
4602 }
4603 r.app = null;
4604 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4605 }
4606 }
4607
4608 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4609 for (ServiceRecord service : mServices.values()) {
4610 if (service.packageName.equals(name)) {
4611 if (service.app != null) {
4612 service.app.removed = true;
4613 }
4614 service.app = null;
4615 services.add(service);
4616 }
4617 }
4618
4619 N = services.size();
4620 for (i=0; i<N; i++) {
4621 bringDownServiceLocked(services.get(i), true);
4622 }
4623
4624 resumeTopActivityLocked(null);
4625 }
4626
4627 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4628 final String name = app.processName;
4629 final int uid = app.info.uid;
4630 if (Config.LOGD) Log.d(
4631 TAG, "Force removing process " + app + " (" + name
4632 + "/" + uid + ")");
4633
4634 mProcessNames.remove(name, uid);
4635 boolean needRestart = false;
4636 if (app.pid > 0 && app.pid != MY_PID) {
4637 int pid = app.pid;
4638 synchronized (mPidsSelfLocked) {
4639 mPidsSelfLocked.remove(pid);
4640 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4641 }
4642 handleAppDiedLocked(app, true);
4643 mLRUProcesses.remove(app);
4644 Process.killProcess(pid);
4645
4646 if (app.persistent) {
4647 if (!callerWillRestart) {
4648 addAppLocked(app.info);
4649 } else {
4650 needRestart = true;
4651 }
4652 }
4653 } else {
4654 mRemovedProcesses.add(app);
4655 }
4656
4657 return needRestart;
4658 }
4659
4660 private final void processStartTimedOutLocked(ProcessRecord app) {
4661 final int pid = app.pid;
4662 boolean gone = false;
4663 synchronized (mPidsSelfLocked) {
4664 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4665 if (knownApp != null && knownApp.thread == null) {
4666 mPidsSelfLocked.remove(pid);
4667 gone = true;
4668 }
4669 }
4670
4671 if (gone) {
4672 Log.w(TAG, "Process " + app + " failed to attach");
4673 mProcessNames.remove(app.processName, app.info.uid);
4674 Process.killProcess(pid);
4675 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4676 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4677 mPendingBroadcast = null;
4678 scheduleBroadcastsLocked();
4679 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004680 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4681 Log.w(TAG, "Unattached app died before backup, skipping");
4682 try {
4683 IBackupManager bm = IBackupManager.Stub.asInterface(
4684 ServiceManager.getService(Context.BACKUP_SERVICE));
4685 bm.agentDisconnected(app.info.packageName);
4686 } catch (RemoteException e) {
4687 // Can't happen; the backup manager is local
4688 }
4689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004690 } else {
4691 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4692 }
4693 }
4694
4695 private final boolean attachApplicationLocked(IApplicationThread thread,
4696 int pid) {
4697
4698 // Find the application record that is being attached... either via
4699 // the pid if we are running in multiple processes, or just pull the
4700 // next app record if we are emulating process with anonymous threads.
4701 ProcessRecord app;
4702 if (pid != MY_PID && pid >= 0) {
4703 synchronized (mPidsSelfLocked) {
4704 app = mPidsSelfLocked.get(pid);
4705 }
4706 } else if (mStartingProcesses.size() > 0) {
4707 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004708 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004709 } else {
4710 app = null;
4711 }
4712
4713 if (app == null) {
4714 Log.w(TAG, "No pending application record for pid " + pid
4715 + " (IApplicationThread " + thread + "); dropping process");
4716 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4717 if (pid > 0 && pid != MY_PID) {
4718 Process.killProcess(pid);
4719 } else {
4720 try {
4721 thread.scheduleExit();
4722 } catch (Exception e) {
4723 // Ignore exceptions.
4724 }
4725 }
4726 return false;
4727 }
4728
4729 // If this application record is still attached to a previous
4730 // process, clean it up now.
4731 if (app.thread != null) {
4732 handleAppDiedLocked(app, true);
4733 }
4734
4735 // Tell the process all about itself.
4736
4737 if (localLOGV) Log.v(
4738 TAG, "Binding process pid " + pid + " to record " + app);
4739
4740 String processName = app.processName;
4741 try {
4742 thread.asBinder().linkToDeath(new AppDeathRecipient(
4743 app, pid, thread), 0);
4744 } catch (RemoteException e) {
4745 app.resetPackageList();
4746 startProcessLocked(app, "link fail", processName);
4747 return false;
4748 }
4749
4750 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4751
4752 app.thread = thread;
4753 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004754 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004755 app.forcingToForeground = null;
4756 app.foregroundServices = false;
4757 app.debugging = false;
4758
4759 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4760
4761 List providers = generateApplicationProvidersLocked(app);
4762
4763 if (localLOGV) Log.v(
4764 TAG, "New app record " + app
4765 + " thread=" + thread.asBinder() + " pid=" + pid);
4766 try {
4767 int testMode = IApplicationThread.DEBUG_OFF;
4768 if (mDebugApp != null && mDebugApp.equals(processName)) {
4769 testMode = mWaitForDebugger
4770 ? IApplicationThread.DEBUG_WAIT
4771 : IApplicationThread.DEBUG_ON;
4772 app.debugging = true;
4773 if (mDebugTransient) {
4774 mDebugApp = mOrigDebugApp;
4775 mWaitForDebugger = mOrigWaitForDebugger;
4776 }
4777 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004778 // If the app is being launched for restore or full backup, set it up specially
4779 boolean isRestrictedBackupMode = false;
4780 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4781 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4782 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4783 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004784 thread.bindApplication(processName, app.instrumentationInfo != null
4785 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 app.instrumentationClass, app.instrumentationProfileFile,
4787 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004788 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004789 updateLRUListLocked(app, false);
4790 app.lastRequestedGc = SystemClock.uptimeMillis();
4791 } catch (Exception e) {
4792 // todo: Yikes! What should we do? For now we will try to
4793 // start another process, but that could easily get us in
4794 // an infinite loop of restarting processes...
4795 Log.w(TAG, "Exception thrown during bind!", e);
4796
4797 app.resetPackageList();
4798 startProcessLocked(app, "bind fail", processName);
4799 return false;
4800 }
4801
4802 // Remove this record from the list of starting applications.
4803 mPersistentStartingProcesses.remove(app);
4804 mProcessesOnHold.remove(app);
4805
4806 boolean badApp = false;
4807 boolean didSomething = false;
4808
4809 // See if the top visible activity is waiting to run in this process...
4810 HistoryRecord hr = topRunningActivityLocked(null);
4811 if (hr != null) {
4812 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4813 && processName.equals(hr.processName)) {
4814 try {
4815 if (realStartActivityLocked(hr, app, true, true)) {
4816 didSomething = true;
4817 }
4818 } catch (Exception e) {
4819 Log.w(TAG, "Exception in new application when starting activity "
4820 + hr.intent.getComponent().flattenToShortString(), e);
4821 badApp = true;
4822 }
4823 } else {
4824 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4825 }
4826 }
4827
4828 // Find any services that should be running in this process...
4829 if (!badApp && mPendingServices.size() > 0) {
4830 ServiceRecord sr = null;
4831 try {
4832 for (int i=0; i<mPendingServices.size(); i++) {
4833 sr = mPendingServices.get(i);
4834 if (app.info.uid != sr.appInfo.uid
4835 || !processName.equals(sr.processName)) {
4836 continue;
4837 }
4838
4839 mPendingServices.remove(i);
4840 i--;
4841 realStartServiceLocked(sr, app);
4842 didSomething = true;
4843 }
4844 } catch (Exception e) {
4845 Log.w(TAG, "Exception in new application when starting service "
4846 + sr.shortName, e);
4847 badApp = true;
4848 }
4849 }
4850
4851 // Check if the next broadcast receiver is in this process...
4852 BroadcastRecord br = mPendingBroadcast;
4853 if (!badApp && br != null && br.curApp == app) {
4854 try {
4855 mPendingBroadcast = null;
4856 processCurBroadcastLocked(br, app);
4857 didSomething = true;
4858 } catch (Exception e) {
4859 Log.w(TAG, "Exception in new application when starting receiver "
4860 + br.curComponent.flattenToShortString(), e);
4861 badApp = true;
4862 logBroadcastReceiverDiscard(br);
4863 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4864 br.resultExtras, br.resultAbort, true);
4865 scheduleBroadcastsLocked();
4866 }
4867 }
4868
Christopher Tate181fafa2009-05-14 11:12:14 -07004869 // Check whether the next backup agent is in this process...
4870 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4871 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
4872 try {
4873 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4874 } catch (Exception e) {
4875 Log.w(TAG, "Exception scheduling backup agent creation: ");
4876 e.printStackTrace();
4877 }
4878 }
4879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004880 if (badApp) {
4881 // todo: Also need to kill application to deal with all
4882 // kinds of exceptions.
4883 handleAppDiedLocked(app, false);
4884 return false;
4885 }
4886
4887 if (!didSomething) {
4888 updateOomAdjLocked();
4889 }
4890
4891 return true;
4892 }
4893
4894 public final void attachApplication(IApplicationThread thread) {
4895 synchronized (this) {
4896 int callingPid = Binder.getCallingPid();
4897 final long origId = Binder.clearCallingIdentity();
4898 attachApplicationLocked(thread, callingPid);
4899 Binder.restoreCallingIdentity(origId);
4900 }
4901 }
4902
4903 public final void activityIdle(IBinder token) {
4904 final long origId = Binder.clearCallingIdentity();
4905 activityIdleInternal(token, false);
4906 Binder.restoreCallingIdentity(origId);
4907 }
4908
4909 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
4910 boolean remove) {
4911 int N = mStoppingActivities.size();
4912 if (N <= 0) return null;
4913
4914 ArrayList<HistoryRecord> stops = null;
4915
4916 final boolean nowVisible = mResumedActivity != null
4917 && mResumedActivity.nowVisible
4918 && !mResumedActivity.waitingVisible;
4919 for (int i=0; i<N; i++) {
4920 HistoryRecord s = mStoppingActivities.get(i);
4921 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
4922 + nowVisible + " waitingVisible=" + s.waitingVisible
4923 + " finishing=" + s.finishing);
4924 if (s.waitingVisible && nowVisible) {
4925 mWaitingVisibleActivities.remove(s);
4926 s.waitingVisible = false;
4927 if (s.finishing) {
4928 // If this activity is finishing, it is sitting on top of
4929 // everyone else but we now know it is no longer needed...
4930 // so get rid of it. Otherwise, we need to go through the
4931 // normal flow and hide it once we determine that it is
4932 // hidden by the activities in front of it.
4933 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
4934 mWindowManager.setAppVisibility(s, false);
4935 }
4936 }
4937 if (!s.waitingVisible && remove) {
4938 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
4939 if (stops == null) {
4940 stops = new ArrayList<HistoryRecord>();
4941 }
4942 stops.add(s);
4943 mStoppingActivities.remove(i);
4944 N--;
4945 i--;
4946 }
4947 }
4948
4949 return stops;
4950 }
4951
4952 void enableScreenAfterBoot() {
4953 mWindowManager.enableScreenAfterBoot();
4954 }
4955
4956 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
4957 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
4958
4959 ArrayList<HistoryRecord> stops = null;
4960 ArrayList<HistoryRecord> finishes = null;
4961 ArrayList<HistoryRecord> thumbnails = null;
4962 int NS = 0;
4963 int NF = 0;
4964 int NT = 0;
4965 IApplicationThread sendThumbnail = null;
4966 boolean booting = false;
4967 boolean enableScreen = false;
4968
4969 synchronized (this) {
4970 if (token != null) {
4971 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
4972 }
4973
4974 // Get the activity record.
4975 int index = indexOfTokenLocked(token, false);
4976 if (index >= 0) {
4977 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4978
4979 // No longer need to keep the device awake.
4980 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
4981 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
4982 mLaunchingActivity.release();
4983 }
4984
4985 // We are now idle. If someone is waiting for a thumbnail from
4986 // us, we can now deliver.
4987 r.idle = true;
4988 scheduleAppGcsLocked();
4989 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
4990 sendThumbnail = r.app.thread;
4991 r.thumbnailNeeded = false;
4992 }
4993
4994 // If this activity is fullscreen, set up to hide those under it.
4995
4996 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
4997 ensureActivitiesVisibleLocked(null, 0);
4998
4999 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5000 if (!mBooted && !fromTimeout) {
5001 mBooted = true;
5002 enableScreen = true;
5003 }
5004 }
5005
5006 // Atomically retrieve all of the other things to do.
5007 stops = processStoppingActivitiesLocked(true);
5008 NS = stops != null ? stops.size() : 0;
5009 if ((NF=mFinishingActivities.size()) > 0) {
5010 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5011 mFinishingActivities.clear();
5012 }
5013 if ((NT=mCancelledThumbnails.size()) > 0) {
5014 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5015 mCancelledThumbnails.clear();
5016 }
5017
5018 booting = mBooting;
5019 mBooting = false;
5020 }
5021
5022 int i;
5023
5024 // Send thumbnail if requested.
5025 if (sendThumbnail != null) {
5026 try {
5027 sendThumbnail.requestThumbnail(token);
5028 } catch (Exception e) {
5029 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5030 sendPendingThumbnail(null, token, null, null, true);
5031 }
5032 }
5033
5034 // Stop any activities that are scheduled to do so but have been
5035 // waiting for the next one to start.
5036 for (i=0; i<NS; i++) {
5037 HistoryRecord r = (HistoryRecord)stops.get(i);
5038 synchronized (this) {
5039 if (r.finishing) {
5040 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5041 } else {
5042 stopActivityLocked(r);
5043 }
5044 }
5045 }
5046
5047 // Finish any activities that are scheduled to do so but have been
5048 // waiting for the next one to start.
5049 for (i=0; i<NF; i++) {
5050 HistoryRecord r = (HistoryRecord)finishes.get(i);
5051 synchronized (this) {
5052 destroyActivityLocked(r, true);
5053 }
5054 }
5055
5056 // Report back to any thumbnail receivers.
5057 for (i=0; i<NT; i++) {
5058 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5059 sendPendingThumbnail(r, null, null, null, true);
5060 }
5061
5062 if (booting) {
5063 // Ensure that any processes we had put on hold are now started
5064 // up.
5065 final int NP = mProcessesOnHold.size();
5066 if (NP > 0) {
5067 ArrayList<ProcessRecord> procs =
5068 new ArrayList<ProcessRecord>(mProcessesOnHold);
5069 for (int ip=0; ip<NP; ip++) {
5070 this.startProcessLocked(procs.get(ip), "on-hold", null);
5071 }
5072 }
5073 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5074 // Tell anyone interested that we are done booting!
5075 synchronized (this) {
5076 broadcastIntentLocked(null, null,
5077 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5078 null, null, 0, null, null,
5079 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5080 false, false, MY_PID, Process.SYSTEM_UID);
5081 }
5082 }
5083 }
5084
5085 trimApplications();
5086 //dump();
5087 //mWindowManager.dump();
5088
5089 if (enableScreen) {
5090 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5091 SystemClock.uptimeMillis());
5092 enableScreenAfterBoot();
5093 }
5094 }
5095
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005096 final void ensureScreenEnabled() {
5097 boolean enableScreen;
5098 synchronized (this) {
5099 enableScreen = !mBooted;
5100 mBooted = true;
5101 }
5102
5103 if (enableScreen) {
5104 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5105 SystemClock.uptimeMillis());
5106 enableScreenAfterBoot();
5107 }
5108 }
5109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005110 public final void activityPaused(IBinder token, Bundle icicle) {
5111 // Refuse possible leaked file descriptors
5112 if (icicle != null && icicle.hasFileDescriptors()) {
5113 throw new IllegalArgumentException("File descriptors passed in Bundle");
5114 }
5115
5116 final long origId = Binder.clearCallingIdentity();
5117 activityPaused(token, icicle, false);
5118 Binder.restoreCallingIdentity(origId);
5119 }
5120
5121 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5122 if (DEBUG_PAUSE) Log.v(
5123 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5124 + ", timeout=" + timeout);
5125
5126 HistoryRecord r = null;
5127
5128 synchronized (this) {
5129 int index = indexOfTokenLocked(token, false);
5130 if (index >= 0) {
5131 r = (HistoryRecord)mHistory.get(index);
5132 if (!timeout) {
5133 r.icicle = icicle;
5134 r.haveState = true;
5135 }
5136 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5137 if (mPausingActivity == r) {
5138 r.state = ActivityState.PAUSED;
5139 completePauseLocked();
5140 } else {
5141 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5142 System.identityHashCode(r), r.shortComponentName,
5143 mPausingActivity != null
5144 ? mPausingActivity.shortComponentName : "(none)");
5145 }
5146 }
5147 }
5148 }
5149
5150 public final void activityStopped(IBinder token, Bitmap thumbnail,
5151 CharSequence description) {
5152 if (localLOGV) Log.v(
5153 TAG, "Activity stopped: token=" + token);
5154
5155 HistoryRecord r = null;
5156
5157 final long origId = Binder.clearCallingIdentity();
5158
5159 synchronized (this) {
5160 int index = indexOfTokenLocked(token, false);
5161 if (index >= 0) {
5162 r = (HistoryRecord)mHistory.get(index);
5163 r.thumbnail = thumbnail;
5164 r.description = description;
5165 r.stopped = true;
5166 r.state = ActivityState.STOPPED;
5167 if (!r.finishing) {
5168 if (r.configDestroy) {
5169 destroyActivityLocked(r, true);
5170 resumeTopActivityLocked(null);
5171 }
5172 }
5173 }
5174 }
5175
5176 if (r != null) {
5177 sendPendingThumbnail(r, null, null, null, false);
5178 }
5179
5180 trimApplications();
5181
5182 Binder.restoreCallingIdentity(origId);
5183 }
5184
5185 public final void activityDestroyed(IBinder token) {
5186 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5187 synchronized (this) {
5188 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5189
5190 int index = indexOfTokenLocked(token, false);
5191 if (index >= 0) {
5192 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5193 if (r.state == ActivityState.DESTROYING) {
5194 final long origId = Binder.clearCallingIdentity();
5195 removeActivityFromHistoryLocked(r);
5196 Binder.restoreCallingIdentity(origId);
5197 }
5198 }
5199 }
5200 }
5201
5202 public String getCallingPackage(IBinder token) {
5203 synchronized (this) {
5204 HistoryRecord r = getCallingRecordLocked(token);
5205 return r != null && r.app != null ? r.app.processName : null;
5206 }
5207 }
5208
5209 public ComponentName getCallingActivity(IBinder token) {
5210 synchronized (this) {
5211 HistoryRecord r = getCallingRecordLocked(token);
5212 return r != null ? r.intent.getComponent() : null;
5213 }
5214 }
5215
5216 private HistoryRecord getCallingRecordLocked(IBinder token) {
5217 int index = indexOfTokenLocked(token, true);
5218 if (index >= 0) {
5219 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5220 if (r != null) {
5221 return r.resultTo;
5222 }
5223 }
5224 return null;
5225 }
5226
5227 public ComponentName getActivityClassForToken(IBinder token) {
5228 synchronized(this) {
5229 int index = indexOfTokenLocked(token, false);
5230 if (index >= 0) {
5231 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5232 return r.intent.getComponent();
5233 }
5234 return null;
5235 }
5236 }
5237
5238 public String getPackageForToken(IBinder token) {
5239 synchronized(this) {
5240 int index = indexOfTokenLocked(token, false);
5241 if (index >= 0) {
5242 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5243 return r.packageName;
5244 }
5245 return null;
5246 }
5247 }
5248
5249 public IIntentSender getIntentSender(int type,
5250 String packageName, IBinder token, String resultWho,
5251 int requestCode, Intent intent, String resolvedType, int flags) {
5252 // Refuse possible leaked file descriptors
5253 if (intent != null && intent.hasFileDescriptors() == true) {
5254 throw new IllegalArgumentException("File descriptors passed in Intent");
5255 }
5256
5257 synchronized(this) {
5258 int callingUid = Binder.getCallingUid();
5259 try {
5260 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5261 Process.supportsProcesses()) {
5262 int uid = ActivityThread.getPackageManager()
5263 .getPackageUid(packageName);
5264 if (uid != Binder.getCallingUid()) {
5265 String msg = "Permission Denial: getIntentSender() from pid="
5266 + Binder.getCallingPid()
5267 + ", uid=" + Binder.getCallingUid()
5268 + ", (need uid=" + uid + ")"
5269 + " is not allowed to send as package " + packageName;
5270 Log.w(TAG, msg);
5271 throw new SecurityException(msg);
5272 }
5273 }
5274 } catch (RemoteException e) {
5275 throw new SecurityException(e);
5276 }
5277 HistoryRecord activity = null;
5278 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5279 int index = indexOfTokenLocked(token, false);
5280 if (index < 0) {
5281 return null;
5282 }
5283 activity = (HistoryRecord)mHistory.get(index);
5284 if (activity.finishing) {
5285 return null;
5286 }
5287 }
5288
5289 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5290 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5291 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5292 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5293 |PendingIntent.FLAG_UPDATE_CURRENT);
5294
5295 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5296 type, packageName, activity, resultWho,
5297 requestCode, intent, resolvedType, flags);
5298 WeakReference<PendingIntentRecord> ref;
5299 ref = mIntentSenderRecords.get(key);
5300 PendingIntentRecord rec = ref != null ? ref.get() : null;
5301 if (rec != null) {
5302 if (!cancelCurrent) {
5303 if (updateCurrent) {
5304 rec.key.requestIntent.replaceExtras(intent);
5305 }
5306 return rec;
5307 }
5308 rec.canceled = true;
5309 mIntentSenderRecords.remove(key);
5310 }
5311 if (noCreate) {
5312 return rec;
5313 }
5314 rec = new PendingIntentRecord(this, key, callingUid);
5315 mIntentSenderRecords.put(key, rec.ref);
5316 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5317 if (activity.pendingResults == null) {
5318 activity.pendingResults
5319 = new HashSet<WeakReference<PendingIntentRecord>>();
5320 }
5321 activity.pendingResults.add(rec.ref);
5322 }
5323 return rec;
5324 }
5325 }
5326
5327 public void cancelIntentSender(IIntentSender sender) {
5328 if (!(sender instanceof PendingIntentRecord)) {
5329 return;
5330 }
5331 synchronized(this) {
5332 PendingIntentRecord rec = (PendingIntentRecord)sender;
5333 try {
5334 int uid = ActivityThread.getPackageManager()
5335 .getPackageUid(rec.key.packageName);
5336 if (uid != Binder.getCallingUid()) {
5337 String msg = "Permission Denial: cancelIntentSender() from pid="
5338 + Binder.getCallingPid()
5339 + ", uid=" + Binder.getCallingUid()
5340 + " is not allowed to cancel packges "
5341 + rec.key.packageName;
5342 Log.w(TAG, msg);
5343 throw new SecurityException(msg);
5344 }
5345 } catch (RemoteException e) {
5346 throw new SecurityException(e);
5347 }
5348 cancelIntentSenderLocked(rec, true);
5349 }
5350 }
5351
5352 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5353 rec.canceled = true;
5354 mIntentSenderRecords.remove(rec.key);
5355 if (cleanActivity && rec.key.activity != null) {
5356 rec.key.activity.pendingResults.remove(rec.ref);
5357 }
5358 }
5359
5360 public String getPackageForIntentSender(IIntentSender pendingResult) {
5361 if (!(pendingResult instanceof PendingIntentRecord)) {
5362 return null;
5363 }
5364 synchronized(this) {
5365 try {
5366 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5367 return res.key.packageName;
5368 } catch (ClassCastException e) {
5369 }
5370 }
5371 return null;
5372 }
5373
5374 public void setProcessLimit(int max) {
5375 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5376 "setProcessLimit()");
5377 mProcessLimit = max;
5378 }
5379
5380 public int getProcessLimit() {
5381 return mProcessLimit;
5382 }
5383
5384 void foregroundTokenDied(ForegroundToken token) {
5385 synchronized (ActivityManagerService.this) {
5386 synchronized (mPidsSelfLocked) {
5387 ForegroundToken cur
5388 = mForegroundProcesses.get(token.pid);
5389 if (cur != token) {
5390 return;
5391 }
5392 mForegroundProcesses.remove(token.pid);
5393 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5394 if (pr == null) {
5395 return;
5396 }
5397 pr.forcingToForeground = null;
5398 pr.foregroundServices = false;
5399 }
5400 updateOomAdjLocked();
5401 }
5402 }
5403
5404 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5405 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5406 "setProcessForeground()");
5407 synchronized(this) {
5408 boolean changed = false;
5409
5410 synchronized (mPidsSelfLocked) {
5411 ProcessRecord pr = mPidsSelfLocked.get(pid);
5412 if (pr == null) {
5413 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5414 return;
5415 }
5416 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5417 if (oldToken != null) {
5418 oldToken.token.unlinkToDeath(oldToken, 0);
5419 mForegroundProcesses.remove(pid);
5420 pr.forcingToForeground = null;
5421 changed = true;
5422 }
5423 if (isForeground && token != null) {
5424 ForegroundToken newToken = new ForegroundToken() {
5425 public void binderDied() {
5426 foregroundTokenDied(this);
5427 }
5428 };
5429 newToken.pid = pid;
5430 newToken.token = token;
5431 try {
5432 token.linkToDeath(newToken, 0);
5433 mForegroundProcesses.put(pid, newToken);
5434 pr.forcingToForeground = token;
5435 changed = true;
5436 } catch (RemoteException e) {
5437 // If the process died while doing this, we will later
5438 // do the cleanup with the process death link.
5439 }
5440 }
5441 }
5442
5443 if (changed) {
5444 updateOomAdjLocked();
5445 }
5446 }
5447 }
5448
5449 // =========================================================
5450 // PERMISSIONS
5451 // =========================================================
5452
5453 static class PermissionController extends IPermissionController.Stub {
5454 ActivityManagerService mActivityManagerService;
5455 PermissionController(ActivityManagerService activityManagerService) {
5456 mActivityManagerService = activityManagerService;
5457 }
5458
5459 public boolean checkPermission(String permission, int pid, int uid) {
5460 return mActivityManagerService.checkPermission(permission, pid,
5461 uid) == PackageManager.PERMISSION_GRANTED;
5462 }
5463 }
5464
5465 /**
5466 * This can be called with or without the global lock held.
5467 */
5468 int checkComponentPermission(String permission, int pid, int uid,
5469 int reqUid) {
5470 // We might be performing an operation on behalf of an indirect binder
5471 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5472 // client identity accordingly before proceeding.
5473 Identity tlsIdentity = sCallerIdentity.get();
5474 if (tlsIdentity != null) {
5475 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5476 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5477 uid = tlsIdentity.uid;
5478 pid = tlsIdentity.pid;
5479 }
5480
5481 // Root, system server and our own process get to do everything.
5482 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5483 !Process.supportsProcesses()) {
5484 return PackageManager.PERMISSION_GRANTED;
5485 }
5486 // If the target requires a specific UID, always fail for others.
5487 if (reqUid >= 0 && uid != reqUid) {
5488 return PackageManager.PERMISSION_DENIED;
5489 }
5490 if (permission == null) {
5491 return PackageManager.PERMISSION_GRANTED;
5492 }
5493 try {
5494 return ActivityThread.getPackageManager()
5495 .checkUidPermission(permission, uid);
5496 } catch (RemoteException e) {
5497 // Should never happen, but if it does... deny!
5498 Log.e(TAG, "PackageManager is dead?!?", e);
5499 }
5500 return PackageManager.PERMISSION_DENIED;
5501 }
5502
5503 /**
5504 * As the only public entry point for permissions checking, this method
5505 * can enforce the semantic that requesting a check on a null global
5506 * permission is automatically denied. (Internally a null permission
5507 * string is used when calling {@link #checkComponentPermission} in cases
5508 * when only uid-based security is needed.)
5509 *
5510 * This can be called with or without the global lock held.
5511 */
5512 public int checkPermission(String permission, int pid, int uid) {
5513 if (permission == null) {
5514 return PackageManager.PERMISSION_DENIED;
5515 }
5516 return checkComponentPermission(permission, pid, uid, -1);
5517 }
5518
5519 /**
5520 * Binder IPC calls go through the public entry point.
5521 * This can be called with or without the global lock held.
5522 */
5523 int checkCallingPermission(String permission) {
5524 return checkPermission(permission,
5525 Binder.getCallingPid(),
5526 Binder.getCallingUid());
5527 }
5528
5529 /**
5530 * This can be called with or without the global lock held.
5531 */
5532 void enforceCallingPermission(String permission, String func) {
5533 if (checkCallingPermission(permission)
5534 == PackageManager.PERMISSION_GRANTED) {
5535 return;
5536 }
5537
5538 String msg = "Permission Denial: " + func + " from pid="
5539 + Binder.getCallingPid()
5540 + ", uid=" + Binder.getCallingUid()
5541 + " requires " + permission;
5542 Log.w(TAG, msg);
5543 throw new SecurityException(msg);
5544 }
5545
5546 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5547 ProviderInfo pi, int uid, int modeFlags) {
5548 try {
5549 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5550 if ((pi.readPermission != null) &&
5551 (pm.checkUidPermission(pi.readPermission, uid)
5552 != PackageManager.PERMISSION_GRANTED)) {
5553 return false;
5554 }
5555 }
5556 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5557 if ((pi.writePermission != null) &&
5558 (pm.checkUidPermission(pi.writePermission, uid)
5559 != PackageManager.PERMISSION_GRANTED)) {
5560 return false;
5561 }
5562 }
5563 return true;
5564 } catch (RemoteException e) {
5565 return false;
5566 }
5567 }
5568
5569 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5570 int modeFlags) {
5571 // Root gets to do everything.
5572 if (uid == 0 || !Process.supportsProcesses()) {
5573 return true;
5574 }
5575 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5576 if (perms == null) return false;
5577 UriPermission perm = perms.get(uri);
5578 if (perm == null) return false;
5579 return (modeFlags&perm.modeFlags) == modeFlags;
5580 }
5581
5582 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5583 // Another redirected-binder-call permissions check as in
5584 // {@link checkComponentPermission}.
5585 Identity tlsIdentity = sCallerIdentity.get();
5586 if (tlsIdentity != null) {
5587 uid = tlsIdentity.uid;
5588 pid = tlsIdentity.pid;
5589 }
5590
5591 // Our own process gets to do everything.
5592 if (pid == MY_PID) {
5593 return PackageManager.PERMISSION_GRANTED;
5594 }
5595 synchronized(this) {
5596 return checkUriPermissionLocked(uri, uid, modeFlags)
5597 ? PackageManager.PERMISSION_GRANTED
5598 : PackageManager.PERMISSION_DENIED;
5599 }
5600 }
5601
5602 private void grantUriPermissionLocked(int callingUid,
5603 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5604 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5605 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5606 if (modeFlags == 0) {
5607 return;
5608 }
5609
5610 final IPackageManager pm = ActivityThread.getPackageManager();
5611
5612 // If this is not a content: uri, we can't do anything with it.
5613 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5614 return;
5615 }
5616
5617 String name = uri.getAuthority();
5618 ProviderInfo pi = null;
5619 ContentProviderRecord cpr
5620 = (ContentProviderRecord)mProvidersByName.get(name);
5621 if (cpr != null) {
5622 pi = cpr.info;
5623 } else {
5624 try {
5625 pi = pm.resolveContentProvider(name,
5626 PackageManager.GET_URI_PERMISSION_PATTERNS);
5627 } catch (RemoteException ex) {
5628 }
5629 }
5630 if (pi == null) {
5631 Log.w(TAG, "No content provider found for: " + name);
5632 return;
5633 }
5634
5635 int targetUid;
5636 try {
5637 targetUid = pm.getPackageUid(targetPkg);
5638 if (targetUid < 0) {
5639 return;
5640 }
5641 } catch (RemoteException ex) {
5642 return;
5643 }
5644
5645 // First... does the target actually need this permission?
5646 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5647 // No need to grant the target this permission.
5648 return;
5649 }
5650
5651 // Second... maybe someone else has already granted the
5652 // permission?
5653 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5654 // No need to grant the target this permission.
5655 return;
5656 }
5657
5658 // Third... is the provider allowing granting of URI permissions?
5659 if (!pi.grantUriPermissions) {
5660 throw new SecurityException("Provider " + pi.packageName
5661 + "/" + pi.name
5662 + " does not allow granting of Uri permissions (uri "
5663 + uri + ")");
5664 }
5665 if (pi.uriPermissionPatterns != null) {
5666 final int N = pi.uriPermissionPatterns.length;
5667 boolean allowed = false;
5668 for (int i=0; i<N; i++) {
5669 if (pi.uriPermissionPatterns[i] != null
5670 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5671 allowed = true;
5672 break;
5673 }
5674 }
5675 if (!allowed) {
5676 throw new SecurityException("Provider " + pi.packageName
5677 + "/" + pi.name
5678 + " does not allow granting of permission to path of Uri "
5679 + uri);
5680 }
5681 }
5682
5683 // Fourth... does the caller itself have permission to access
5684 // this uri?
5685 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5686 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5687 throw new SecurityException("Uid " + callingUid
5688 + " does not have permission to uri " + uri);
5689 }
5690 }
5691
5692 // Okay! So here we are: the caller has the assumed permission
5693 // to the uri, and the target doesn't. Let's now give this to
5694 // the target.
5695
5696 HashMap<Uri, UriPermission> targetUris
5697 = mGrantedUriPermissions.get(targetUid);
5698 if (targetUris == null) {
5699 targetUris = new HashMap<Uri, UriPermission>();
5700 mGrantedUriPermissions.put(targetUid, targetUris);
5701 }
5702
5703 UriPermission perm = targetUris.get(uri);
5704 if (perm == null) {
5705 perm = new UriPermission(targetUid, uri);
5706 targetUris.put(uri, perm);
5707
5708 }
5709 perm.modeFlags |= modeFlags;
5710 if (activity == null) {
5711 perm.globalModeFlags |= modeFlags;
5712 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5713 perm.readActivities.add(activity);
5714 if (activity.readUriPermissions == null) {
5715 activity.readUriPermissions = new HashSet<UriPermission>();
5716 }
5717 activity.readUriPermissions.add(perm);
5718 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5719 perm.writeActivities.add(activity);
5720 if (activity.writeUriPermissions == null) {
5721 activity.writeUriPermissions = new HashSet<UriPermission>();
5722 }
5723 activity.writeUriPermissions.add(perm);
5724 }
5725 }
5726
5727 private void grantUriPermissionFromIntentLocked(int callingUid,
5728 String targetPkg, Intent intent, HistoryRecord activity) {
5729 if (intent == null) {
5730 return;
5731 }
5732 Uri data = intent.getData();
5733 if (data == null) {
5734 return;
5735 }
5736 grantUriPermissionLocked(callingUid, targetPkg, data,
5737 intent.getFlags(), activity);
5738 }
5739
5740 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5741 Uri uri, int modeFlags) {
5742 synchronized(this) {
5743 final ProcessRecord r = getRecordForAppLocked(caller);
5744 if (r == null) {
5745 throw new SecurityException("Unable to find app for caller "
5746 + caller
5747 + " when granting permission to uri " + uri);
5748 }
5749 if (targetPkg == null) {
5750 Log.w(TAG, "grantUriPermission: null target");
5751 return;
5752 }
5753 if (uri == null) {
5754 Log.w(TAG, "grantUriPermission: null uri");
5755 return;
5756 }
5757
5758 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5759 null);
5760 }
5761 }
5762
5763 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5764 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5765 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5766 HashMap<Uri, UriPermission> perms
5767 = mGrantedUriPermissions.get(perm.uid);
5768 if (perms != null) {
5769 perms.remove(perm.uri);
5770 if (perms.size() == 0) {
5771 mGrantedUriPermissions.remove(perm.uid);
5772 }
5773 }
5774 }
5775 }
5776
5777 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5778 if (activity.readUriPermissions != null) {
5779 for (UriPermission perm : activity.readUriPermissions) {
5780 perm.readActivities.remove(activity);
5781 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5782 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5783 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5784 removeUriPermissionIfNeededLocked(perm);
5785 }
5786 }
5787 }
5788 if (activity.writeUriPermissions != null) {
5789 for (UriPermission perm : activity.writeUriPermissions) {
5790 perm.writeActivities.remove(activity);
5791 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5792 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5793 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5794 removeUriPermissionIfNeededLocked(perm);
5795 }
5796 }
5797 }
5798 }
5799
5800 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5801 int modeFlags) {
5802 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5803 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5804 if (modeFlags == 0) {
5805 return;
5806 }
5807
5808 final IPackageManager pm = ActivityThread.getPackageManager();
5809
5810 final String authority = uri.getAuthority();
5811 ProviderInfo pi = null;
5812 ContentProviderRecord cpr
5813 = (ContentProviderRecord)mProvidersByName.get(authority);
5814 if (cpr != null) {
5815 pi = cpr.info;
5816 } else {
5817 try {
5818 pi = pm.resolveContentProvider(authority,
5819 PackageManager.GET_URI_PERMISSION_PATTERNS);
5820 } catch (RemoteException ex) {
5821 }
5822 }
5823 if (pi == null) {
5824 Log.w(TAG, "No content provider found for: " + authority);
5825 return;
5826 }
5827
5828 // Does the caller have this permission on the URI?
5829 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5830 // Right now, if you are not the original owner of the permission,
5831 // you are not allowed to revoke it.
5832 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5833 throw new SecurityException("Uid " + callingUid
5834 + " does not have permission to uri " + uri);
5835 //}
5836 }
5837
5838 // Go through all of the permissions and remove any that match.
5839 final List<String> SEGMENTS = uri.getPathSegments();
5840 if (SEGMENTS != null) {
5841 final int NS = SEGMENTS.size();
5842 int N = mGrantedUriPermissions.size();
5843 for (int i=0; i<N; i++) {
5844 HashMap<Uri, UriPermission> perms
5845 = mGrantedUriPermissions.valueAt(i);
5846 Iterator<UriPermission> it = perms.values().iterator();
5847 toploop:
5848 while (it.hasNext()) {
5849 UriPermission perm = it.next();
5850 Uri targetUri = perm.uri;
5851 if (!authority.equals(targetUri.getAuthority())) {
5852 continue;
5853 }
5854 List<String> targetSegments = targetUri.getPathSegments();
5855 if (targetSegments == null) {
5856 continue;
5857 }
5858 if (targetSegments.size() < NS) {
5859 continue;
5860 }
5861 for (int j=0; j<NS; j++) {
5862 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5863 continue toploop;
5864 }
5865 }
5866 perm.clearModes(modeFlags);
5867 if (perm.modeFlags == 0) {
5868 it.remove();
5869 }
5870 }
5871 if (perms.size() == 0) {
5872 mGrantedUriPermissions.remove(
5873 mGrantedUriPermissions.keyAt(i));
5874 N--;
5875 i--;
5876 }
5877 }
5878 }
5879 }
5880
5881 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5882 int modeFlags) {
5883 synchronized(this) {
5884 final ProcessRecord r = getRecordForAppLocked(caller);
5885 if (r == null) {
5886 throw new SecurityException("Unable to find app for caller "
5887 + caller
5888 + " when revoking permission to uri " + uri);
5889 }
5890 if (uri == null) {
5891 Log.w(TAG, "revokeUriPermission: null uri");
5892 return;
5893 }
5894
5895 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5896 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5897 if (modeFlags == 0) {
5898 return;
5899 }
5900
5901 final IPackageManager pm = ActivityThread.getPackageManager();
5902
5903 final String authority = uri.getAuthority();
5904 ProviderInfo pi = null;
5905 ContentProviderRecord cpr
5906 = (ContentProviderRecord)mProvidersByName.get(authority);
5907 if (cpr != null) {
5908 pi = cpr.info;
5909 } else {
5910 try {
5911 pi = pm.resolveContentProvider(authority,
5912 PackageManager.GET_URI_PERMISSION_PATTERNS);
5913 } catch (RemoteException ex) {
5914 }
5915 }
5916 if (pi == null) {
5917 Log.w(TAG, "No content provider found for: " + authority);
5918 return;
5919 }
5920
5921 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
5922 }
5923 }
5924
5925 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
5926 synchronized (this) {
5927 ProcessRecord app =
5928 who != null ? getRecordForAppLocked(who) : null;
5929 if (app == null) return;
5930
5931 Message msg = Message.obtain();
5932 msg.what = WAIT_FOR_DEBUGGER_MSG;
5933 msg.obj = app;
5934 msg.arg1 = waiting ? 1 : 0;
5935 mHandler.sendMessage(msg);
5936 }
5937 }
5938
5939 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
5940 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08005941 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005942 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08005943 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005944 }
5945
5946 // =========================================================
5947 // TASK MANAGEMENT
5948 // =========================================================
5949
5950 public List getTasks(int maxNum, int flags,
5951 IThumbnailReceiver receiver) {
5952 ArrayList list = new ArrayList();
5953
5954 PendingThumbnailsRecord pending = null;
5955 IApplicationThread topThumbnail = null;
5956 HistoryRecord topRecord = null;
5957
5958 synchronized(this) {
5959 if (localLOGV) Log.v(
5960 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
5961 + ", receiver=" + receiver);
5962
5963 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
5964 != PackageManager.PERMISSION_GRANTED) {
5965 if (receiver != null) {
5966 // If the caller wants to wait for pending thumbnails,
5967 // it ain't gonna get them.
5968 try {
5969 receiver.finished();
5970 } catch (RemoteException ex) {
5971 }
5972 }
5973 String msg = "Permission Denial: getTasks() from pid="
5974 + Binder.getCallingPid()
5975 + ", uid=" + Binder.getCallingUid()
5976 + " requires " + android.Manifest.permission.GET_TASKS;
5977 Log.w(TAG, msg);
5978 throw new SecurityException(msg);
5979 }
5980
5981 int pos = mHistory.size()-1;
5982 HistoryRecord next =
5983 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5984 HistoryRecord top = null;
5985 CharSequence topDescription = null;
5986 TaskRecord curTask = null;
5987 int numActivities = 0;
5988 int numRunning = 0;
5989 while (pos >= 0 && maxNum > 0) {
5990 final HistoryRecord r = next;
5991 pos--;
5992 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
5993
5994 // Initialize state for next task if needed.
5995 if (top == null ||
5996 (top.state == ActivityState.INITIALIZING
5997 && top.task == r.task)) {
5998 top = r;
5999 topDescription = r.description;
6000 curTask = r.task;
6001 numActivities = numRunning = 0;
6002 }
6003
6004 // Add 'r' into the current task.
6005 numActivities++;
6006 if (r.app != null && r.app.thread != null) {
6007 numRunning++;
6008 }
6009 if (topDescription == null) {
6010 topDescription = r.description;
6011 }
6012
6013 if (localLOGV) Log.v(
6014 TAG, r.intent.getComponent().flattenToShortString()
6015 + ": task=" + r.task);
6016
6017 // If the next one is a different task, generate a new
6018 // TaskInfo entry for what we have.
6019 if (next == null || next.task != curTask) {
6020 ActivityManager.RunningTaskInfo ci
6021 = new ActivityManager.RunningTaskInfo();
6022 ci.id = curTask.taskId;
6023 ci.baseActivity = r.intent.getComponent();
6024 ci.topActivity = top.intent.getComponent();
6025 ci.thumbnail = top.thumbnail;
6026 ci.description = topDescription;
6027 ci.numActivities = numActivities;
6028 ci.numRunning = numRunning;
6029 //System.out.println(
6030 // "#" + maxNum + ": " + " descr=" + ci.description);
6031 if (ci.thumbnail == null && receiver != null) {
6032 if (localLOGV) Log.v(
6033 TAG, "State=" + top.state + "Idle=" + top.idle
6034 + " app=" + top.app
6035 + " thr=" + (top.app != null ? top.app.thread : null));
6036 if (top.state == ActivityState.RESUMED
6037 || top.state == ActivityState.PAUSING) {
6038 if (top.idle && top.app != null
6039 && top.app.thread != null) {
6040 topRecord = top;
6041 topThumbnail = top.app.thread;
6042 } else {
6043 top.thumbnailNeeded = true;
6044 }
6045 }
6046 if (pending == null) {
6047 pending = new PendingThumbnailsRecord(receiver);
6048 }
6049 pending.pendingRecords.add(top);
6050 }
6051 list.add(ci);
6052 maxNum--;
6053 top = null;
6054 }
6055 }
6056
6057 if (pending != null) {
6058 mPendingThumbnails.add(pending);
6059 }
6060 }
6061
6062 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6063
6064 if (topThumbnail != null) {
6065 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6066 try {
6067 topThumbnail.requestThumbnail(topRecord);
6068 } catch (Exception e) {
6069 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6070 sendPendingThumbnail(null, topRecord, null, null, true);
6071 }
6072 }
6073
6074 if (pending == null && receiver != null) {
6075 // In this case all thumbnails were available and the client
6076 // is being asked to be told when the remaining ones come in...
6077 // which is unusually, since the top-most currently running
6078 // activity should never have a canned thumbnail! Oh well.
6079 try {
6080 receiver.finished();
6081 } catch (RemoteException ex) {
6082 }
6083 }
6084
6085 return list;
6086 }
6087
6088 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6089 int flags) {
6090 synchronized (this) {
6091 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6092 "getRecentTasks()");
6093
6094 final int N = mRecentTasks.size();
6095 ArrayList<ActivityManager.RecentTaskInfo> res
6096 = new ArrayList<ActivityManager.RecentTaskInfo>(
6097 maxNum < N ? maxNum : N);
6098 for (int i=0; i<N && maxNum > 0; i++) {
6099 TaskRecord tr = mRecentTasks.get(i);
6100 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6101 || (tr.intent == null)
6102 || ((tr.intent.getFlags()
6103 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6104 ActivityManager.RecentTaskInfo rti
6105 = new ActivityManager.RecentTaskInfo();
6106 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6107 rti.baseIntent = new Intent(
6108 tr.intent != null ? tr.intent : tr.affinityIntent);
6109 rti.origActivity = tr.origActivity;
6110 res.add(rti);
6111 maxNum--;
6112 }
6113 }
6114 return res;
6115 }
6116 }
6117
6118 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6119 int j;
6120 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6121 TaskRecord jt = startTask;
6122
6123 // First look backwards
6124 for (j=startIndex-1; j>=0; j--) {
6125 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6126 if (r.task != jt) {
6127 jt = r.task;
6128 if (affinity.equals(jt.affinity)) {
6129 return j;
6130 }
6131 }
6132 }
6133
6134 // Now look forwards
6135 final int N = mHistory.size();
6136 jt = startTask;
6137 for (j=startIndex+1; j<N; j++) {
6138 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6139 if (r.task != jt) {
6140 if (affinity.equals(jt.affinity)) {
6141 return j;
6142 }
6143 jt = r.task;
6144 }
6145 }
6146
6147 // Might it be at the top?
6148 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6149 return N-1;
6150 }
6151
6152 return -1;
6153 }
6154
6155 /**
6156 * Perform a reset of the given task, if needed as part of launching it.
6157 * Returns the new HistoryRecord at the top of the task.
6158 */
6159 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6160 HistoryRecord newActivity) {
6161 boolean forceReset = (newActivity.info.flags
6162 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6163 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6164 if ((newActivity.info.flags
6165 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6166 forceReset = true;
6167 }
6168 }
6169
6170 final TaskRecord task = taskTop.task;
6171
6172 // We are going to move through the history list so that we can look
6173 // at each activity 'target' with 'below' either the interesting
6174 // activity immediately below it in the stack or null.
6175 HistoryRecord target = null;
6176 int targetI = 0;
6177 int taskTopI = -1;
6178 int replyChainEnd = -1;
6179 int lastReparentPos = -1;
6180 for (int i=mHistory.size()-1; i>=-1; i--) {
6181 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6182
6183 if (below != null && below.finishing) {
6184 continue;
6185 }
6186 if (target == null) {
6187 target = below;
6188 targetI = i;
6189 // If we were in the middle of a reply chain before this
6190 // task, it doesn't appear like the root of the chain wants
6191 // anything interesting, so drop it.
6192 replyChainEnd = -1;
6193 continue;
6194 }
6195
6196 final int flags = target.info.flags;
6197
6198 final boolean finishOnTaskLaunch =
6199 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6200 final boolean allowTaskReparenting =
6201 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6202
6203 if (target.task == task) {
6204 // We are inside of the task being reset... we'll either
6205 // finish this activity, push it out for another task,
6206 // or leave it as-is. We only do this
6207 // for activities that are not the root of the task (since
6208 // if we finish the root, we may no longer have the task!).
6209 if (taskTopI < 0) {
6210 taskTopI = targetI;
6211 }
6212 if (below != null && below.task == task) {
6213 final boolean clearWhenTaskReset =
6214 (target.intent.getFlags()
6215 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006216 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006217 // If this activity is sending a reply to a previous
6218 // activity, we can't do anything with it now until
6219 // we reach the start of the reply chain.
6220 // XXX note that we are assuming the result is always
6221 // to the previous activity, which is almost always
6222 // the case but we really shouldn't count on.
6223 if (replyChainEnd < 0) {
6224 replyChainEnd = targetI;
6225 }
Ed Heyl73798232009-03-24 21:32:21 -07006226 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006227 && target.taskAffinity != null
6228 && !target.taskAffinity.equals(task.affinity)) {
6229 // If this activity has an affinity for another
6230 // task, then we need to move it out of here. We will
6231 // move it as far out of the way as possible, to the
6232 // bottom of the activity stack. This also keeps it
6233 // correctly ordered with any activities we previously
6234 // moved.
6235 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6236 if (target.taskAffinity != null
6237 && target.taskAffinity.equals(p.task.affinity)) {
6238 // If the activity currently at the bottom has the
6239 // same task affinity as the one we are moving,
6240 // then merge it into the same task.
6241 target.task = p.task;
6242 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6243 + " out to bottom task " + p.task);
6244 } else {
6245 mCurTask++;
6246 if (mCurTask <= 0) {
6247 mCurTask = 1;
6248 }
6249 target.task = new TaskRecord(mCurTask, target.info, null,
6250 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6251 target.task.affinityIntent = target.intent;
6252 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6253 + " out to new task " + target.task);
6254 }
6255 mWindowManager.setAppGroupId(target, task.taskId);
6256 if (replyChainEnd < 0) {
6257 replyChainEnd = targetI;
6258 }
6259 int dstPos = 0;
6260 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6261 p = (HistoryRecord)mHistory.get(srcPos);
6262 if (p.finishing) {
6263 continue;
6264 }
6265 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6266 + " out to target's task " + target.task);
6267 task.numActivities--;
6268 p.task = target.task;
6269 target.task.numActivities++;
6270 mHistory.remove(srcPos);
6271 mHistory.add(dstPos, p);
6272 mWindowManager.moveAppToken(dstPos, p);
6273 mWindowManager.setAppGroupId(p, p.task.taskId);
6274 dstPos++;
6275 if (VALIDATE_TOKENS) {
6276 mWindowManager.validateAppTokens(mHistory);
6277 }
6278 i++;
6279 }
6280 if (taskTop == p) {
6281 taskTop = below;
6282 }
6283 if (taskTopI == replyChainEnd) {
6284 taskTopI = -1;
6285 }
6286 replyChainEnd = -1;
6287 addRecentTask(target.task);
6288 } else if (forceReset || finishOnTaskLaunch
6289 || clearWhenTaskReset) {
6290 // If the activity should just be removed -- either
6291 // because it asks for it, or the task should be
6292 // cleared -- then finish it and anything that is
6293 // part of its reply chain.
6294 if (clearWhenTaskReset) {
6295 // In this case, we want to finish this activity
6296 // and everything above it, so be sneaky and pretend
6297 // like these are all in the reply chain.
6298 replyChainEnd = targetI+1;
6299 while (replyChainEnd < mHistory.size() &&
6300 ((HistoryRecord)mHistory.get(
6301 replyChainEnd)).task == task) {
6302 replyChainEnd++;
6303 }
6304 replyChainEnd--;
6305 } else if (replyChainEnd < 0) {
6306 replyChainEnd = targetI;
6307 }
6308 HistoryRecord p = null;
6309 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6310 p = (HistoryRecord)mHistory.get(srcPos);
6311 if (p.finishing) {
6312 continue;
6313 }
6314 if (finishActivityLocked(p, srcPos,
6315 Activity.RESULT_CANCELED, null, "reset")) {
6316 replyChainEnd--;
6317 srcPos--;
6318 }
6319 }
6320 if (taskTop == p) {
6321 taskTop = below;
6322 }
6323 if (taskTopI == replyChainEnd) {
6324 taskTopI = -1;
6325 }
6326 replyChainEnd = -1;
6327 } else {
6328 // If we were in the middle of a chain, well the
6329 // activity that started it all doesn't want anything
6330 // special, so leave it all as-is.
6331 replyChainEnd = -1;
6332 }
6333 } else {
6334 // Reached the bottom of the task -- any reply chain
6335 // should be left as-is.
6336 replyChainEnd = -1;
6337 }
6338
6339 } else if (target.resultTo != null) {
6340 // If this activity is sending a reply to a previous
6341 // activity, we can't do anything with it now until
6342 // we reach the start of the reply chain.
6343 // XXX note that we are assuming the result is always
6344 // to the previous activity, which is almost always
6345 // the case but we really shouldn't count on.
6346 if (replyChainEnd < 0) {
6347 replyChainEnd = targetI;
6348 }
6349
6350 } else if (taskTopI >= 0 && allowTaskReparenting
6351 && task.affinity != null
6352 && task.affinity.equals(target.taskAffinity)) {
6353 // We are inside of another task... if this activity has
6354 // an affinity for our task, then either remove it if we are
6355 // clearing or move it over to our task. Note that
6356 // we currently punt on the case where we are resetting a
6357 // task that is not at the top but who has activities above
6358 // with an affinity to it... this is really not a normal
6359 // case, and we will need to later pull that task to the front
6360 // and usually at that point we will do the reset and pick
6361 // up those remaining activities. (This only happens if
6362 // someone starts an activity in a new task from an activity
6363 // in a task that is not currently on top.)
6364 if (forceReset || finishOnTaskLaunch) {
6365 if (replyChainEnd < 0) {
6366 replyChainEnd = targetI;
6367 }
6368 HistoryRecord p = null;
6369 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6370 p = (HistoryRecord)mHistory.get(srcPos);
6371 if (p.finishing) {
6372 continue;
6373 }
6374 if (finishActivityLocked(p, srcPos,
6375 Activity.RESULT_CANCELED, null, "reset")) {
6376 taskTopI--;
6377 lastReparentPos--;
6378 replyChainEnd--;
6379 srcPos--;
6380 }
6381 }
6382 replyChainEnd = -1;
6383 } else {
6384 if (replyChainEnd < 0) {
6385 replyChainEnd = targetI;
6386 }
6387 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6388 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6389 if (p.finishing) {
6390 continue;
6391 }
6392 if (lastReparentPos < 0) {
6393 lastReparentPos = taskTopI;
6394 taskTop = p;
6395 } else {
6396 lastReparentPos--;
6397 }
6398 mHistory.remove(srcPos);
6399 p.task.numActivities--;
6400 p.task = task;
6401 mHistory.add(lastReparentPos, p);
6402 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6403 + " in to resetting task " + task);
6404 task.numActivities++;
6405 mWindowManager.moveAppToken(lastReparentPos, p);
6406 mWindowManager.setAppGroupId(p, p.task.taskId);
6407 if (VALIDATE_TOKENS) {
6408 mWindowManager.validateAppTokens(mHistory);
6409 }
6410 }
6411 replyChainEnd = -1;
6412
6413 // Now we've moved it in to place... but what if this is
6414 // a singleTop activity and we have put it on top of another
6415 // instance of the same activity? Then we drop the instance
6416 // below so it remains singleTop.
6417 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6418 for (int j=lastReparentPos-1; j>=0; j--) {
6419 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6420 if (p.finishing) {
6421 continue;
6422 }
6423 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6424 if (finishActivityLocked(p, j,
6425 Activity.RESULT_CANCELED, null, "replace")) {
6426 taskTopI--;
6427 lastReparentPos--;
6428 }
6429 }
6430 }
6431 }
6432 }
6433 }
6434
6435 target = below;
6436 targetI = i;
6437 }
6438
6439 return taskTop;
6440 }
6441
6442 /**
6443 * TODO: Add mWatcher hook
6444 */
6445 public void moveTaskToFront(int task) {
6446 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6447 "moveTaskToFront()");
6448
6449 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006450 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6451 Binder.getCallingUid(), "Task to front")) {
6452 return;
6453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006454 final long origId = Binder.clearCallingIdentity();
6455 try {
6456 int N = mRecentTasks.size();
6457 for (int i=0; i<N; i++) {
6458 TaskRecord tr = mRecentTasks.get(i);
6459 if (tr.taskId == task) {
6460 moveTaskToFrontLocked(tr);
6461 return;
6462 }
6463 }
6464 for (int i=mHistory.size()-1; i>=0; i--) {
6465 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6466 if (hr.task.taskId == task) {
6467 moveTaskToFrontLocked(hr.task);
6468 return;
6469 }
6470 }
6471 } finally {
6472 Binder.restoreCallingIdentity(origId);
6473 }
6474 }
6475 }
6476
6477 private final void moveTaskToFrontLocked(TaskRecord tr) {
6478 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6479
6480 final int task = tr.taskId;
6481 int top = mHistory.size()-1;
6482
6483 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6484 // nothing to do!
6485 return;
6486 }
6487
6488 if (DEBUG_TRANSITION) Log.v(TAG,
6489 "Prepare to front transition: task=" + tr);
6490 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6491
6492 ArrayList moved = new ArrayList();
6493
6494 // Applying the affinities may have removed entries from the history,
6495 // so get the size again.
6496 top = mHistory.size()-1;
6497 int pos = top;
6498
6499 // Shift all activities with this task up to the top
6500 // of the stack, keeping them in the same internal order.
6501 while (pos >= 0) {
6502 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6503 if (localLOGV) Log.v(
6504 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6505 boolean first = true;
6506 if (r.task.taskId == task) {
6507 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6508 mHistory.remove(pos);
6509 mHistory.add(top, r);
6510 moved.add(0, r);
6511 top--;
6512 if (first) {
6513 addRecentTask(r.task);
6514 first = false;
6515 }
6516 }
6517 pos--;
6518 }
6519
6520 mWindowManager.moveAppTokensToTop(moved);
6521 if (VALIDATE_TOKENS) {
6522 mWindowManager.validateAppTokens(mHistory);
6523 }
6524
6525 finishTaskMove(task);
6526 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6527 }
6528
6529 private final void finishTaskMove(int task) {
6530 resumeTopActivityLocked(null);
6531 }
6532
6533 public void moveTaskToBack(int task) {
6534 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6535 "moveTaskToBack()");
6536
6537 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006538 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6539 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6540 Binder.getCallingUid(), "Task to back")) {
6541 return;
6542 }
6543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006544 final long origId = Binder.clearCallingIdentity();
6545 moveTaskToBackLocked(task);
6546 Binder.restoreCallingIdentity(origId);
6547 }
6548 }
6549
6550 /**
6551 * Moves an activity, and all of the other activities within the same task, to the bottom
6552 * of the history stack. The activity's order within the task is unchanged.
6553 *
6554 * @param token A reference to the activity we wish to move
6555 * @param nonRoot If false then this only works if the activity is the root
6556 * of a task; if true it will work for any activity in a task.
6557 * @return Returns true if the move completed, false if not.
6558 */
6559 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6560 synchronized(this) {
6561 final long origId = Binder.clearCallingIdentity();
6562 int taskId = getTaskForActivityLocked(token, !nonRoot);
6563 if (taskId >= 0) {
6564 return moveTaskToBackLocked(taskId);
6565 }
6566 Binder.restoreCallingIdentity(origId);
6567 }
6568 return false;
6569 }
6570
6571 /**
6572 * Worker method for rearranging history stack. Implements the function of moving all
6573 * activities for a specific task (gathering them if disjoint) into a single group at the
6574 * bottom of the stack.
6575 *
6576 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6577 * to premeptively cancel the move.
6578 *
6579 * @param task The taskId to collect and move to the bottom.
6580 * @return Returns true if the move completed, false if not.
6581 */
6582 private final boolean moveTaskToBackLocked(int task) {
6583 Log.i(TAG, "moveTaskToBack: " + task);
6584
6585 // If we have a watcher, preflight the move before committing to it. First check
6586 // for *other* available tasks, but if none are available, then try again allowing the
6587 // current task to be selected.
6588 if (mWatcher != null) {
6589 HistoryRecord next = topRunningActivityLocked(null, task);
6590 if (next == null) {
6591 next = topRunningActivityLocked(null, 0);
6592 }
6593 if (next != null) {
6594 // ask watcher if this is allowed
6595 boolean moveOK = true;
6596 try {
6597 moveOK = mWatcher.activityResuming(next.packageName);
6598 } catch (RemoteException e) {
6599 mWatcher = null;
6600 }
6601 if (!moveOK) {
6602 return false;
6603 }
6604 }
6605 }
6606
6607 ArrayList moved = new ArrayList();
6608
6609 if (DEBUG_TRANSITION) Log.v(TAG,
6610 "Prepare to back transition: task=" + task);
6611 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6612
6613 final int N = mHistory.size();
6614 int bottom = 0;
6615 int pos = 0;
6616
6617 // Shift all activities with this task down to the bottom
6618 // of the stack, keeping them in the same internal order.
6619 while (pos < N) {
6620 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6621 if (localLOGV) Log.v(
6622 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6623 if (r.task.taskId == task) {
6624 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6625 mHistory.remove(pos);
6626 mHistory.add(bottom, r);
6627 moved.add(r);
6628 bottom++;
6629 }
6630 pos++;
6631 }
6632
6633 mWindowManager.moveAppTokensToBottom(moved);
6634 if (VALIDATE_TOKENS) {
6635 mWindowManager.validateAppTokens(mHistory);
6636 }
6637
6638 finishTaskMove(task);
6639 return true;
6640 }
6641
6642 public void moveTaskBackwards(int task) {
6643 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6644 "moveTaskBackwards()");
6645
6646 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006647 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6648 Binder.getCallingUid(), "Task backwards")) {
6649 return;
6650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006651 final long origId = Binder.clearCallingIdentity();
6652 moveTaskBackwardsLocked(task);
6653 Binder.restoreCallingIdentity(origId);
6654 }
6655 }
6656
6657 private final void moveTaskBackwardsLocked(int task) {
6658 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6659 }
6660
6661 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6662 synchronized(this) {
6663 return getTaskForActivityLocked(token, onlyRoot);
6664 }
6665 }
6666
6667 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6668 final int N = mHistory.size();
6669 TaskRecord lastTask = null;
6670 for (int i=0; i<N; i++) {
6671 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6672 if (r == token) {
6673 if (!onlyRoot || lastTask != r.task) {
6674 return r.task.taskId;
6675 }
6676 return -1;
6677 }
6678 lastTask = r.task;
6679 }
6680
6681 return -1;
6682 }
6683
6684 /**
6685 * Returns the top activity in any existing task matching the given
6686 * Intent. Returns null if no such task is found.
6687 */
6688 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6689 ComponentName cls = intent.getComponent();
6690 if (info.targetActivity != null) {
6691 cls = new ComponentName(info.packageName, info.targetActivity);
6692 }
6693
6694 TaskRecord cp = null;
6695
6696 final int N = mHistory.size();
6697 for (int i=(N-1); i>=0; i--) {
6698 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6699 if (!r.finishing && r.task != cp
6700 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6701 cp = r.task;
6702 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6703 // + "/aff=" + r.task.affinity + " to new cls="
6704 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6705 if (r.task.affinity != null) {
6706 if (r.task.affinity.equals(info.taskAffinity)) {
6707 //Log.i(TAG, "Found matching affinity!");
6708 return r;
6709 }
6710 } else if (r.task.intent != null
6711 && r.task.intent.getComponent().equals(cls)) {
6712 //Log.i(TAG, "Found matching class!");
6713 //dump();
6714 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6715 return r;
6716 } else if (r.task.affinityIntent != null
6717 && r.task.affinityIntent.getComponent().equals(cls)) {
6718 //Log.i(TAG, "Found matching class!");
6719 //dump();
6720 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6721 return r;
6722 }
6723 }
6724 }
6725
6726 return null;
6727 }
6728
6729 /**
6730 * Returns the first activity (starting from the top of the stack) that
6731 * is the same as the given activity. Returns null if no such activity
6732 * is found.
6733 */
6734 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6735 ComponentName cls = intent.getComponent();
6736 if (info.targetActivity != null) {
6737 cls = new ComponentName(info.packageName, info.targetActivity);
6738 }
6739
6740 final int N = mHistory.size();
6741 for (int i=(N-1); i>=0; i--) {
6742 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6743 if (!r.finishing) {
6744 if (r.intent.getComponent().equals(cls)) {
6745 //Log.i(TAG, "Found matching class!");
6746 //dump();
6747 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6748 return r;
6749 }
6750 }
6751 }
6752
6753 return null;
6754 }
6755
6756 public void finishOtherInstances(IBinder token, ComponentName className) {
6757 synchronized(this) {
6758 final long origId = Binder.clearCallingIdentity();
6759
6760 int N = mHistory.size();
6761 TaskRecord lastTask = null;
6762 for (int i=0; i<N; i++) {
6763 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6764 if (r.realActivity.equals(className)
6765 && r != token && lastTask != r.task) {
6766 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6767 null, "others")) {
6768 i--;
6769 N--;
6770 }
6771 }
6772 lastTask = r.task;
6773 }
6774
6775 Binder.restoreCallingIdentity(origId);
6776 }
6777 }
6778
6779 // =========================================================
6780 // THUMBNAILS
6781 // =========================================================
6782
6783 public void reportThumbnail(IBinder token,
6784 Bitmap thumbnail, CharSequence description) {
6785 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6786 final long origId = Binder.clearCallingIdentity();
6787 sendPendingThumbnail(null, token, thumbnail, description, true);
6788 Binder.restoreCallingIdentity(origId);
6789 }
6790
6791 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6792 Bitmap thumbnail, CharSequence description, boolean always) {
6793 TaskRecord task = null;
6794 ArrayList receivers = null;
6795
6796 //System.out.println("Send pending thumbnail: " + r);
6797
6798 synchronized(this) {
6799 if (r == null) {
6800 int index = indexOfTokenLocked(token, false);
6801 if (index < 0) {
6802 return;
6803 }
6804 r = (HistoryRecord)mHistory.get(index);
6805 }
6806 if (thumbnail == null) {
6807 thumbnail = r.thumbnail;
6808 description = r.description;
6809 }
6810 if (thumbnail == null && !always) {
6811 // If there is no thumbnail, and this entry is not actually
6812 // going away, then abort for now and pick up the next
6813 // thumbnail we get.
6814 return;
6815 }
6816 task = r.task;
6817
6818 int N = mPendingThumbnails.size();
6819 int i=0;
6820 while (i<N) {
6821 PendingThumbnailsRecord pr =
6822 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6823 //System.out.println("Looking in " + pr.pendingRecords);
6824 if (pr.pendingRecords.remove(r)) {
6825 if (receivers == null) {
6826 receivers = new ArrayList();
6827 }
6828 receivers.add(pr);
6829 if (pr.pendingRecords.size() == 0) {
6830 pr.finished = true;
6831 mPendingThumbnails.remove(i);
6832 N--;
6833 continue;
6834 }
6835 }
6836 i++;
6837 }
6838 }
6839
6840 if (receivers != null) {
6841 final int N = receivers.size();
6842 for (int i=0; i<N; i++) {
6843 try {
6844 PendingThumbnailsRecord pr =
6845 (PendingThumbnailsRecord)receivers.get(i);
6846 pr.receiver.newThumbnail(
6847 task != null ? task.taskId : -1, thumbnail, description);
6848 if (pr.finished) {
6849 pr.receiver.finished();
6850 }
6851 } catch (Exception e) {
6852 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6853 }
6854 }
6855 }
6856 }
6857
6858 // =========================================================
6859 // CONTENT PROVIDERS
6860 // =========================================================
6861
6862 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6863 List providers = null;
6864 try {
6865 providers = ActivityThread.getPackageManager().
6866 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006867 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006868 } catch (RemoteException ex) {
6869 }
6870 if (providers != null) {
6871 final int N = providers.size();
6872 for (int i=0; i<N; i++) {
6873 ProviderInfo cpi =
6874 (ProviderInfo)providers.get(i);
6875 ContentProviderRecord cpr =
6876 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6877 if (cpr == null) {
6878 cpr = new ContentProviderRecord(cpi, app.info);
6879 mProvidersByClass.put(cpi.name, cpr);
6880 }
6881 app.pubProviders.put(cpi.name, cpr);
6882 app.addPackage(cpi.applicationInfo.packageName);
6883 }
6884 }
6885 return providers;
6886 }
6887
6888 private final String checkContentProviderPermissionLocked(
6889 ProviderInfo cpi, ProcessRecord r, int mode) {
6890 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6891 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6892 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6893 cpi.exported ? -1 : cpi.applicationInfo.uid)
6894 == PackageManager.PERMISSION_GRANTED
6895 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6896 return null;
6897 }
6898 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6899 cpi.exported ? -1 : cpi.applicationInfo.uid)
6900 == PackageManager.PERMISSION_GRANTED) {
6901 return null;
6902 }
6903 String msg = "Permission Denial: opening provider " + cpi.name
6904 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
6905 + ", uid=" + callingUid + ") requires "
6906 + cpi.readPermission + " or " + cpi.writePermission;
6907 Log.w(TAG, msg);
6908 return msg;
6909 }
6910
6911 private final ContentProviderHolder getContentProviderImpl(
6912 IApplicationThread caller, String name) {
6913 ContentProviderRecord cpr;
6914 ProviderInfo cpi = null;
6915
6916 synchronized(this) {
6917 ProcessRecord r = null;
6918 if (caller != null) {
6919 r = getRecordForAppLocked(caller);
6920 if (r == null) {
6921 throw new SecurityException(
6922 "Unable to find app for caller " + caller
6923 + " (pid=" + Binder.getCallingPid()
6924 + ") when getting content provider " + name);
6925 }
6926 }
6927
6928 // First check if this content provider has been published...
6929 cpr = (ContentProviderRecord)mProvidersByName.get(name);
6930 if (cpr != null) {
6931 cpi = cpr.info;
6932 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6933 return new ContentProviderHolder(cpi,
6934 cpi.readPermission != null
6935 ? cpi.readPermission : cpi.writePermission);
6936 }
6937
6938 if (r != null && cpr.canRunHere(r)) {
6939 // This provider has been published or is in the process
6940 // of being published... but it is also allowed to run
6941 // in the caller's process, so don't make a connection
6942 // and just let the caller instantiate its own instance.
6943 if (cpr.provider != null) {
6944 // don't give caller the provider object, it needs
6945 // to make its own.
6946 cpr = new ContentProviderRecord(cpr);
6947 }
6948 return cpr;
6949 }
6950
6951 final long origId = Binder.clearCallingIdentity();
6952
6953 // In this case the provider is a single instance, so we can
6954 // return it right away.
6955 if (r != null) {
6956 r.conProviders.add(cpr);
6957 cpr.clients.add(r);
6958 } else {
6959 cpr.externals++;
6960 }
6961
6962 if (cpr.app != null) {
6963 updateOomAdjLocked(cpr.app);
6964 }
6965
6966 Binder.restoreCallingIdentity(origId);
6967
6968 } else {
6969 try {
6970 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07006971 resolveContentProvider(name,
6972 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006973 } catch (RemoteException ex) {
6974 }
6975 if (cpi == null) {
6976 return null;
6977 }
6978
6979 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6980 return new ContentProviderHolder(cpi,
6981 cpi.readPermission != null
6982 ? cpi.readPermission : cpi.writePermission);
6983 }
6984
6985 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6986 final boolean firstClass = cpr == null;
6987 if (firstClass) {
6988 try {
6989 ApplicationInfo ai =
6990 ActivityThread.getPackageManager().
6991 getApplicationInfo(
6992 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006993 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006994 if (ai == null) {
6995 Log.w(TAG, "No package info for content provider "
6996 + cpi.name);
6997 return null;
6998 }
6999 cpr = new ContentProviderRecord(cpi, ai);
7000 } catch (RemoteException ex) {
7001 // pm is in same process, this will never happen.
7002 }
7003 }
7004
7005 if (r != null && cpr.canRunHere(r)) {
7006 // If this is a multiprocess provider, then just return its
7007 // info and allow the caller to instantiate it. Only do
7008 // this if the provider is the same user as the caller's
7009 // process, or can run as root (so can be in any process).
7010 return cpr;
7011 }
7012
7013 if (false) {
7014 RuntimeException e = new RuntimeException("foo");
7015 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7016 // + " pruid " + ai.uid + "): " + cpi.className, e);
7017 }
7018
7019 // This is single process, and our app is now connecting to it.
7020 // See if we are already in the process of launching this
7021 // provider.
7022 final int N = mLaunchingProviders.size();
7023 int i;
7024 for (i=0; i<N; i++) {
7025 if (mLaunchingProviders.get(i) == cpr) {
7026 break;
7027 }
7028 if (false) {
7029 final ContentProviderRecord rec =
7030 (ContentProviderRecord)mLaunchingProviders.get(i);
7031 if (rec.info.name.equals(cpr.info.name)) {
7032 cpr = rec;
7033 break;
7034 }
7035 }
7036 }
7037
7038 // If the provider is not already being launched, then get it
7039 // started.
7040 if (i >= N) {
7041 final long origId = Binder.clearCallingIdentity();
7042 ProcessRecord proc = startProcessLocked(cpi.processName,
7043 cpr.appInfo, false, 0, "content provider",
7044 new ComponentName(cpi.applicationInfo.packageName,
7045 cpi.name));
7046 if (proc == null) {
7047 Log.w(TAG, "Unable to launch app "
7048 + cpi.applicationInfo.packageName + "/"
7049 + cpi.applicationInfo.uid + " for provider "
7050 + name + ": process is bad");
7051 return null;
7052 }
7053 cpr.launchingApp = proc;
7054 mLaunchingProviders.add(cpr);
7055 Binder.restoreCallingIdentity(origId);
7056 }
7057
7058 // Make sure the provider is published (the same provider class
7059 // may be published under multiple names).
7060 if (firstClass) {
7061 mProvidersByClass.put(cpi.name, cpr);
7062 }
7063 mProvidersByName.put(name, cpr);
7064
7065 if (r != null) {
7066 r.conProviders.add(cpr);
7067 cpr.clients.add(r);
7068 } else {
7069 cpr.externals++;
7070 }
7071 }
7072 }
7073
7074 // Wait for the provider to be published...
7075 synchronized (cpr) {
7076 while (cpr.provider == null) {
7077 if (cpr.launchingApp == null) {
7078 Log.w(TAG, "Unable to launch app "
7079 + cpi.applicationInfo.packageName + "/"
7080 + cpi.applicationInfo.uid + " for provider "
7081 + name + ": launching app became null");
7082 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7083 cpi.applicationInfo.packageName,
7084 cpi.applicationInfo.uid, name);
7085 return null;
7086 }
7087 try {
7088 cpr.wait();
7089 } catch (InterruptedException ex) {
7090 }
7091 }
7092 }
7093 return cpr;
7094 }
7095
7096 public final ContentProviderHolder getContentProvider(
7097 IApplicationThread caller, String name) {
7098 if (caller == null) {
7099 String msg = "null IApplicationThread when getting content provider "
7100 + name;
7101 Log.w(TAG, msg);
7102 throw new SecurityException(msg);
7103 }
7104
7105 return getContentProviderImpl(caller, name);
7106 }
7107
7108 private ContentProviderHolder getContentProviderExternal(String name) {
7109 return getContentProviderImpl(null, name);
7110 }
7111
7112 /**
7113 * Drop a content provider from a ProcessRecord's bookkeeping
7114 * @param cpr
7115 */
7116 public void removeContentProvider(IApplicationThread caller, String name) {
7117 synchronized (this) {
7118 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7119 if(cpr == null) {
7120 //remove from mProvidersByClass
7121 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7122 return;
7123 }
7124 final ProcessRecord r = getRecordForAppLocked(caller);
7125 if (r == null) {
7126 throw new SecurityException(
7127 "Unable to find app for caller " + caller +
7128 " when removing content provider " + name);
7129 }
7130 //update content provider record entry info
7131 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7132 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7133 r.info.processName+" from process "+localCpr.appInfo.processName);
7134 if(localCpr.appInfo.processName == r.info.processName) {
7135 //should not happen. taken care of as a local provider
7136 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7137 return;
7138 } else {
7139 localCpr.clients.remove(r);
7140 r.conProviders.remove(localCpr);
7141 }
7142 updateOomAdjLocked();
7143 }
7144 }
7145
7146 private void removeContentProviderExternal(String name) {
7147 synchronized (this) {
7148 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7149 if(cpr == null) {
7150 //remove from mProvidersByClass
7151 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7152 return;
7153 }
7154
7155 //update content provider record entry info
7156 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7157 localCpr.externals--;
7158 if (localCpr.externals < 0) {
7159 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7160 }
7161 updateOomAdjLocked();
7162 }
7163 }
7164
7165 public final void publishContentProviders(IApplicationThread caller,
7166 List<ContentProviderHolder> providers) {
7167 if (providers == null) {
7168 return;
7169 }
7170
7171 synchronized(this) {
7172 final ProcessRecord r = getRecordForAppLocked(caller);
7173 if (r == null) {
7174 throw new SecurityException(
7175 "Unable to find app for caller " + caller
7176 + " (pid=" + Binder.getCallingPid()
7177 + ") when publishing content providers");
7178 }
7179
7180 final long origId = Binder.clearCallingIdentity();
7181
7182 final int N = providers.size();
7183 for (int i=0; i<N; i++) {
7184 ContentProviderHolder src = providers.get(i);
7185 if (src == null || src.info == null || src.provider == null) {
7186 continue;
7187 }
7188 ContentProviderRecord dst =
7189 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7190 if (dst != null) {
7191 mProvidersByClass.put(dst.info.name, dst);
7192 String names[] = dst.info.authority.split(";");
7193 for (int j = 0; j < names.length; j++) {
7194 mProvidersByName.put(names[j], dst);
7195 }
7196
7197 int NL = mLaunchingProviders.size();
7198 int j;
7199 for (j=0; j<NL; j++) {
7200 if (mLaunchingProviders.get(j) == dst) {
7201 mLaunchingProviders.remove(j);
7202 j--;
7203 NL--;
7204 }
7205 }
7206 synchronized (dst) {
7207 dst.provider = src.provider;
7208 dst.app = r;
7209 dst.notifyAll();
7210 }
7211 updateOomAdjLocked(r);
7212 }
7213 }
7214
7215 Binder.restoreCallingIdentity(origId);
7216 }
7217 }
7218
7219 public static final void installSystemProviders() {
7220 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7221 List providers = mSelf.generateApplicationProvidersLocked(app);
7222 mSystemThread.installSystemProviders(providers);
7223 }
7224
7225 // =========================================================
7226 // GLOBAL MANAGEMENT
7227 // =========================================================
7228
7229 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7230 ApplicationInfo info, String customProcess) {
7231 String proc = customProcess != null ? customProcess : info.processName;
7232 BatteryStatsImpl.Uid.Proc ps = null;
7233 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7234 synchronized (stats) {
7235 ps = stats.getProcessStatsLocked(info.uid, proc);
7236 }
7237 return new ProcessRecord(ps, thread, info, proc);
7238 }
7239
7240 final ProcessRecord addAppLocked(ApplicationInfo info) {
7241 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7242
7243 if (app == null) {
7244 app = newProcessRecordLocked(null, info, null);
7245 mProcessNames.put(info.processName, info.uid, app);
7246 updateLRUListLocked(app, true);
7247 }
7248
7249 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7250 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7251 app.persistent = true;
7252 app.maxAdj = CORE_SERVER_ADJ;
7253 }
7254 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7255 mPersistentStartingProcesses.add(app);
7256 startProcessLocked(app, "added application", app.processName);
7257 }
7258
7259 return app;
7260 }
7261
7262 public void unhandledBack() {
7263 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7264 "unhandledBack()");
7265
7266 synchronized(this) {
7267 int count = mHistory.size();
7268 if (Config.LOGD) Log.d(
7269 TAG, "Performing unhandledBack(): stack size = " + count);
7270 if (count > 1) {
7271 final long origId = Binder.clearCallingIdentity();
7272 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7273 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7274 Binder.restoreCallingIdentity(origId);
7275 }
7276 }
7277 }
7278
7279 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7280 String name = uri.getAuthority();
7281 ContentProviderHolder cph = getContentProviderExternal(name);
7282 ParcelFileDescriptor pfd = null;
7283 if (cph != null) {
7284 // We record the binder invoker's uid in thread-local storage before
7285 // going to the content provider to open the file. Later, in the code
7286 // that handles all permissions checks, we look for this uid and use
7287 // that rather than the Activity Manager's own uid. The effect is that
7288 // we do the check against the caller's permissions even though it looks
7289 // to the content provider like the Activity Manager itself is making
7290 // the request.
7291 sCallerIdentity.set(new Identity(
7292 Binder.getCallingPid(), Binder.getCallingUid()));
7293 try {
7294 pfd = cph.provider.openFile(uri, "r");
7295 } catch (FileNotFoundException e) {
7296 // do nothing; pfd will be returned null
7297 } finally {
7298 // Ensure that whatever happens, we clean up the identity state
7299 sCallerIdentity.remove();
7300 }
7301
7302 // We've got the fd now, so we're done with the provider.
7303 removeContentProviderExternal(name);
7304 } else {
7305 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7306 }
7307 return pfd;
7308 }
7309
7310 public void goingToSleep() {
7311 synchronized(this) {
7312 mSleeping = true;
7313 mWindowManager.setEventDispatching(false);
7314
7315 if (mResumedActivity != null) {
7316 pauseIfSleepingLocked();
7317 } else {
7318 Log.w(TAG, "goingToSleep with no resumed activity!");
7319 }
7320 }
7321 }
7322
Dianne Hackborn55280a92009-05-07 15:53:46 -07007323 public boolean shutdown(int timeout) {
7324 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7325 != PackageManager.PERMISSION_GRANTED) {
7326 throw new SecurityException("Requires permission "
7327 + android.Manifest.permission.SHUTDOWN);
7328 }
7329
7330 boolean timedout = false;
7331
7332 synchronized(this) {
7333 mShuttingDown = true;
7334 mWindowManager.setEventDispatching(false);
7335
7336 if (mResumedActivity != null) {
7337 pauseIfSleepingLocked();
7338 final long endTime = System.currentTimeMillis() + timeout;
7339 while (mResumedActivity != null || mPausingActivity != null) {
7340 long delay = endTime - System.currentTimeMillis();
7341 if (delay <= 0) {
7342 Log.w(TAG, "Activity manager shutdown timed out");
7343 timedout = true;
7344 break;
7345 }
7346 try {
7347 this.wait();
7348 } catch (InterruptedException e) {
7349 }
7350 }
7351 }
7352 }
7353
7354 mUsageStatsService.shutdown();
7355 mBatteryStatsService.shutdown();
7356
7357 return timedout;
7358 }
7359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007360 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007361 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007362 if (!mGoingToSleep.isHeld()) {
7363 mGoingToSleep.acquire();
7364 if (mLaunchingActivity.isHeld()) {
7365 mLaunchingActivity.release();
7366 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7367 }
7368 }
7369
7370 // If we are not currently pausing an activity, get the current
7371 // one to pause. If we are pausing one, we will just let that stuff
7372 // run and release the wake lock when all done.
7373 if (mPausingActivity == null) {
7374 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7375 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7376 startPausingLocked(false, true);
7377 }
7378 }
7379 }
7380
7381 public void wakingUp() {
7382 synchronized(this) {
7383 if (mGoingToSleep.isHeld()) {
7384 mGoingToSleep.release();
7385 }
7386 mWindowManager.setEventDispatching(true);
7387 mSleeping = false;
7388 resumeTopActivityLocked(null);
7389 }
7390 }
7391
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007392 public void stopAppSwitches() {
7393 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7394 != PackageManager.PERMISSION_GRANTED) {
7395 throw new SecurityException("Requires permission "
7396 + android.Manifest.permission.STOP_APP_SWITCHES);
7397 }
7398
7399 synchronized(this) {
7400 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7401 + APP_SWITCH_DELAY_TIME;
7402 mDidAppSwitch = false;
7403 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7404 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7405 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7406 }
7407 }
7408
7409 public void resumeAppSwitches() {
7410 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7411 != PackageManager.PERMISSION_GRANTED) {
7412 throw new SecurityException("Requires permission "
7413 + android.Manifest.permission.STOP_APP_SWITCHES);
7414 }
7415
7416 synchronized(this) {
7417 // Note that we don't execute any pending app switches... we will
7418 // let those wait until either the timeout, or the next start
7419 // activity request.
7420 mAppSwitchesAllowedTime = 0;
7421 }
7422 }
7423
7424 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7425 String name) {
7426 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7427 return true;
7428 }
7429
7430 final int perm = checkComponentPermission(
7431 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7432 callingUid, -1);
7433 if (perm == PackageManager.PERMISSION_GRANTED) {
7434 return true;
7435 }
7436
7437 Log.w(TAG, name + " request from " + callingUid + " stopped");
7438 return false;
7439 }
7440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007441 public void setDebugApp(String packageName, boolean waitForDebugger,
7442 boolean persistent) {
7443 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7444 "setDebugApp()");
7445
7446 // Note that this is not really thread safe if there are multiple
7447 // callers into it at the same time, but that's not a situation we
7448 // care about.
7449 if (persistent) {
7450 final ContentResolver resolver = mContext.getContentResolver();
7451 Settings.System.putString(
7452 resolver, Settings.System.DEBUG_APP,
7453 packageName);
7454 Settings.System.putInt(
7455 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7456 waitForDebugger ? 1 : 0);
7457 }
7458
7459 synchronized (this) {
7460 if (!persistent) {
7461 mOrigDebugApp = mDebugApp;
7462 mOrigWaitForDebugger = mWaitForDebugger;
7463 }
7464 mDebugApp = packageName;
7465 mWaitForDebugger = waitForDebugger;
7466 mDebugTransient = !persistent;
7467 if (packageName != null) {
7468 final long origId = Binder.clearCallingIdentity();
7469 uninstallPackageLocked(packageName, -1, false);
7470 Binder.restoreCallingIdentity(origId);
7471 }
7472 }
7473 }
7474
7475 public void setAlwaysFinish(boolean enabled) {
7476 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7477 "setAlwaysFinish()");
7478
7479 Settings.System.putInt(
7480 mContext.getContentResolver(),
7481 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7482
7483 synchronized (this) {
7484 mAlwaysFinishActivities = enabled;
7485 }
7486 }
7487
7488 public void setActivityWatcher(IActivityWatcher watcher) {
7489 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7490 "setActivityWatcher()");
7491 synchronized (this) {
7492 mWatcher = watcher;
7493 }
7494 }
7495
7496 public final void enterSafeMode() {
7497 synchronized(this) {
7498 // It only makes sense to do this before the system is ready
7499 // and started launching other packages.
7500 if (!mSystemReady) {
7501 try {
7502 ActivityThread.getPackageManager().enterSafeMode();
7503 } catch (RemoteException e) {
7504 }
7505
7506 View v = LayoutInflater.from(mContext).inflate(
7507 com.android.internal.R.layout.safe_mode, null);
7508 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7509 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7510 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7511 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7512 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7513 lp.format = v.getBackground().getOpacity();
7514 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7515 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7516 ((WindowManager)mContext.getSystemService(
7517 Context.WINDOW_SERVICE)).addView(v, lp);
7518 }
7519 }
7520 }
7521
7522 public void noteWakeupAlarm(IIntentSender sender) {
7523 if (!(sender instanceof PendingIntentRecord)) {
7524 return;
7525 }
7526 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7527 synchronized (stats) {
7528 if (mBatteryStatsService.isOnBattery()) {
7529 mBatteryStatsService.enforceCallingPermission();
7530 PendingIntentRecord rec = (PendingIntentRecord)sender;
7531 int MY_UID = Binder.getCallingUid();
7532 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7533 BatteryStatsImpl.Uid.Pkg pkg =
7534 stats.getPackageStatsLocked(uid, rec.key.packageName);
7535 pkg.incWakeupsLocked();
7536 }
7537 }
7538 }
7539
7540 public boolean killPidsForMemory(int[] pids) {
7541 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7542 throw new SecurityException("killPidsForMemory only available to the system");
7543 }
7544
7545 // XXX Note: don't acquire main activity lock here, because the window
7546 // manager calls in with its locks held.
7547
7548 boolean killed = false;
7549 synchronized (mPidsSelfLocked) {
7550 int[] types = new int[pids.length];
7551 int worstType = 0;
7552 for (int i=0; i<pids.length; i++) {
7553 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7554 if (proc != null) {
7555 int type = proc.setAdj;
7556 types[i] = type;
7557 if (type > worstType) {
7558 worstType = type;
7559 }
7560 }
7561 }
7562
7563 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7564 // then constrain it so we will kill all hidden procs.
7565 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7566 worstType = HIDDEN_APP_MIN_ADJ;
7567 }
7568 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7569 for (int i=0; i<pids.length; i++) {
7570 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7571 if (proc == null) {
7572 continue;
7573 }
7574 int adj = proc.setAdj;
7575 if (adj >= worstType) {
7576 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7577 + adj + ")");
7578 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7579 proc.processName, adj);
7580 killed = true;
7581 Process.killProcess(pids[i]);
7582 }
7583 }
7584 }
7585 return killed;
7586 }
7587
7588 public void reportPss(IApplicationThread caller, int pss) {
7589 Watchdog.PssRequestor req;
7590 String name;
7591 ProcessRecord callerApp;
7592 synchronized (this) {
7593 if (caller == null) {
7594 return;
7595 }
7596 callerApp = getRecordForAppLocked(caller);
7597 if (callerApp == null) {
7598 return;
7599 }
7600 callerApp.lastPss = pss;
7601 req = callerApp;
7602 name = callerApp.processName;
7603 }
7604 Watchdog.getInstance().reportPss(req, name, pss);
7605 if (!callerApp.persistent) {
7606 removeRequestedPss(callerApp);
7607 }
7608 }
7609
7610 public void requestPss(Runnable completeCallback) {
7611 ArrayList<ProcessRecord> procs;
7612 synchronized (this) {
7613 mRequestPssCallback = completeCallback;
7614 mRequestPssList.clear();
7615 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7616 ProcessRecord proc = mLRUProcesses.get(i);
7617 if (!proc.persistent) {
7618 mRequestPssList.add(proc);
7619 }
7620 }
7621 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7622 }
7623
7624 int oldPri = Process.getThreadPriority(Process.myTid());
7625 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7626 for (int i=procs.size()-1; i>=0; i--) {
7627 ProcessRecord proc = procs.get(i);
7628 proc.lastPss = 0;
7629 proc.requestPss();
7630 }
7631 Process.setThreadPriority(oldPri);
7632 }
7633
7634 void removeRequestedPss(ProcessRecord proc) {
7635 Runnable callback = null;
7636 synchronized (this) {
7637 if (mRequestPssList.remove(proc)) {
7638 if (mRequestPssList.size() == 0) {
7639 callback = mRequestPssCallback;
7640 mRequestPssCallback = null;
7641 }
7642 }
7643 }
7644
7645 if (callback != null) {
7646 callback.run();
7647 }
7648 }
7649
7650 public void collectPss(Watchdog.PssStats stats) {
7651 stats.mEmptyPss = 0;
7652 stats.mEmptyCount = 0;
7653 stats.mBackgroundPss = 0;
7654 stats.mBackgroundCount = 0;
7655 stats.mServicePss = 0;
7656 stats.mServiceCount = 0;
7657 stats.mVisiblePss = 0;
7658 stats.mVisibleCount = 0;
7659 stats.mForegroundPss = 0;
7660 stats.mForegroundCount = 0;
7661 stats.mNoPssCount = 0;
7662 synchronized (this) {
7663 int i;
7664 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7665 ? mProcDeaths.length : stats.mProcDeaths.length;
7666 int aggr = 0;
7667 for (i=0; i<NPD; i++) {
7668 aggr += mProcDeaths[i];
7669 stats.mProcDeaths[i] = aggr;
7670 }
7671 while (i<stats.mProcDeaths.length) {
7672 stats.mProcDeaths[i] = 0;
7673 i++;
7674 }
7675
7676 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7677 ProcessRecord proc = mLRUProcesses.get(i);
7678 if (proc.persistent) {
7679 continue;
7680 }
7681 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7682 if (proc.lastPss == 0) {
7683 stats.mNoPssCount++;
7684 continue;
7685 }
7686 if (proc.setAdj == EMPTY_APP_ADJ) {
7687 stats.mEmptyPss += proc.lastPss;
7688 stats.mEmptyCount++;
7689 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7690 stats.mEmptyPss += proc.lastPss;
7691 stats.mEmptyCount++;
7692 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7693 stats.mBackgroundPss += proc.lastPss;
7694 stats.mBackgroundCount++;
7695 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7696 stats.mVisiblePss += proc.lastPss;
7697 stats.mVisibleCount++;
7698 } else {
7699 stats.mForegroundPss += proc.lastPss;
7700 stats.mForegroundCount++;
7701 }
7702 }
7703 }
7704 }
7705
7706 public final void startRunning(String pkg, String cls, String action,
7707 String data) {
7708 synchronized(this) {
7709 if (mStartRunning) {
7710 return;
7711 }
7712 mStartRunning = true;
7713 mTopComponent = pkg != null && cls != null
7714 ? new ComponentName(pkg, cls) : null;
7715 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7716 mTopData = data;
7717 if (!mSystemReady) {
7718 return;
7719 }
7720 }
7721
7722 systemReady();
7723 }
7724
7725 private void retrieveSettings() {
7726 final ContentResolver resolver = mContext.getContentResolver();
7727 String debugApp = Settings.System.getString(
7728 resolver, Settings.System.DEBUG_APP);
7729 boolean waitForDebugger = Settings.System.getInt(
7730 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7731 boolean alwaysFinishActivities = Settings.System.getInt(
7732 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7733
7734 Configuration configuration = new Configuration();
7735 Settings.System.getConfiguration(resolver, configuration);
7736
7737 synchronized (this) {
7738 mDebugApp = mOrigDebugApp = debugApp;
7739 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7740 mAlwaysFinishActivities = alwaysFinishActivities;
7741 // This happens before any activities are started, so we can
7742 // change mConfiguration in-place.
7743 mConfiguration.updateFrom(configuration);
7744 }
7745 }
7746
7747 public boolean testIsSystemReady() {
7748 // no need to synchronize(this) just to read & return the value
7749 return mSystemReady;
7750 }
7751
7752 public void systemReady() {
7753 // In the simulator, startRunning will never have been called, which
7754 // normally sets a few crucial variables. Do it here instead.
7755 if (!Process.supportsProcesses()) {
7756 mStartRunning = true;
7757 mTopAction = Intent.ACTION_MAIN;
7758 }
7759
7760 synchronized(this) {
7761 if (mSystemReady) {
7762 return;
7763 }
7764 mSystemReady = true;
7765 if (!mStartRunning) {
7766 return;
7767 }
7768 }
7769
7770 if (Config.LOGD) Log.d(TAG, "Start running!");
7771 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7772 SystemClock.uptimeMillis());
7773
7774 synchronized(this) {
7775 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7776 ResolveInfo ri = mContext.getPackageManager()
7777 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007778 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007779 CharSequence errorMsg = null;
7780 if (ri != null) {
7781 ActivityInfo ai = ri.activityInfo;
7782 ApplicationInfo app = ai.applicationInfo;
7783 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7784 mTopAction = Intent.ACTION_FACTORY_TEST;
7785 mTopData = null;
7786 mTopComponent = new ComponentName(app.packageName,
7787 ai.name);
7788 } else {
7789 errorMsg = mContext.getResources().getText(
7790 com.android.internal.R.string.factorytest_not_system);
7791 }
7792 } else {
7793 errorMsg = mContext.getResources().getText(
7794 com.android.internal.R.string.factorytest_no_action);
7795 }
7796 if (errorMsg != null) {
7797 mTopAction = null;
7798 mTopData = null;
7799 mTopComponent = null;
7800 Message msg = Message.obtain();
7801 msg.what = SHOW_FACTORY_ERROR_MSG;
7802 msg.getData().putCharSequence("msg", errorMsg);
7803 mHandler.sendMessage(msg);
7804 }
7805 }
7806 }
7807
7808 retrieveSettings();
7809
7810 synchronized (this) {
7811 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7812 try {
7813 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007814 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007815 if (apps != null) {
7816 int N = apps.size();
7817 int i;
7818 for (i=0; i<N; i++) {
7819 ApplicationInfo info
7820 = (ApplicationInfo)apps.get(i);
7821 if (info != null &&
7822 !info.packageName.equals("android")) {
7823 addAppLocked(info);
7824 }
7825 }
7826 }
7827 } catch (RemoteException ex) {
7828 // pm is in same process, this will never happen.
7829 }
7830 }
7831
7832 try {
7833 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7834 Message msg = Message.obtain();
7835 msg.what = SHOW_UID_ERROR_MSG;
7836 mHandler.sendMessage(msg);
7837 }
7838 } catch (RemoteException e) {
7839 }
7840
7841 // Start up initial activity.
7842 mBooting = true;
7843 resumeTopActivityLocked(null);
7844 }
7845 }
7846
7847 boolean makeAppCrashingLocked(ProcessRecord app,
7848 String tag, String shortMsg, String longMsg, byte[] crashData) {
7849 app.crashing = true;
7850 app.crashingReport = generateProcessError(app,
7851 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7852 startAppProblemLocked(app);
7853 app.stopFreezingAllLocked();
7854 return handleAppCrashLocked(app);
7855 }
7856
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007857 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7858 IPackageManager pm = ActivityThread.getPackageManager();
7859 try {
7860 // was an installer package name specified when this app was
7861 // installed?
7862 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7863 if (installerPackageName == null) {
7864 return null;
7865 }
7866
7867 // is there an Activity in this package that handles ACTION_APP_ERROR?
7868 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
7869 ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
7870 if (info == null || info.activityInfo == null) {
7871 return null;
7872 }
7873
7874 return new ComponentName(installerPackageName, info.activityInfo.name);
7875 } catch (RemoteException e) {
7876 // will return null and no error report will be delivered
7877 }
7878 return null;
7879 }
7880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007881 void makeAppNotRespondingLocked(ProcessRecord app,
7882 String tag, String shortMsg, String longMsg, byte[] crashData) {
7883 app.notResponding = true;
7884 app.notRespondingReport = generateProcessError(app,
7885 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7886 crashData);
7887 startAppProblemLocked(app);
7888 app.stopFreezingAllLocked();
7889 }
7890
7891 /**
7892 * Generate a process error record, suitable for attachment to a ProcessRecord.
7893 *
7894 * @param app The ProcessRecord in which the error occurred.
7895 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7896 * ActivityManager.AppErrorStateInfo
7897 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7898 * @param shortMsg Short message describing the crash.
7899 * @param longMsg Long message describing the crash.
7900 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7901 *
7902 * @return Returns a fully-formed AppErrorStateInfo record.
7903 */
7904 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
7905 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
7906 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
7907
7908 report.condition = condition;
7909 report.processName = app.processName;
7910 report.pid = app.pid;
7911 report.uid = app.info.uid;
7912 report.tag = tag;
7913 report.shortMsg = shortMsg;
7914 report.longMsg = longMsg;
7915 report.crashData = crashData;
7916
7917 return report;
7918 }
7919
7920 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
7921 boolean crashed) {
7922 synchronized (this) {
7923 app.crashing = false;
7924 app.crashingReport = null;
7925 app.notResponding = false;
7926 app.notRespondingReport = null;
7927 if (app.anrDialog == fromDialog) {
7928 app.anrDialog = null;
7929 }
7930 if (app.waitDialog == fromDialog) {
7931 app.waitDialog = null;
7932 }
7933 if (app.pid > 0 && app.pid != MY_PID) {
7934 if (crashed) {
7935 handleAppCrashLocked(app);
7936 }
7937 Log.i(ActivityManagerService.TAG, "Killing process "
7938 + app.processName
7939 + " (pid=" + app.pid + ") at user's request");
7940 Process.killProcess(app.pid);
7941 }
7942
7943 }
7944 }
7945
7946 boolean handleAppCrashLocked(ProcessRecord app) {
7947 long now = SystemClock.uptimeMillis();
7948
7949 Long crashTime = mProcessCrashTimes.get(app.info.processName,
7950 app.info.uid);
7951 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
7952 // This process loses!
7953 Log.w(TAG, "Process " + app.info.processName
7954 + " has crashed too many times: killing!");
7955 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
7956 app.info.processName, app.info.uid);
7957 killServicesLocked(app, false);
7958 for (int i=mHistory.size()-1; i>=0; i--) {
7959 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7960 if (r.app == app) {
7961 if (Config.LOGD) Log.d(
7962 TAG, " Force finishing activity "
7963 + r.intent.getComponent().flattenToShortString());
7964 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
7965 }
7966 }
7967 if (!app.persistent) {
7968 // We don't want to start this process again until the user
7969 // explicitly does so... but for persistent process, we really
7970 // need to keep it running. If a persistent process is actually
7971 // repeatedly crashing, then badness for everyone.
7972 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
7973 app.info.processName);
7974 mBadProcesses.put(app.info.processName, app.info.uid, now);
7975 app.bad = true;
7976 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
7977 app.removed = true;
7978 removeProcessLocked(app, false);
7979 return false;
7980 }
7981 }
7982
7983 // Bump up the crash count of any services currently running in the proc.
7984 if (app.services.size() != 0) {
7985 // Any services running in the application need to be placed
7986 // back in the pending list.
7987 Iterator it = app.services.iterator();
7988 while (it.hasNext()) {
7989 ServiceRecord sr = (ServiceRecord)it.next();
7990 sr.crashCount++;
7991 }
7992 }
7993
7994 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
7995 return true;
7996 }
7997
7998 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007999 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008000 skipCurrentReceiverLocked(app);
8001 }
8002
8003 void skipCurrentReceiverLocked(ProcessRecord app) {
8004 boolean reschedule = false;
8005 BroadcastRecord r = app.curReceiver;
8006 if (r != null) {
8007 // The current broadcast is waiting for this app's receiver
8008 // to be finished. Looks like that's not going to happen, so
8009 // let the broadcast continue.
8010 logBroadcastReceiverDiscard(r);
8011 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8012 r.resultExtras, r.resultAbort, true);
8013 reschedule = true;
8014 }
8015 r = mPendingBroadcast;
8016 if (r != null && r.curApp == app) {
8017 if (DEBUG_BROADCAST) Log.v(TAG,
8018 "skip & discard pending app " + r);
8019 logBroadcastReceiverDiscard(r);
8020 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8021 r.resultExtras, r.resultAbort, true);
8022 reschedule = true;
8023 }
8024 if (reschedule) {
8025 scheduleBroadcastsLocked();
8026 }
8027 }
8028
8029 public int handleApplicationError(IBinder app, int flags,
8030 String tag, String shortMsg, String longMsg, byte[] crashData) {
8031 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008032 ProcessRecord r = null;
8033 synchronized (this) {
8034 if (app != null) {
8035 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8036 final int NA = apps.size();
8037 for (int ia=0; ia<NA; ia++) {
8038 ProcessRecord p = apps.valueAt(ia);
8039 if (p.thread != null && p.thread.asBinder() == app) {
8040 r = p;
8041 break;
8042 }
8043 }
8044 }
8045 }
8046
8047 if (r != null) {
8048 // The application has crashed. Send the SIGQUIT to the process so
8049 // that it can dump its state.
8050 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8051 //Log.i(TAG, "Current system threads:");
8052 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8053 }
8054
8055 if (mWatcher != null) {
8056 try {
8057 String name = r != null ? r.processName : null;
8058 int pid = r != null ? r.pid : Binder.getCallingPid();
8059 if (!mWatcher.appCrashed(name, pid,
8060 shortMsg, longMsg, crashData)) {
8061 Log.w(TAG, "Force-killing crashed app " + name
8062 + " at watcher's request");
8063 Process.killProcess(pid);
8064 return 0;
8065 }
8066 } catch (RemoteException e) {
8067 mWatcher = null;
8068 }
8069 }
8070
8071 final long origId = Binder.clearCallingIdentity();
8072
8073 // If this process is running instrumentation, finish it.
8074 if (r != null && r.instrumentationClass != null) {
8075 Log.w(TAG, "Error in app " + r.processName
8076 + " running instrumentation " + r.instrumentationClass + ":");
8077 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8078 if (longMsg != null) Log.w(TAG, " " + longMsg);
8079 Bundle info = new Bundle();
8080 info.putString("shortMsg", shortMsg);
8081 info.putString("longMsg", longMsg);
8082 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8083 Binder.restoreCallingIdentity(origId);
8084 return 0;
8085 }
8086
8087 if (r != null) {
8088 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8089 return 0;
8090 }
8091 } else {
8092 Log.w(TAG, "Some application object " + app + " tag " + tag
8093 + " has crashed, but I don't know who it is.");
8094 Log.w(TAG, "ShortMsg:" + shortMsg);
8095 Log.w(TAG, "LongMsg:" + longMsg);
8096 Binder.restoreCallingIdentity(origId);
8097 return 0;
8098 }
8099
8100 Message msg = Message.obtain();
8101 msg.what = SHOW_ERROR_MSG;
8102 HashMap data = new HashMap();
8103 data.put("result", result);
8104 data.put("app", r);
8105 data.put("flags", flags);
8106 data.put("shortMsg", shortMsg);
8107 data.put("longMsg", longMsg);
8108 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8109 // For system processes, submit crash data to the server.
8110 data.put("crashData", crashData);
8111 }
8112 msg.obj = data;
8113 mHandler.sendMessage(msg);
8114
8115 Binder.restoreCallingIdentity(origId);
8116 }
8117
8118 int res = result.get();
8119
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008120 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008121 synchronized (this) {
8122 if (r != null) {
8123 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8124 SystemClock.uptimeMillis());
8125 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008126 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8127 appErrorIntent = createAppErrorIntentLocked(r);
8128 res = AppErrorDialog.FORCE_QUIT;
8129 }
8130 }
8131
8132 if (appErrorIntent != null) {
8133 try {
8134 mContext.startActivity(appErrorIntent);
8135 } catch (ActivityNotFoundException e) {
8136 Log.w(TAG, "bug report receiver dissappeared", e);
8137 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008138 }
8139
8140 return res;
8141 }
8142
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008143 Intent createAppErrorIntentLocked(ProcessRecord r) {
8144 ApplicationErrorReport report = createAppErrorReportLocked(r);
8145 if (report == null) {
8146 return null;
8147 }
8148 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8149 result.setComponent(r.errorReportReceiver);
8150 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8151 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8152 return result;
8153 }
8154
8155 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8156 if (r.errorReportReceiver == null) {
8157 return null;
8158 }
8159
8160 if (!r.crashing && !r.notResponding) {
8161 return null;
8162 }
8163
8164 try {
8165 ApplicationErrorReport report = new ApplicationErrorReport();
8166 report.packageName = r.info.packageName;
8167 report.installerPackageName = r.errorReportReceiver.getPackageName();
8168 report.processName = r.processName;
8169
8170 if (r.crashing) {
8171 report.type = ApplicationErrorReport.TYPE_CRASH;
8172 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8173
8174 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8175 r.crashingReport.crashData);
8176 DataInputStream dataStream = new DataInputStream(byteStream);
8177 CrashData crashData = new CrashData(dataStream);
8178 ThrowableData throwData = crashData.getThrowableData();
8179
8180 report.time = crashData.getTime();
8181 report.crashInfo.stackTrace = throwData.toString();
8182
8183 // extract the source of the exception, useful for report
8184 // clustering
8185 while (throwData.getCause() != null) {
8186 throwData = throwData.getCause();
8187 }
8188 StackTraceElementData trace = throwData.getStackTrace()[0];
8189 report.crashInfo.exceptionClassName = throwData.getType();
8190 report.crashInfo.throwFileName = trace.getFileName();
8191 report.crashInfo.throwClassName = trace.getClassName();
8192 report.crashInfo.throwMethodName = trace.getMethodName();
8193 } else if (r.notResponding) {
8194 report.type = ApplicationErrorReport.TYPE_ANR;
8195 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8196
8197 report.anrInfo.activity = r.notRespondingReport.tag;
8198 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8199 report.anrInfo.info = r.notRespondingReport.longMsg;
8200 }
8201
8202 return report;
8203 } catch (IOException e) {
8204 // we don't send it
8205 }
8206
8207 return null;
8208 }
8209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008210 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8211 // assume our apps are happy - lazy create the list
8212 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8213
8214 synchronized (this) {
8215
8216 // iterate across all processes
8217 final int N = mLRUProcesses.size();
8218 for (int i = 0; i < N; i++) {
8219 ProcessRecord app = mLRUProcesses.get(i);
8220 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8221 // This one's in trouble, so we'll generate a report for it
8222 // crashes are higher priority (in case there's a crash *and* an anr)
8223 ActivityManager.ProcessErrorStateInfo report = null;
8224 if (app.crashing) {
8225 report = app.crashingReport;
8226 } else if (app.notResponding) {
8227 report = app.notRespondingReport;
8228 }
8229
8230 if (report != null) {
8231 if (errList == null) {
8232 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8233 }
8234 errList.add(report);
8235 } else {
8236 Log.w(TAG, "Missing app error report, app = " + app.processName +
8237 " crashing = " + app.crashing +
8238 " notResponding = " + app.notResponding);
8239 }
8240 }
8241 }
8242 }
8243
8244 return errList;
8245 }
8246
8247 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8248 // Lazy instantiation of list
8249 List<ActivityManager.RunningAppProcessInfo> runList = null;
8250 synchronized (this) {
8251 // Iterate across all processes
8252 final int N = mLRUProcesses.size();
8253 for (int i = 0; i < N; i++) {
8254 ProcessRecord app = mLRUProcesses.get(i);
8255 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8256 // Generate process state info for running application
8257 ActivityManager.RunningAppProcessInfo currApp =
8258 new ActivityManager.RunningAppProcessInfo(app.processName,
8259 app.pid, app.getPackageList());
8260 int adj = app.curAdj;
8261 if (adj >= CONTENT_PROVIDER_ADJ) {
8262 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8263 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8264 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008265 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8266 } else if (adj >= HOME_APP_ADJ) {
8267 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8268 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008269 } else if (adj >= SECONDARY_SERVER_ADJ) {
8270 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8271 } else if (adj >= VISIBLE_APP_ADJ) {
8272 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8273 } else {
8274 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8275 }
8276 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8277 // + " lru=" + currApp.lru);
8278 if (runList == null) {
8279 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8280 }
8281 runList.add(currApp);
8282 }
8283 }
8284 }
8285 return runList;
8286 }
8287
8288 @Override
8289 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8290 synchronized (this) {
8291 if (checkCallingPermission(android.Manifest.permission.DUMP)
8292 != PackageManager.PERMISSION_GRANTED) {
8293 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8294 + Binder.getCallingPid()
8295 + ", uid=" + Binder.getCallingUid()
8296 + " without permission "
8297 + android.Manifest.permission.DUMP);
8298 return;
8299 }
8300 if (args.length != 0 && "service".equals(args[0])) {
8301 dumpService(fd, pw, args);
8302 return;
8303 }
8304 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008305 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008306 pw.println(" ");
8307 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008308 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008309 if (mWaitingVisibleActivities.size() > 0) {
8310 pw.println(" ");
8311 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008312 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008313 }
8314 if (mStoppingActivities.size() > 0) {
8315 pw.println(" ");
8316 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008317 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008318 }
8319 if (mFinishingActivities.size() > 0) {
8320 pw.println(" ");
8321 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008322 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008323 }
8324
8325 pw.println(" ");
8326 pw.println(" mPausingActivity: " + mPausingActivity);
8327 pw.println(" mResumedActivity: " + mResumedActivity);
8328 pw.println(" mFocusedActivity: " + mFocusedActivity);
8329 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8330
8331 if (mRecentTasks.size() > 0) {
8332 pw.println(" ");
8333 pw.println("Recent tasks in Current Activity Manager State:");
8334
8335 final int N = mRecentTasks.size();
8336 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008337 TaskRecord tr = mRecentTasks.get(i);
8338 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8339 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008340 mRecentTasks.get(i).dump(pw, " ");
8341 }
8342 }
8343
8344 pw.println(" ");
8345 pw.println(" mCurTask: " + mCurTask);
8346
8347 pw.println(" ");
8348 pw.println("Processes in Current Activity Manager State:");
8349
8350 boolean needSep = false;
8351 int numPers = 0;
8352
8353 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8354 final int NA = procs.size();
8355 for (int ia=0; ia<NA; ia++) {
8356 if (!needSep) {
8357 pw.println(" All known processes:");
8358 needSep = true;
8359 }
8360 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008361 pw.print(r.persistent ? " *PERS*" : " *APP*");
8362 pw.print(" UID "); pw.print(procs.keyAt(ia));
8363 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008364 r.dump(pw, " ");
8365 if (r.persistent) {
8366 numPers++;
8367 }
8368 }
8369 }
8370
8371 if (mLRUProcesses.size() > 0) {
8372 if (needSep) pw.println(" ");
8373 needSep = true;
8374 pw.println(" Running processes (most recent first):");
8375 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008376 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008377 needSep = true;
8378 }
8379
8380 synchronized (mPidsSelfLocked) {
8381 if (mPidsSelfLocked.size() > 0) {
8382 if (needSep) pw.println(" ");
8383 needSep = true;
8384 pw.println(" PID mappings:");
8385 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008386 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8387 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008388 }
8389 }
8390 }
8391
8392 if (mForegroundProcesses.size() > 0) {
8393 if (needSep) pw.println(" ");
8394 needSep = true;
8395 pw.println(" Foreground Processes:");
8396 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008397 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8398 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008399 }
8400 }
8401
8402 if (mPersistentStartingProcesses.size() > 0) {
8403 if (needSep) pw.println(" ");
8404 needSep = true;
8405 pw.println(" Persisent processes that are starting:");
8406 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008407 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008408 }
8409
8410 if (mStartingProcesses.size() > 0) {
8411 if (needSep) pw.println(" ");
8412 needSep = true;
8413 pw.println(" Processes that are starting:");
8414 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008415 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008416 }
8417
8418 if (mRemovedProcesses.size() > 0) {
8419 if (needSep) pw.println(" ");
8420 needSep = true;
8421 pw.println(" Processes that are being removed:");
8422 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008423 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008424 }
8425
8426 if (mProcessesOnHold.size() > 0) {
8427 if (needSep) pw.println(" ");
8428 needSep = true;
8429 pw.println(" Processes that are on old until the system is ready:");
8430 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008431 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008432 }
8433
8434 if (mProcessCrashTimes.getMap().size() > 0) {
8435 if (needSep) pw.println(" ");
8436 needSep = true;
8437 pw.println(" Time since processes crashed:");
8438 long now = SystemClock.uptimeMillis();
8439 for (Map.Entry<String, SparseArray<Long>> procs
8440 : mProcessCrashTimes.getMap().entrySet()) {
8441 SparseArray<Long> uids = procs.getValue();
8442 final int N = uids.size();
8443 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008444 pw.print(" Process "); pw.print(procs.getKey());
8445 pw.print(" uid "); pw.print(uids.keyAt(i));
8446 pw.print(": last crashed ");
8447 pw.print((now-uids.valueAt(i)));
8448 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008449 }
8450 }
8451 }
8452
8453 if (mBadProcesses.getMap().size() > 0) {
8454 if (needSep) pw.println(" ");
8455 needSep = true;
8456 pw.println(" Bad processes:");
8457 for (Map.Entry<String, SparseArray<Long>> procs
8458 : mBadProcesses.getMap().entrySet()) {
8459 SparseArray<Long> uids = procs.getValue();
8460 final int N = uids.size();
8461 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008462 pw.print(" Bad process "); pw.print(procs.getKey());
8463 pw.print(" uid "); pw.print(uids.keyAt(i));
8464 pw.print(": crashed at time ");
8465 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008466 }
8467 }
8468 }
8469
8470 pw.println(" ");
8471 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008472 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008473 pw.println(" mConfiguration: " + mConfiguration);
8474 pw.println(" mStartRunning=" + mStartRunning
8475 + " mSystemReady=" + mSystemReady
8476 + " mBooting=" + mBooting
8477 + " mBooted=" + mBooted
8478 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008479 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008480 pw.println(" mGoingToSleep=" + mGoingToSleep);
8481 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8482 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8483 + " mDebugTransient=" + mDebugTransient
8484 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8485 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8486 + " mWatcher=" + mWatcher);
8487 }
8488 }
8489
8490 /**
8491 * There are three ways to call this:
8492 * - no service specified: dump all the services
8493 * - a flattened component name that matched an existing service was specified as the
8494 * first arg: dump that one service
8495 * - the first arg isn't the flattened component name of an existing service:
8496 * dump all services whose component contains the first arg as a substring
8497 */
8498 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8499 String[] newArgs;
8500 String componentNameString;
8501 ServiceRecord r;
8502 if (args.length == 1) {
8503 componentNameString = null;
8504 newArgs = EMPTY_STRING_ARRAY;
8505 r = null;
8506 } else {
8507 componentNameString = args[1];
8508 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8509 r = componentName != null ? mServices.get(componentName) : null;
8510 newArgs = new String[args.length - 2];
8511 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8512 }
8513
8514 if (r != null) {
8515 dumpService(fd, pw, r, newArgs);
8516 } else {
8517 for (ServiceRecord r1 : mServices.values()) {
8518 if (componentNameString == null
8519 || r1.name.flattenToString().contains(componentNameString)) {
8520 dumpService(fd, pw, r1, newArgs);
8521 }
8522 }
8523 }
8524 }
8525
8526 /**
8527 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8528 * there is a thread associated with the service.
8529 */
8530 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8531 pw.println(" Service " + r.name.flattenToString());
8532 if (r.app != null && r.app.thread != null) {
8533 try {
8534 // flush anything that is already in the PrintWriter since the thread is going
8535 // to write to the file descriptor directly
8536 pw.flush();
8537 r.app.thread.dumpService(fd, r, args);
8538 pw.print("\n");
8539 } catch (RemoteException e) {
8540 pw.println("got a RemoteException while dumping the service");
8541 }
8542 }
8543 }
8544
8545 void dumpBroadcasts(PrintWriter pw) {
8546 synchronized (this) {
8547 if (checkCallingPermission(android.Manifest.permission.DUMP)
8548 != PackageManager.PERMISSION_GRANTED) {
8549 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8550 + Binder.getCallingPid()
8551 + ", uid=" + Binder.getCallingUid()
8552 + " without permission "
8553 + android.Manifest.permission.DUMP);
8554 return;
8555 }
8556 pw.println("Broadcasts in Current Activity Manager State:");
8557
8558 if (mRegisteredReceivers.size() > 0) {
8559 pw.println(" ");
8560 pw.println(" Registered Receivers:");
8561 Iterator it = mRegisteredReceivers.values().iterator();
8562 while (it.hasNext()) {
8563 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008564 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008565 r.dump(pw, " ");
8566 }
8567 }
8568
8569 pw.println(" ");
8570 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008571 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008572
8573 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8574 || mPendingBroadcast != null) {
8575 if (mParallelBroadcasts.size() > 0) {
8576 pw.println(" ");
8577 pw.println(" Active broadcasts:");
8578 }
8579 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8580 pw.println(" Broadcast #" + i + ":");
8581 mParallelBroadcasts.get(i).dump(pw, " ");
8582 }
8583 if (mOrderedBroadcasts.size() > 0) {
8584 pw.println(" ");
8585 pw.println(" Active serialized broadcasts:");
8586 }
8587 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8588 pw.println(" Serialized Broadcast #" + i + ":");
8589 mOrderedBroadcasts.get(i).dump(pw, " ");
8590 }
8591 pw.println(" ");
8592 pw.println(" Pending broadcast:");
8593 if (mPendingBroadcast != null) {
8594 mPendingBroadcast.dump(pw, " ");
8595 } else {
8596 pw.println(" (null)");
8597 }
8598 }
8599
8600 pw.println(" ");
8601 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8602 if (mStickyBroadcasts != null) {
8603 pw.println(" ");
8604 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008605 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008606 for (Map.Entry<String, ArrayList<Intent>> ent
8607 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008608 pw.print(" * Sticky action "); pw.print(ent.getKey());
8609 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008610 ArrayList<Intent> intents = ent.getValue();
8611 final int N = intents.size();
8612 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008613 sb.setLength(0);
8614 sb.append(" Intent: ");
8615 intents.get(i).toShortString(sb, true, false);
8616 pw.println(sb.toString());
8617 Bundle bundle = intents.get(i).getExtras();
8618 if (bundle != null) {
8619 pw.print(" ");
8620 pw.println(bundle.toString());
8621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008622 }
8623 }
8624 }
8625
8626 pw.println(" ");
8627 pw.println(" mHandler:");
8628 mHandler.dump(new PrintWriterPrinter(pw), " ");
8629 }
8630 }
8631
8632 void dumpServices(PrintWriter pw) {
8633 synchronized (this) {
8634 if (checkCallingPermission(android.Manifest.permission.DUMP)
8635 != PackageManager.PERMISSION_GRANTED) {
8636 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8637 + Binder.getCallingPid()
8638 + ", uid=" + Binder.getCallingUid()
8639 + " without permission "
8640 + android.Manifest.permission.DUMP);
8641 return;
8642 }
8643 pw.println("Services in Current Activity Manager State:");
8644
8645 boolean needSep = false;
8646
8647 if (mServices.size() > 0) {
8648 pw.println(" Active services:");
8649 Iterator<ServiceRecord> it = mServices.values().iterator();
8650 while (it.hasNext()) {
8651 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008652 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008653 r.dump(pw, " ");
8654 }
8655 needSep = true;
8656 }
8657
8658 if (mPendingServices.size() > 0) {
8659 if (needSep) pw.println(" ");
8660 pw.println(" Pending services:");
8661 for (int i=0; i<mPendingServices.size(); i++) {
8662 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008663 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008664 r.dump(pw, " ");
8665 }
8666 needSep = true;
8667 }
8668
8669 if (mRestartingServices.size() > 0) {
8670 if (needSep) pw.println(" ");
8671 pw.println(" Restarting services:");
8672 for (int i=0; i<mRestartingServices.size(); i++) {
8673 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008674 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008675 r.dump(pw, " ");
8676 }
8677 needSep = true;
8678 }
8679
8680 if (mStoppingServices.size() > 0) {
8681 if (needSep) pw.println(" ");
8682 pw.println(" Stopping services:");
8683 for (int i=0; i<mStoppingServices.size(); i++) {
8684 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008685 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008686 r.dump(pw, " ");
8687 }
8688 needSep = true;
8689 }
8690
8691 if (mServiceConnections.size() > 0) {
8692 if (needSep) pw.println(" ");
8693 pw.println(" Connection bindings to services:");
8694 Iterator<ConnectionRecord> it
8695 = mServiceConnections.values().iterator();
8696 while (it.hasNext()) {
8697 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008698 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008699 r.dump(pw, " ");
8700 }
8701 }
8702 }
8703 }
8704
8705 void dumpProviders(PrintWriter pw) {
8706 synchronized (this) {
8707 if (checkCallingPermission(android.Manifest.permission.DUMP)
8708 != PackageManager.PERMISSION_GRANTED) {
8709 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8710 + Binder.getCallingPid()
8711 + ", uid=" + Binder.getCallingUid()
8712 + " without permission "
8713 + android.Manifest.permission.DUMP);
8714 return;
8715 }
8716
8717 pw.println("Content Providers in Current Activity Manager State:");
8718
8719 boolean needSep = false;
8720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008721 if (mProvidersByClass.size() > 0) {
8722 if (needSep) pw.println(" ");
8723 pw.println(" Published content providers (by class):");
8724 Iterator it = mProvidersByClass.entrySet().iterator();
8725 while (it.hasNext()) {
8726 Map.Entry e = (Map.Entry)it.next();
8727 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008728 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008729 r.dump(pw, " ");
8730 }
8731 needSep = true;
8732 }
8733
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008734 if (mProvidersByName.size() > 0) {
8735 pw.println(" ");
8736 pw.println(" Authority to provider mappings:");
8737 Iterator it = mProvidersByName.entrySet().iterator();
8738 while (it.hasNext()) {
8739 Map.Entry e = (Map.Entry)it.next();
8740 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8741 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8742 pw.println(r);
8743 }
8744 needSep = true;
8745 }
8746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008747 if (mLaunchingProviders.size() > 0) {
8748 if (needSep) pw.println(" ");
8749 pw.println(" Launching content providers:");
8750 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008751 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8752 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008753 }
8754 needSep = true;
8755 }
8756
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008757 if (mGrantedUriPermissions.size() > 0) {
8758 pw.println();
8759 pw.println("Granted Uri Permissions:");
8760 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8761 int uid = mGrantedUriPermissions.keyAt(i);
8762 HashMap<Uri, UriPermission> perms
8763 = mGrantedUriPermissions.valueAt(i);
8764 pw.print(" * UID "); pw.print(uid);
8765 pw.println(" holds:");
8766 for (UriPermission perm : perms.values()) {
8767 pw.print(" "); pw.println(perm);
8768 perm.dump(pw, " ");
8769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008770 }
8771 }
8772 }
8773 }
8774
8775 void dumpSenders(PrintWriter pw) {
8776 synchronized (this) {
8777 if (checkCallingPermission(android.Manifest.permission.DUMP)
8778 != PackageManager.PERMISSION_GRANTED) {
8779 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8780 + Binder.getCallingPid()
8781 + ", uid=" + Binder.getCallingUid()
8782 + " without permission "
8783 + android.Manifest.permission.DUMP);
8784 return;
8785 }
8786
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008787 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008788
8789 if (this.mIntentSenderRecords.size() > 0) {
8790 Iterator<WeakReference<PendingIntentRecord>> it
8791 = mIntentSenderRecords.values().iterator();
8792 while (it.hasNext()) {
8793 WeakReference<PendingIntentRecord> ref = it.next();
8794 PendingIntentRecord rec = ref != null ? ref.get(): null;
8795 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008796 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008797 rec.dump(pw, " ");
8798 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008799 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008800 }
8801 }
8802 }
8803 }
8804 }
8805
8806 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008807 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808 TaskRecord lastTask = null;
8809 for (int i=list.size()-1; i>=0; i--) {
8810 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008811 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008812 if (lastTask != r.task) {
8813 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008814 pw.print(prefix);
8815 pw.print(full ? "* " : " ");
8816 pw.println(lastTask);
8817 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008818 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008820 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008821 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8822 pw.print(" #"); pw.print(i); pw.print(": ");
8823 pw.println(r);
8824 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008825 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008826 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008827 }
8828 }
8829
8830 private static final int dumpProcessList(PrintWriter pw, List list,
8831 String prefix, String normalLabel, String persistentLabel,
8832 boolean inclOomAdj) {
8833 int numPers = 0;
8834 for (int i=list.size()-1; i>=0; i--) {
8835 ProcessRecord r = (ProcessRecord)list.get(i);
8836 if (false) {
8837 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8838 + " #" + i + ":");
8839 r.dump(pw, prefix + " ");
8840 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008841 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008842 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008843 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008844 } else {
8845 pw.println(String.format("%s%s #%2d: %s",
8846 prefix, (r.persistent ? persistentLabel : normalLabel),
8847 i, r.toString()));
8848 }
8849 if (r.persistent) {
8850 numPers++;
8851 }
8852 }
8853 return numPers;
8854 }
8855
8856 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8857 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008858 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008859 long uptime = SystemClock.uptimeMillis();
8860 long realtime = SystemClock.elapsedRealtime();
8861
8862 if (isCheckinRequest) {
8863 // short checkin version
8864 pw.println(uptime + "," + realtime);
8865 pw.flush();
8866 } else {
8867 pw.println("Applications Memory Usage (kB):");
8868 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8869 }
8870 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8871 ProcessRecord r = (ProcessRecord)list.get(i);
8872 if (r.thread != null) {
8873 if (!isCheckinRequest) {
8874 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8875 pw.flush();
8876 }
8877 try {
8878 r.thread.asBinder().dump(fd, args);
8879 } catch (RemoteException e) {
8880 if (!isCheckinRequest) {
8881 pw.println("Got RemoteException!");
8882 pw.flush();
8883 }
8884 }
8885 }
8886 }
8887 }
8888
8889 /**
8890 * Searches array of arguments for the specified string
8891 * @param args array of argument strings
8892 * @param value value to search for
8893 * @return true if the value is contained in the array
8894 */
8895 private static boolean scanArgs(String[] args, String value) {
8896 if (args != null) {
8897 for (String arg : args) {
8898 if (value.equals(arg)) {
8899 return true;
8900 }
8901 }
8902 }
8903 return false;
8904 }
8905
8906 private final int indexOfTokenLocked(IBinder token, boolean required) {
8907 int count = mHistory.size();
8908
8909 // convert the token to an entry in the history.
8910 HistoryRecord r = null;
8911 int index = -1;
8912 for (int i=count-1; i>=0; i--) {
8913 Object o = mHistory.get(i);
8914 if (o == token) {
8915 r = (HistoryRecord)o;
8916 index = i;
8917 break;
8918 }
8919 }
8920 if (index < 0 && required) {
8921 RuntimeInit.crash(TAG, new InvalidTokenException(token));
8922 }
8923
8924 return index;
8925 }
8926
8927 static class InvalidTokenException extends Exception {
8928 InvalidTokenException(IBinder token) {
8929 super("Bad activity token: " + token);
8930 }
8931 }
8932
8933 private final void killServicesLocked(ProcessRecord app,
8934 boolean allowRestart) {
8935 // Report disconnected services.
8936 if (false) {
8937 // XXX we are letting the client link to the service for
8938 // death notifications.
8939 if (app.services.size() > 0) {
8940 Iterator it = app.services.iterator();
8941 while (it.hasNext()) {
8942 ServiceRecord r = (ServiceRecord)it.next();
8943 if (r.connections.size() > 0) {
8944 Iterator<ConnectionRecord> jt
8945 = r.connections.values().iterator();
8946 while (jt.hasNext()) {
8947 ConnectionRecord c = jt.next();
8948 if (c.binding.client != app) {
8949 try {
8950 //c.conn.connected(r.className, null);
8951 } catch (Exception e) {
8952 // todo: this should be asynchronous!
8953 Log.w(TAG, "Exception thrown disconnected servce "
8954 + r.shortName
8955 + " from app " + app.processName, e);
8956 }
8957 }
8958 }
8959 }
8960 }
8961 }
8962 }
8963
8964 // Clean up any connections this application has to other services.
8965 if (app.connections.size() > 0) {
8966 Iterator<ConnectionRecord> it = app.connections.iterator();
8967 while (it.hasNext()) {
8968 ConnectionRecord r = it.next();
8969 removeConnectionLocked(r, app, null);
8970 }
8971 }
8972 app.connections.clear();
8973
8974 if (app.services.size() != 0) {
8975 // Any services running in the application need to be placed
8976 // back in the pending list.
8977 Iterator it = app.services.iterator();
8978 while (it.hasNext()) {
8979 ServiceRecord sr = (ServiceRecord)it.next();
8980 synchronized (sr.stats.getBatteryStats()) {
8981 sr.stats.stopLaunchedLocked();
8982 }
8983 sr.app = null;
8984 sr.executeNesting = 0;
8985 mStoppingServices.remove(sr);
8986 if (sr.bindings.size() > 0) {
8987 Iterator<IntentBindRecord> bindings
8988 = sr.bindings.values().iterator();
8989 while (bindings.hasNext()) {
8990 IntentBindRecord b = bindings.next();
8991 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
8992 + ": shouldUnbind=" + b.hasBound);
8993 b.binder = null;
8994 b.requested = b.received = b.hasBound = false;
8995 }
8996 }
8997
8998 if (sr.crashCount >= 2) {
8999 Log.w(TAG, "Service crashed " + sr.crashCount
9000 + " times, stopping: " + sr);
9001 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9002 sr.crashCount, sr.shortName, app.pid);
9003 bringDownServiceLocked(sr, true);
9004 } else if (!allowRestart) {
9005 bringDownServiceLocked(sr, true);
9006 } else {
9007 scheduleServiceRestartLocked(sr);
9008 }
9009 }
9010
9011 if (!allowRestart) {
9012 app.services.clear();
9013 }
9014 }
9015
9016 app.executingServices.clear();
9017 }
9018
9019 private final void removeDyingProviderLocked(ProcessRecord proc,
9020 ContentProviderRecord cpr) {
9021 synchronized (cpr) {
9022 cpr.launchingApp = null;
9023 cpr.notifyAll();
9024 }
9025
9026 mProvidersByClass.remove(cpr.info.name);
9027 String names[] = cpr.info.authority.split(";");
9028 for (int j = 0; j < names.length; j++) {
9029 mProvidersByName.remove(names[j]);
9030 }
9031
9032 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9033 while (cit.hasNext()) {
9034 ProcessRecord capp = cit.next();
9035 if (!capp.persistent && capp.thread != null
9036 && capp.pid != 0
9037 && capp.pid != MY_PID) {
9038 Log.i(TAG, "Killing app " + capp.processName
9039 + " (pid " + capp.pid
9040 + ") because provider " + cpr.info.name
9041 + " is in dying process " + proc.processName);
9042 Process.killProcess(capp.pid);
9043 }
9044 }
9045
9046 mLaunchingProviders.remove(cpr);
9047 }
9048
9049 /**
9050 * Main code for cleaning up a process when it has gone away. This is
9051 * called both as a result of the process dying, or directly when stopping
9052 * a process when running in single process mode.
9053 */
9054 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9055 boolean restarting, int index) {
9056 if (index >= 0) {
9057 mLRUProcesses.remove(index);
9058 }
9059
9060 // Dismiss any open dialogs.
9061 if (app.crashDialog != null) {
9062 app.crashDialog.dismiss();
9063 app.crashDialog = null;
9064 }
9065 if (app.anrDialog != null) {
9066 app.anrDialog.dismiss();
9067 app.anrDialog = null;
9068 }
9069 if (app.waitDialog != null) {
9070 app.waitDialog.dismiss();
9071 app.waitDialog = null;
9072 }
9073
9074 app.crashing = false;
9075 app.notResponding = false;
9076
9077 app.resetPackageList();
9078 app.thread = null;
9079 app.forcingToForeground = null;
9080 app.foregroundServices = false;
9081
9082 killServicesLocked(app, true);
9083
9084 boolean restart = false;
9085
9086 int NL = mLaunchingProviders.size();
9087
9088 // Remove published content providers.
9089 if (!app.pubProviders.isEmpty()) {
9090 Iterator it = app.pubProviders.values().iterator();
9091 while (it.hasNext()) {
9092 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9093 cpr.provider = null;
9094 cpr.app = null;
9095
9096 // See if someone is waiting for this provider... in which
9097 // case we don't remove it, but just let it restart.
9098 int i = 0;
9099 if (!app.bad) {
9100 for (; i<NL; i++) {
9101 if (mLaunchingProviders.get(i) == cpr) {
9102 restart = true;
9103 break;
9104 }
9105 }
9106 } else {
9107 i = NL;
9108 }
9109
9110 if (i >= NL) {
9111 removeDyingProviderLocked(app, cpr);
9112 NL = mLaunchingProviders.size();
9113 }
9114 }
9115 app.pubProviders.clear();
9116 }
9117
9118 // Look through the content providers we are waiting to have launched,
9119 // and if any run in this process then either schedule a restart of
9120 // the process or kill the client waiting for it if this process has
9121 // gone bad.
9122 for (int i=0; i<NL; i++) {
9123 ContentProviderRecord cpr = (ContentProviderRecord)
9124 mLaunchingProviders.get(i);
9125 if (cpr.launchingApp == app) {
9126 if (!app.bad) {
9127 restart = true;
9128 } else {
9129 removeDyingProviderLocked(app, cpr);
9130 NL = mLaunchingProviders.size();
9131 }
9132 }
9133 }
9134
9135 // Unregister from connected content providers.
9136 if (!app.conProviders.isEmpty()) {
9137 Iterator it = app.conProviders.iterator();
9138 while (it.hasNext()) {
9139 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9140 cpr.clients.remove(app);
9141 }
9142 app.conProviders.clear();
9143 }
9144
9145 skipCurrentReceiverLocked(app);
9146
9147 // Unregister any receivers.
9148 if (app.receivers.size() > 0) {
9149 Iterator<ReceiverList> it = app.receivers.iterator();
9150 while (it.hasNext()) {
9151 removeReceiverLocked(it.next());
9152 }
9153 app.receivers.clear();
9154 }
9155
Christopher Tate181fafa2009-05-14 11:12:14 -07009156 // If the app is undergoing backup, tell the backup manager about it
9157 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9158 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9159 try {
9160 IBackupManager bm = IBackupManager.Stub.asInterface(
9161 ServiceManager.getService(Context.BACKUP_SERVICE));
9162 bm.agentDisconnected(app.info.packageName);
9163 } catch (RemoteException e) {
9164 // can't happen; backup manager is local
9165 }
9166 }
9167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009168 // If the caller is restarting this app, then leave it in its
9169 // current lists and let the caller take care of it.
9170 if (restarting) {
9171 return;
9172 }
9173
9174 if (!app.persistent) {
9175 if (DEBUG_PROCESSES) Log.v(TAG,
9176 "Removing non-persistent process during cleanup: " + app);
9177 mProcessNames.remove(app.processName, app.info.uid);
9178 } else if (!app.removed) {
9179 // This app is persistent, so we need to keep its record around.
9180 // If it is not already on the pending app list, add it there
9181 // and start a new process for it.
9182 app.thread = null;
9183 app.forcingToForeground = null;
9184 app.foregroundServices = false;
9185 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9186 mPersistentStartingProcesses.add(app);
9187 restart = true;
9188 }
9189 }
9190 mProcessesOnHold.remove(app);
9191
The Android Open Source Project4df24232009-03-05 14:34:35 -08009192 if (app == mHomeProcess) {
9193 mHomeProcess = null;
9194 }
9195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009196 if (restart) {
9197 // We have components that still need to be running in the
9198 // process, so re-launch it.
9199 mProcessNames.put(app.processName, app.info.uid, app);
9200 startProcessLocked(app, "restart", app.processName);
9201 } else if (app.pid > 0 && app.pid != MY_PID) {
9202 // Goodbye!
9203 synchronized (mPidsSelfLocked) {
9204 mPidsSelfLocked.remove(app.pid);
9205 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9206 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009207 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009208 }
9209 }
9210
9211 // =========================================================
9212 // SERVICES
9213 // =========================================================
9214
9215 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9216 ActivityManager.RunningServiceInfo info =
9217 new ActivityManager.RunningServiceInfo();
9218 info.service = r.name;
9219 if (r.app != null) {
9220 info.pid = r.app.pid;
9221 }
9222 info.process = r.processName;
9223 info.foreground = r.isForeground;
9224 info.activeSince = r.createTime;
9225 info.started = r.startRequested;
9226 info.clientCount = r.connections.size();
9227 info.crashCount = r.crashCount;
9228 info.lastActivityTime = r.lastActivity;
9229 return info;
9230 }
9231
9232 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9233 int flags) {
9234 synchronized (this) {
9235 ArrayList<ActivityManager.RunningServiceInfo> res
9236 = new ArrayList<ActivityManager.RunningServiceInfo>();
9237
9238 if (mServices.size() > 0) {
9239 Iterator<ServiceRecord> it = mServices.values().iterator();
9240 while (it.hasNext() && res.size() < maxNum) {
9241 res.add(makeRunningServiceInfoLocked(it.next()));
9242 }
9243 }
9244
9245 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9246 ServiceRecord r = mRestartingServices.get(i);
9247 ActivityManager.RunningServiceInfo info =
9248 makeRunningServiceInfoLocked(r);
9249 info.restarting = r.nextRestartTime;
9250 res.add(info);
9251 }
9252
9253 return res;
9254 }
9255 }
9256
9257 private final ServiceRecord findServiceLocked(ComponentName name,
9258 IBinder token) {
9259 ServiceRecord r = mServices.get(name);
9260 return r == token ? r : null;
9261 }
9262
9263 private final class ServiceLookupResult {
9264 final ServiceRecord record;
9265 final String permission;
9266
9267 ServiceLookupResult(ServiceRecord _record, String _permission) {
9268 record = _record;
9269 permission = _permission;
9270 }
9271 };
9272
9273 private ServiceLookupResult findServiceLocked(Intent service,
9274 String resolvedType) {
9275 ServiceRecord r = null;
9276 if (service.getComponent() != null) {
9277 r = mServices.get(service.getComponent());
9278 }
9279 if (r == null) {
9280 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9281 r = mServicesByIntent.get(filter);
9282 }
9283
9284 if (r == null) {
9285 try {
9286 ResolveInfo rInfo =
9287 ActivityThread.getPackageManager().resolveService(
9288 service, resolvedType, 0);
9289 ServiceInfo sInfo =
9290 rInfo != null ? rInfo.serviceInfo : null;
9291 if (sInfo == null) {
9292 return null;
9293 }
9294
9295 ComponentName name = new ComponentName(
9296 sInfo.applicationInfo.packageName, sInfo.name);
9297 r = mServices.get(name);
9298 } catch (RemoteException ex) {
9299 // pm is in same process, this will never happen.
9300 }
9301 }
9302 if (r != null) {
9303 int callingPid = Binder.getCallingPid();
9304 int callingUid = Binder.getCallingUid();
9305 if (checkComponentPermission(r.permission,
9306 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9307 != PackageManager.PERMISSION_GRANTED) {
9308 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9309 + " from pid=" + callingPid
9310 + ", uid=" + callingUid
9311 + " requires " + r.permission);
9312 return new ServiceLookupResult(null, r.permission);
9313 }
9314 return new ServiceLookupResult(r, null);
9315 }
9316 return null;
9317 }
9318
9319 private class ServiceRestarter implements Runnable {
9320 private ServiceRecord mService;
9321
9322 void setService(ServiceRecord service) {
9323 mService = service;
9324 }
9325
9326 public void run() {
9327 synchronized(ActivityManagerService.this) {
9328 performServiceRestartLocked(mService);
9329 }
9330 }
9331 }
9332
9333 private ServiceLookupResult retrieveServiceLocked(Intent service,
9334 String resolvedType, int callingPid, int callingUid) {
9335 ServiceRecord r = null;
9336 if (service.getComponent() != null) {
9337 r = mServices.get(service.getComponent());
9338 }
9339 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9340 r = mServicesByIntent.get(filter);
9341 if (r == null) {
9342 try {
9343 ResolveInfo rInfo =
9344 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009345 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009346 ServiceInfo sInfo =
9347 rInfo != null ? rInfo.serviceInfo : null;
9348 if (sInfo == null) {
9349 Log.w(TAG, "Unable to start service " + service +
9350 ": not found");
9351 return null;
9352 }
9353
9354 ComponentName name = new ComponentName(
9355 sInfo.applicationInfo.packageName, sInfo.name);
9356 r = mServices.get(name);
9357 if (r == null) {
9358 filter = new Intent.FilterComparison(service.cloneFilter());
9359 ServiceRestarter res = new ServiceRestarter();
9360 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9361 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9362 synchronized (stats) {
9363 ss = stats.getServiceStatsLocked(
9364 sInfo.applicationInfo.uid, sInfo.packageName,
9365 sInfo.name);
9366 }
9367 r = new ServiceRecord(ss, name, filter, sInfo, res);
9368 res.setService(r);
9369 mServices.put(name, r);
9370 mServicesByIntent.put(filter, r);
9371
9372 // Make sure this component isn't in the pending list.
9373 int N = mPendingServices.size();
9374 for (int i=0; i<N; i++) {
9375 ServiceRecord pr = mPendingServices.get(i);
9376 if (pr.name.equals(name)) {
9377 mPendingServices.remove(i);
9378 i--;
9379 N--;
9380 }
9381 }
9382 }
9383 } catch (RemoteException ex) {
9384 // pm is in same process, this will never happen.
9385 }
9386 }
9387 if (r != null) {
9388 if (checkComponentPermission(r.permission,
9389 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9390 != PackageManager.PERMISSION_GRANTED) {
9391 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9392 + " from pid=" + Binder.getCallingPid()
9393 + ", uid=" + Binder.getCallingUid()
9394 + " requires " + r.permission);
9395 return new ServiceLookupResult(null, r.permission);
9396 }
9397 return new ServiceLookupResult(r, null);
9398 }
9399 return null;
9400 }
9401
9402 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9403 long now = SystemClock.uptimeMillis();
9404 if (r.executeNesting == 0 && r.app != null) {
9405 if (r.app.executingServices.size() == 0) {
9406 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9407 msg.obj = r.app;
9408 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9409 }
9410 r.app.executingServices.add(r);
9411 }
9412 r.executeNesting++;
9413 r.executingStart = now;
9414 }
9415
9416 private final void sendServiceArgsLocked(ServiceRecord r,
9417 boolean oomAdjusted) {
9418 final int N = r.startArgs.size();
9419 if (N == 0) {
9420 return;
9421 }
9422
9423 final int BASEID = r.lastStartId - N + 1;
9424 int i = 0;
9425 while (i < N) {
9426 try {
9427 Intent args = r.startArgs.get(i);
9428 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9429 + r.name + " " + r.intent + " args=" + args);
9430 bumpServiceExecutingLocked(r);
9431 if (!oomAdjusted) {
9432 oomAdjusted = true;
9433 updateOomAdjLocked(r.app);
9434 }
9435 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9436 i++;
9437 } catch (Exception e) {
9438 break;
9439 }
9440 }
9441 if (i == N) {
9442 r.startArgs.clear();
9443 } else {
9444 while (i > 0) {
9445 r.startArgs.remove(0);
9446 i--;
9447 }
9448 }
9449 }
9450
9451 private final boolean requestServiceBindingLocked(ServiceRecord r,
9452 IntentBindRecord i, boolean rebind) {
9453 if (r.app == null || r.app.thread == null) {
9454 // If service is not currently running, can't yet bind.
9455 return false;
9456 }
9457 if ((!i.requested || rebind) && i.apps.size() > 0) {
9458 try {
9459 bumpServiceExecutingLocked(r);
9460 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9461 + ": shouldUnbind=" + i.hasBound);
9462 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9463 if (!rebind) {
9464 i.requested = true;
9465 }
9466 i.hasBound = true;
9467 i.doRebind = false;
9468 } catch (RemoteException e) {
9469 return false;
9470 }
9471 }
9472 return true;
9473 }
9474
9475 private final void requestServiceBindingsLocked(ServiceRecord r) {
9476 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9477 while (bindings.hasNext()) {
9478 IntentBindRecord i = bindings.next();
9479 if (!requestServiceBindingLocked(r, i, false)) {
9480 break;
9481 }
9482 }
9483 }
9484
9485 private final void realStartServiceLocked(ServiceRecord r,
9486 ProcessRecord app) throws RemoteException {
9487 if (app.thread == null) {
9488 throw new RemoteException();
9489 }
9490
9491 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009492 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009493
9494 app.services.add(r);
9495 bumpServiceExecutingLocked(r);
9496 updateLRUListLocked(app, true);
9497
9498 boolean created = false;
9499 try {
9500 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9501 + r.name + " " + r.intent);
9502 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9503 System.identityHashCode(r), r.shortName,
9504 r.intent.getIntent().toString(), r.app.pid);
9505 synchronized (r.stats.getBatteryStats()) {
9506 r.stats.startLaunchedLocked();
9507 }
9508 app.thread.scheduleCreateService(r, r.serviceInfo);
9509 created = true;
9510 } finally {
9511 if (!created) {
9512 app.services.remove(r);
9513 scheduleServiceRestartLocked(r);
9514 }
9515 }
9516
9517 requestServiceBindingsLocked(r);
9518 sendServiceArgsLocked(r, true);
9519 }
9520
9521 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9522 r.totalRestartCount++;
9523 if (r.restartDelay == 0) {
9524 r.restartCount++;
9525 r.restartDelay = SERVICE_RESTART_DURATION;
9526 } else {
9527 // If it has been a "reasonably long time" since the service
9528 // was started, then reset our restart duration back to
9529 // the beginning, so we don't infinitely increase the duration
9530 // on a service that just occasionally gets killed (which is
9531 // a normal case, due to process being killed to reclaim memory).
9532 long now = SystemClock.uptimeMillis();
9533 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9534 r.restartCount = 1;
9535 r.restartDelay = SERVICE_RESTART_DURATION;
9536 } else {
9537 r.restartDelay *= 2;
9538 }
9539 }
9540 if (!mRestartingServices.contains(r)) {
9541 mRestartingServices.add(r);
9542 }
9543 mHandler.removeCallbacks(r.restarter);
9544 mHandler.postDelayed(r.restarter, r.restartDelay);
9545 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9546 Log.w(TAG, "Scheduling restart of crashed service "
9547 + r.shortName + " in " + r.restartDelay + "ms");
9548 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9549 r.shortName, r.restartDelay);
9550
9551 Message msg = Message.obtain();
9552 msg.what = SERVICE_ERROR_MSG;
9553 msg.obj = r;
9554 mHandler.sendMessage(msg);
9555 }
9556
9557 final void performServiceRestartLocked(ServiceRecord r) {
9558 if (!mRestartingServices.contains(r)) {
9559 return;
9560 }
9561 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9562 }
9563
9564 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9565 if (r.restartDelay == 0) {
9566 return false;
9567 }
9568 r.resetRestartCounter();
9569 mRestartingServices.remove(r);
9570 mHandler.removeCallbacks(r.restarter);
9571 return true;
9572 }
9573
9574 private final boolean bringUpServiceLocked(ServiceRecord r,
9575 int intentFlags, boolean whileRestarting) {
9576 //Log.i(TAG, "Bring up service:");
9577 //r.dump(" ");
9578
9579 if (r.app != null) {
9580 sendServiceArgsLocked(r, false);
9581 return true;
9582 }
9583
9584 if (!whileRestarting && r.restartDelay > 0) {
9585 // If waiting for a restart, then do nothing.
9586 return true;
9587 }
9588
9589 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9590 + " " + r.intent);
9591
9592 final String appName = r.processName;
9593 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9594 if (app != null && app.thread != null) {
9595 try {
9596 realStartServiceLocked(r, app);
9597 return true;
9598 } catch (RemoteException e) {
9599 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9600 }
9601
9602 // If a dead object exception was thrown -- fall through to
9603 // restart the application.
9604 }
9605
9606 if (!mPendingServices.contains(r)) {
9607 // Not running -- get it started, and enqueue this service record
9608 // to be executed when the app comes up.
9609 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9610 "service", r.name) == null) {
9611 Log.w(TAG, "Unable to launch app "
9612 + r.appInfo.packageName + "/"
9613 + r.appInfo.uid + " for service "
9614 + r.intent.getIntent() + ": process is bad");
9615 bringDownServiceLocked(r, true);
9616 return false;
9617 }
9618 mPendingServices.add(r);
9619 }
9620 return true;
9621 }
9622
9623 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9624 //Log.i(TAG, "Bring down service:");
9625 //r.dump(" ");
9626
9627 // Does it still need to run?
9628 if (!force && r.startRequested) {
9629 return;
9630 }
9631 if (r.connections.size() > 0) {
9632 if (!force) {
9633 // XXX should probably keep a count of the number of auto-create
9634 // connections directly in the service.
9635 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9636 while (it.hasNext()) {
9637 ConnectionRecord cr = it.next();
9638 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9639 return;
9640 }
9641 }
9642 }
9643
9644 // Report to all of the connections that the service is no longer
9645 // available.
9646 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9647 while (it.hasNext()) {
9648 ConnectionRecord c = it.next();
9649 try {
9650 // todo: shouldn't be a synchronous call!
9651 c.conn.connected(r.name, null);
9652 } catch (Exception e) {
9653 Log.w(TAG, "Failure disconnecting service " + r.name +
9654 " to connection " + c.conn.asBinder() +
9655 " (in " + c.binding.client.processName + ")", e);
9656 }
9657 }
9658 }
9659
9660 // Tell the service that it has been unbound.
9661 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9662 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9663 while (it.hasNext()) {
9664 IntentBindRecord ibr = it.next();
9665 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9666 + ": hasBound=" + ibr.hasBound);
9667 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9668 try {
9669 bumpServiceExecutingLocked(r);
9670 updateOomAdjLocked(r.app);
9671 ibr.hasBound = false;
9672 r.app.thread.scheduleUnbindService(r,
9673 ibr.intent.getIntent());
9674 } catch (Exception e) {
9675 Log.w(TAG, "Exception when unbinding service "
9676 + r.shortName, e);
9677 serviceDoneExecutingLocked(r, true);
9678 }
9679 }
9680 }
9681 }
9682
9683 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9684 + " " + r.intent);
9685 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9686 System.identityHashCode(r), r.shortName,
9687 (r.app != null) ? r.app.pid : -1);
9688
9689 mServices.remove(r.name);
9690 mServicesByIntent.remove(r.intent);
9691 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9692 r.totalRestartCount = 0;
9693 unscheduleServiceRestartLocked(r);
9694
9695 // Also make sure it is not on the pending list.
9696 int N = mPendingServices.size();
9697 for (int i=0; i<N; i++) {
9698 if (mPendingServices.get(i) == r) {
9699 mPendingServices.remove(i);
9700 if (DEBUG_SERVICE) Log.v(
9701 TAG, "Removed pending service: " + r.shortName);
9702 i--;
9703 N--;
9704 }
9705 }
9706
9707 if (r.app != null) {
9708 synchronized (r.stats.getBatteryStats()) {
9709 r.stats.stopLaunchedLocked();
9710 }
9711 r.app.services.remove(r);
9712 if (r.app.thread != null) {
9713 updateServiceForegroundLocked(r.app, false);
9714 try {
9715 Log.i(TAG, "Stopping service: " + r.shortName);
9716 bumpServiceExecutingLocked(r);
9717 mStoppingServices.add(r);
9718 updateOomAdjLocked(r.app);
9719 r.app.thread.scheduleStopService(r);
9720 } catch (Exception e) {
9721 Log.w(TAG, "Exception when stopping service "
9722 + r.shortName, e);
9723 serviceDoneExecutingLocked(r, true);
9724 }
9725 } else {
9726 if (DEBUG_SERVICE) Log.v(
9727 TAG, "Removed service that has no process: " + r.shortName);
9728 }
9729 } else {
9730 if (DEBUG_SERVICE) Log.v(
9731 TAG, "Removed service that is not running: " + r.shortName);
9732 }
9733 }
9734
9735 ComponentName startServiceLocked(IApplicationThread caller,
9736 Intent service, String resolvedType,
9737 int callingPid, int callingUid) {
9738 synchronized(this) {
9739 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9740 + " type=" + resolvedType + " args=" + service.getExtras());
9741
9742 if (caller != null) {
9743 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9744 if (callerApp == null) {
9745 throw new SecurityException(
9746 "Unable to find app for caller " + caller
9747 + " (pid=" + Binder.getCallingPid()
9748 + ") when starting service " + service);
9749 }
9750 }
9751
9752 ServiceLookupResult res =
9753 retrieveServiceLocked(service, resolvedType,
9754 callingPid, callingUid);
9755 if (res == null) {
9756 return null;
9757 }
9758 if (res.record == null) {
9759 return new ComponentName("!", res.permission != null
9760 ? res.permission : "private to package");
9761 }
9762 ServiceRecord r = res.record;
9763 if (unscheduleServiceRestartLocked(r)) {
9764 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9765 + r.shortName);
9766 }
9767 r.startRequested = true;
9768 r.startArgs.add(service);
9769 r.lastStartId++;
9770 if (r.lastStartId < 1) {
9771 r.lastStartId = 1;
9772 }
9773 r.lastActivity = SystemClock.uptimeMillis();
9774 synchronized (r.stats.getBatteryStats()) {
9775 r.stats.startRunningLocked();
9776 }
9777 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9778 return new ComponentName("!", "Service process is bad");
9779 }
9780 return r.name;
9781 }
9782 }
9783
9784 public ComponentName startService(IApplicationThread caller, Intent service,
9785 String resolvedType) {
9786 // Refuse possible leaked file descriptors
9787 if (service != null && service.hasFileDescriptors() == true) {
9788 throw new IllegalArgumentException("File descriptors passed in Intent");
9789 }
9790
9791 synchronized(this) {
9792 final int callingPid = Binder.getCallingPid();
9793 final int callingUid = Binder.getCallingUid();
9794 final long origId = Binder.clearCallingIdentity();
9795 ComponentName res = startServiceLocked(caller, service,
9796 resolvedType, callingPid, callingUid);
9797 Binder.restoreCallingIdentity(origId);
9798 return res;
9799 }
9800 }
9801
9802 ComponentName startServiceInPackage(int uid,
9803 Intent service, String resolvedType) {
9804 synchronized(this) {
9805 final long origId = Binder.clearCallingIdentity();
9806 ComponentName res = startServiceLocked(null, service,
9807 resolvedType, -1, uid);
9808 Binder.restoreCallingIdentity(origId);
9809 return res;
9810 }
9811 }
9812
9813 public int stopService(IApplicationThread caller, Intent service,
9814 String resolvedType) {
9815 // Refuse possible leaked file descriptors
9816 if (service != null && service.hasFileDescriptors() == true) {
9817 throw new IllegalArgumentException("File descriptors passed in Intent");
9818 }
9819
9820 synchronized(this) {
9821 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9822 + " type=" + resolvedType);
9823
9824 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9825 if (caller != null && callerApp == null) {
9826 throw new SecurityException(
9827 "Unable to find app for caller " + caller
9828 + " (pid=" + Binder.getCallingPid()
9829 + ") when stopping service " + service);
9830 }
9831
9832 // If this service is active, make sure it is stopped.
9833 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9834 if (r != null) {
9835 if (r.record != null) {
9836 synchronized (r.record.stats.getBatteryStats()) {
9837 r.record.stats.stopRunningLocked();
9838 }
9839 r.record.startRequested = false;
9840 final long origId = Binder.clearCallingIdentity();
9841 bringDownServiceLocked(r.record, false);
9842 Binder.restoreCallingIdentity(origId);
9843 return 1;
9844 }
9845 return -1;
9846 }
9847 }
9848
9849 return 0;
9850 }
9851
9852 public IBinder peekService(Intent service, String resolvedType) {
9853 // Refuse possible leaked file descriptors
9854 if (service != null && service.hasFileDescriptors() == true) {
9855 throw new IllegalArgumentException("File descriptors passed in Intent");
9856 }
9857
9858 IBinder ret = null;
9859
9860 synchronized(this) {
9861 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9862
9863 if (r != null) {
9864 // r.record is null if findServiceLocked() failed the caller permission check
9865 if (r.record == null) {
9866 throw new SecurityException(
9867 "Permission Denial: Accessing service " + r.record.name
9868 + " from pid=" + Binder.getCallingPid()
9869 + ", uid=" + Binder.getCallingUid()
9870 + " requires " + r.permission);
9871 }
9872 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9873 if (ib != null) {
9874 ret = ib.binder;
9875 }
9876 }
9877 }
9878
9879 return ret;
9880 }
9881
9882 public boolean stopServiceToken(ComponentName className, IBinder token,
9883 int startId) {
9884 synchronized(this) {
9885 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9886 + " " + token + " startId=" + startId);
9887 ServiceRecord r = findServiceLocked(className, token);
9888 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9889 synchronized (r.stats.getBatteryStats()) {
9890 r.stats.stopRunningLocked();
9891 r.startRequested = false;
9892 }
9893 final long origId = Binder.clearCallingIdentity();
9894 bringDownServiceLocked(r, false);
9895 Binder.restoreCallingIdentity(origId);
9896 return true;
9897 }
9898 }
9899 return false;
9900 }
9901
9902 public void setServiceForeground(ComponentName className, IBinder token,
9903 boolean isForeground) {
9904 synchronized(this) {
9905 ServiceRecord r = findServiceLocked(className, token);
9906 if (r != null) {
9907 if (r.isForeground != isForeground) {
9908 final long origId = Binder.clearCallingIdentity();
9909 r.isForeground = isForeground;
9910 if (r.app != null) {
9911 updateServiceForegroundLocked(r.app, true);
9912 }
9913 Binder.restoreCallingIdentity(origId);
9914 }
9915 }
9916 }
9917 }
9918
9919 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
9920 boolean anyForeground = false;
9921 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
9922 if (sr.isForeground) {
9923 anyForeground = true;
9924 break;
9925 }
9926 }
9927 if (anyForeground != proc.foregroundServices) {
9928 proc.foregroundServices = anyForeground;
9929 if (oomAdj) {
9930 updateOomAdjLocked();
9931 }
9932 }
9933 }
9934
9935 public int bindService(IApplicationThread caller, IBinder token,
9936 Intent service, String resolvedType,
9937 IServiceConnection connection, int flags) {
9938 // Refuse possible leaked file descriptors
9939 if (service != null && service.hasFileDescriptors() == true) {
9940 throw new IllegalArgumentException("File descriptors passed in Intent");
9941 }
9942
9943 synchronized(this) {
9944 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
9945 + " type=" + resolvedType + " conn=" + connection.asBinder()
9946 + " flags=0x" + Integer.toHexString(flags));
9947 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9948 if (callerApp == null) {
9949 throw new SecurityException(
9950 "Unable to find app for caller " + caller
9951 + " (pid=" + Binder.getCallingPid()
9952 + ") when binding service " + service);
9953 }
9954
9955 HistoryRecord activity = null;
9956 if (token != null) {
9957 int aindex = indexOfTokenLocked(token, false);
9958 if (aindex < 0) {
9959 Log.w(TAG, "Binding with unknown activity: " + token);
9960 return 0;
9961 }
9962 activity = (HistoryRecord)mHistory.get(aindex);
9963 }
9964
9965 ServiceLookupResult res =
9966 retrieveServiceLocked(service, resolvedType,
9967 Binder.getCallingPid(), Binder.getCallingUid());
9968 if (res == null) {
9969 return 0;
9970 }
9971 if (res.record == null) {
9972 return -1;
9973 }
9974 ServiceRecord s = res.record;
9975
9976 final long origId = Binder.clearCallingIdentity();
9977
9978 if (unscheduleServiceRestartLocked(s)) {
9979 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
9980 + s.shortName);
9981 }
9982
9983 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
9984 ConnectionRecord c = new ConnectionRecord(b, activity,
9985 connection, flags);
9986
9987 IBinder binder = connection.asBinder();
9988 s.connections.put(binder, c);
9989 b.connections.add(c);
9990 if (activity != null) {
9991 if (activity.connections == null) {
9992 activity.connections = new HashSet<ConnectionRecord>();
9993 }
9994 activity.connections.add(c);
9995 }
9996 b.client.connections.add(c);
9997 mServiceConnections.put(binder, c);
9998
9999 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10000 s.lastActivity = SystemClock.uptimeMillis();
10001 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10002 return 0;
10003 }
10004 }
10005
10006 if (s.app != null) {
10007 // This could have made the service more important.
10008 updateOomAdjLocked(s.app);
10009 }
10010
10011 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10012 + ": received=" + b.intent.received
10013 + " apps=" + b.intent.apps.size()
10014 + " doRebind=" + b.intent.doRebind);
10015
10016 if (s.app != null && b.intent.received) {
10017 // Service is already running, so we can immediately
10018 // publish the connection.
10019 try {
10020 c.conn.connected(s.name, b.intent.binder);
10021 } catch (Exception e) {
10022 Log.w(TAG, "Failure sending service " + s.shortName
10023 + " to connection " + c.conn.asBinder()
10024 + " (in " + c.binding.client.processName + ")", e);
10025 }
10026
10027 // If this is the first app connected back to this binding,
10028 // and the service had previously asked to be told when
10029 // rebound, then do so.
10030 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10031 requestServiceBindingLocked(s, b.intent, true);
10032 }
10033 } else if (!b.intent.requested) {
10034 requestServiceBindingLocked(s, b.intent, false);
10035 }
10036
10037 Binder.restoreCallingIdentity(origId);
10038 }
10039
10040 return 1;
10041 }
10042
10043 private void removeConnectionLocked(
10044 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10045 IBinder binder = c.conn.asBinder();
10046 AppBindRecord b = c.binding;
10047 ServiceRecord s = b.service;
10048 s.connections.remove(binder);
10049 b.connections.remove(c);
10050 if (c.activity != null && c.activity != skipAct) {
10051 if (c.activity.connections != null) {
10052 c.activity.connections.remove(c);
10053 }
10054 }
10055 if (b.client != skipApp) {
10056 b.client.connections.remove(c);
10057 }
10058 mServiceConnections.remove(binder);
10059
10060 if (b.connections.size() == 0) {
10061 b.intent.apps.remove(b.client);
10062 }
10063
10064 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10065 + ": shouldUnbind=" + b.intent.hasBound);
10066 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10067 && b.intent.hasBound) {
10068 try {
10069 bumpServiceExecutingLocked(s);
10070 updateOomAdjLocked(s.app);
10071 b.intent.hasBound = false;
10072 // Assume the client doesn't want to know about a rebind;
10073 // we will deal with that later if it asks for one.
10074 b.intent.doRebind = false;
10075 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10076 } catch (Exception e) {
10077 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10078 serviceDoneExecutingLocked(s, true);
10079 }
10080 }
10081
10082 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10083 bringDownServiceLocked(s, false);
10084 }
10085 }
10086
10087 public boolean unbindService(IServiceConnection connection) {
10088 synchronized (this) {
10089 IBinder binder = connection.asBinder();
10090 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10091 ConnectionRecord r = mServiceConnections.get(binder);
10092 if (r == null) {
10093 Log.w(TAG, "Unbind failed: could not find connection for "
10094 + connection.asBinder());
10095 return false;
10096 }
10097
10098 final long origId = Binder.clearCallingIdentity();
10099
10100 removeConnectionLocked(r, null, null);
10101
10102 if (r.binding.service.app != null) {
10103 // This could have made the service less important.
10104 updateOomAdjLocked(r.binding.service.app);
10105 }
10106
10107 Binder.restoreCallingIdentity(origId);
10108 }
10109
10110 return true;
10111 }
10112
10113 public void publishService(IBinder token, Intent intent, IBinder service) {
10114 // Refuse possible leaked file descriptors
10115 if (intent != null && intent.hasFileDescriptors() == true) {
10116 throw new IllegalArgumentException("File descriptors passed in Intent");
10117 }
10118
10119 synchronized(this) {
10120 if (!(token instanceof ServiceRecord)) {
10121 throw new IllegalArgumentException("Invalid service token");
10122 }
10123 ServiceRecord r = (ServiceRecord)token;
10124
10125 final long origId = Binder.clearCallingIdentity();
10126
10127 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10128 + " " + intent + ": " + service);
10129 if (r != null) {
10130 Intent.FilterComparison filter
10131 = new Intent.FilterComparison(intent);
10132 IntentBindRecord b = r.bindings.get(filter);
10133 if (b != null && !b.received) {
10134 b.binder = service;
10135 b.requested = true;
10136 b.received = true;
10137 if (r.connections.size() > 0) {
10138 Iterator<ConnectionRecord> it
10139 = r.connections.values().iterator();
10140 while (it.hasNext()) {
10141 ConnectionRecord c = it.next();
10142 if (!filter.equals(c.binding.intent.intent)) {
10143 if (DEBUG_SERVICE) Log.v(
10144 TAG, "Not publishing to: " + c);
10145 if (DEBUG_SERVICE) Log.v(
10146 TAG, "Bound intent: " + c.binding.intent.intent);
10147 if (DEBUG_SERVICE) Log.v(
10148 TAG, "Published intent: " + intent);
10149 continue;
10150 }
10151 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10152 try {
10153 c.conn.connected(r.name, service);
10154 } catch (Exception e) {
10155 Log.w(TAG, "Failure sending service " + r.name +
10156 " to connection " + c.conn.asBinder() +
10157 " (in " + c.binding.client.processName + ")", e);
10158 }
10159 }
10160 }
10161 }
10162
10163 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10164
10165 Binder.restoreCallingIdentity(origId);
10166 }
10167 }
10168 }
10169
10170 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10171 // Refuse possible leaked file descriptors
10172 if (intent != null && intent.hasFileDescriptors() == true) {
10173 throw new IllegalArgumentException("File descriptors passed in Intent");
10174 }
10175
10176 synchronized(this) {
10177 if (!(token instanceof ServiceRecord)) {
10178 throw new IllegalArgumentException("Invalid service token");
10179 }
10180 ServiceRecord r = (ServiceRecord)token;
10181
10182 final long origId = Binder.clearCallingIdentity();
10183
10184 if (r != null) {
10185 Intent.FilterComparison filter
10186 = new Intent.FilterComparison(intent);
10187 IntentBindRecord b = r.bindings.get(filter);
10188 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10189 + " at " + b + ": apps="
10190 + (b != null ? b.apps.size() : 0));
10191 if (b != null) {
10192 if (b.apps.size() > 0) {
10193 // Applications have already bound since the last
10194 // unbind, so just rebind right here.
10195 requestServiceBindingLocked(r, b, true);
10196 } else {
10197 // Note to tell the service the next time there is
10198 // a new client.
10199 b.doRebind = true;
10200 }
10201 }
10202
10203 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10204
10205 Binder.restoreCallingIdentity(origId);
10206 }
10207 }
10208 }
10209
10210 public void serviceDoneExecuting(IBinder token) {
10211 synchronized(this) {
10212 if (!(token instanceof ServiceRecord)) {
10213 throw new IllegalArgumentException("Invalid service token");
10214 }
10215 ServiceRecord r = (ServiceRecord)token;
10216 boolean inStopping = mStoppingServices.contains(token);
10217 if (r != null) {
10218 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10219 + ": nesting=" + r.executeNesting
10220 + ", inStopping=" + inStopping);
10221 if (r != token) {
10222 Log.w(TAG, "Done executing service " + r.name
10223 + " with incorrect token: given " + token
10224 + ", expected " + r);
10225 return;
10226 }
10227
10228 final long origId = Binder.clearCallingIdentity();
10229 serviceDoneExecutingLocked(r, inStopping);
10230 Binder.restoreCallingIdentity(origId);
10231 } else {
10232 Log.w(TAG, "Done executing unknown service " + r.name
10233 + " with token " + token);
10234 }
10235 }
10236 }
10237
10238 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10239 r.executeNesting--;
10240 if (r.executeNesting <= 0 && r.app != null) {
10241 r.app.executingServices.remove(r);
10242 if (r.app.executingServices.size() == 0) {
10243 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10244 }
10245 if (inStopping) {
10246 mStoppingServices.remove(r);
10247 }
10248 updateOomAdjLocked(r.app);
10249 }
10250 }
10251
10252 void serviceTimeout(ProcessRecord proc) {
10253 synchronized(this) {
10254 if (proc.executingServices.size() == 0 || proc.thread == null) {
10255 return;
10256 }
10257 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10258 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10259 ServiceRecord timeout = null;
10260 long nextTime = 0;
10261 while (it.hasNext()) {
10262 ServiceRecord sr = it.next();
10263 if (sr.executingStart < maxTime) {
10264 timeout = sr;
10265 break;
10266 }
10267 if (sr.executingStart > nextTime) {
10268 nextTime = sr.executingStart;
10269 }
10270 }
10271 if (timeout != null && mLRUProcesses.contains(proc)) {
10272 Log.w(TAG, "Timeout executing service: " + timeout);
10273 appNotRespondingLocked(proc, null, "Executing service "
10274 + timeout.name);
10275 } else {
10276 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10277 msg.obj = proc;
10278 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10279 }
10280 }
10281 }
10282
10283 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010284 // BACKUP AND RESTORE
10285 // =========================================================
10286
10287 // Cause the target app to be launched if necessary and its backup agent
10288 // instantiated. The backup agent will invoke backupAgentCreated() on the
10289 // activity manager to announce its creation.
10290 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10291 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10292 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10293
10294 synchronized(this) {
10295 // !!! TODO: currently no check here that we're already bound
10296 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10297 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10298 synchronized (stats) {
10299 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10300 }
10301
10302 BackupRecord r = new BackupRecord(ss, app, backupMode);
10303 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10304 // startProcessLocked() returns existing proc's record if it's already running
10305 ProcessRecord proc = startProcessLocked(app.processName, app,
10306 false, 0, "backup", hostingName);
10307 if (proc == null) {
10308 Log.e(TAG, "Unable to start backup agent process " + r);
10309 return false;
10310 }
10311
10312 r.app = proc;
10313 mBackupTarget = r;
10314 mBackupAppName = app.packageName;
10315
10316 // If the process is already attached, schedule the creation of the backup agent now.
10317 // If it is not yet live, this will be done when it attaches to the framework.
10318 if (proc.thread != null) {
10319 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10320 try {
10321 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10322 } catch (RemoteException e) {
10323 // !!! TODO: notify the backup manager that we crashed, or rely on
10324 // death notices, or...?
10325 }
10326 } else {
10327 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10328 }
10329 // Invariants: at this point, the target app process exists and the application
10330 // is either already running or in the process of coming up. mBackupTarget and
10331 // mBackupAppName describe the app, so that when it binds back to the AM we
10332 // know that it's scheduled for a backup-agent operation.
10333 }
10334
10335 return true;
10336 }
10337
10338 // A backup agent has just come up
10339 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10340 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10341 + " = " + agent);
10342
10343 synchronized(this) {
10344 if (!agentPackageName.equals(mBackupAppName)) {
10345 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10346 return;
10347 }
10348
10349 try {
10350 IBackupManager bm = IBackupManager.Stub.asInterface(
10351 ServiceManager.getService(Context.BACKUP_SERVICE));
10352 bm.agentConnected(agentPackageName, agent);
10353 } catch (RemoteException e) {
10354 // can't happen; the backup manager service is local
10355 } catch (Exception e) {
10356 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10357 e.printStackTrace();
10358 }
10359 }
10360 }
10361
10362 // done with this agent
10363 public void unbindBackupAgent(ApplicationInfo appInfo) {
10364 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
10365
10366 synchronized(this) {
10367 if (!mBackupAppName.equals(appInfo.packageName)) {
10368 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10369 return;
10370 }
10371
10372 try {
10373 mBackupTarget.app.thread.scheduleDestroyBackupAgent(appInfo);
10374 } catch (Exception e) {
10375 Log.e(TAG, "Exception when unbinding backup agent:");
10376 e.printStackTrace();
10377 }
10378 mBackupTarget = null;
10379 mBackupAppName = null;
10380 }
10381 }
10382 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010383 // BROADCASTS
10384 // =========================================================
10385
10386 private final List getStickies(String action, IntentFilter filter,
10387 List cur) {
10388 final ContentResolver resolver = mContext.getContentResolver();
10389 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10390 if (list == null) {
10391 return cur;
10392 }
10393 int N = list.size();
10394 for (int i=0; i<N; i++) {
10395 Intent intent = list.get(i);
10396 if (filter.match(resolver, intent, true, TAG) >= 0) {
10397 if (cur == null) {
10398 cur = new ArrayList<Intent>();
10399 }
10400 cur.add(intent);
10401 }
10402 }
10403 return cur;
10404 }
10405
10406 private final void scheduleBroadcastsLocked() {
10407 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10408 + mBroadcastsScheduled);
10409
10410 if (mBroadcastsScheduled) {
10411 return;
10412 }
10413 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10414 mBroadcastsScheduled = true;
10415 }
10416
10417 public Intent registerReceiver(IApplicationThread caller,
10418 IIntentReceiver receiver, IntentFilter filter, String permission) {
10419 synchronized(this) {
10420 ProcessRecord callerApp = null;
10421 if (caller != null) {
10422 callerApp = getRecordForAppLocked(caller);
10423 if (callerApp == null) {
10424 throw new SecurityException(
10425 "Unable to find app for caller " + caller
10426 + " (pid=" + Binder.getCallingPid()
10427 + ") when registering receiver " + receiver);
10428 }
10429 }
10430
10431 List allSticky = null;
10432
10433 // Look for any matching sticky broadcasts...
10434 Iterator actions = filter.actionsIterator();
10435 if (actions != null) {
10436 while (actions.hasNext()) {
10437 String action = (String)actions.next();
10438 allSticky = getStickies(action, filter, allSticky);
10439 }
10440 } else {
10441 allSticky = getStickies(null, filter, allSticky);
10442 }
10443
10444 // The first sticky in the list is returned directly back to
10445 // the client.
10446 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10447
10448 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10449 + ": " + sticky);
10450
10451 if (receiver == null) {
10452 return sticky;
10453 }
10454
10455 ReceiverList rl
10456 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10457 if (rl == null) {
10458 rl = new ReceiverList(this, callerApp,
10459 Binder.getCallingPid(),
10460 Binder.getCallingUid(), receiver);
10461 if (rl.app != null) {
10462 rl.app.receivers.add(rl);
10463 } else {
10464 try {
10465 receiver.asBinder().linkToDeath(rl, 0);
10466 } catch (RemoteException e) {
10467 return sticky;
10468 }
10469 rl.linkedToDeath = true;
10470 }
10471 mRegisteredReceivers.put(receiver.asBinder(), rl);
10472 }
10473 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10474 rl.add(bf);
10475 if (!bf.debugCheck()) {
10476 Log.w(TAG, "==> For Dynamic broadast");
10477 }
10478 mReceiverResolver.addFilter(bf);
10479
10480 // Enqueue broadcasts for all existing stickies that match
10481 // this filter.
10482 if (allSticky != null) {
10483 ArrayList receivers = new ArrayList();
10484 receivers.add(bf);
10485
10486 int N = allSticky.size();
10487 for (int i=0; i<N; i++) {
10488 Intent intent = (Intent)allSticky.get(i);
10489 BroadcastRecord r = new BroadcastRecord(intent, null,
10490 null, -1, -1, null, receivers, null, 0, null, null,
10491 false);
10492 if (mParallelBroadcasts.size() == 0) {
10493 scheduleBroadcastsLocked();
10494 }
10495 mParallelBroadcasts.add(r);
10496 }
10497 }
10498
10499 return sticky;
10500 }
10501 }
10502
10503 public void unregisterReceiver(IIntentReceiver receiver) {
10504 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10505
10506 boolean doNext = false;
10507
10508 synchronized(this) {
10509 ReceiverList rl
10510 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10511 if (rl != null) {
10512 if (rl.curBroadcast != null) {
10513 BroadcastRecord r = rl.curBroadcast;
10514 doNext = finishReceiverLocked(
10515 receiver.asBinder(), r.resultCode, r.resultData,
10516 r.resultExtras, r.resultAbort, true);
10517 }
10518
10519 if (rl.app != null) {
10520 rl.app.receivers.remove(rl);
10521 }
10522 removeReceiverLocked(rl);
10523 if (rl.linkedToDeath) {
10524 rl.linkedToDeath = false;
10525 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10526 }
10527 }
10528 }
10529
10530 if (!doNext) {
10531 return;
10532 }
10533
10534 final long origId = Binder.clearCallingIdentity();
10535 processNextBroadcast(false);
10536 trimApplications();
10537 Binder.restoreCallingIdentity(origId);
10538 }
10539
10540 void removeReceiverLocked(ReceiverList rl) {
10541 mRegisteredReceivers.remove(rl.receiver.asBinder());
10542 int N = rl.size();
10543 for (int i=0; i<N; i++) {
10544 mReceiverResolver.removeFilter(rl.get(i));
10545 }
10546 }
10547
10548 private final int broadcastIntentLocked(ProcessRecord callerApp,
10549 String callerPackage, Intent intent, String resolvedType,
10550 IIntentReceiver resultTo, int resultCode, String resultData,
10551 Bundle map, String requiredPermission,
10552 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10553 intent = new Intent(intent);
10554
10555 if (DEBUG_BROADCAST) Log.v(
10556 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10557 + " ordered=" + ordered);
10558 if ((resultTo != null) && !ordered) {
10559 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10560 }
10561
10562 // Handle special intents: if this broadcast is from the package
10563 // manager about a package being removed, we need to remove all of
10564 // its activities from the history stack.
10565 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10566 intent.getAction());
10567 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10568 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10569 || uidRemoved) {
10570 if (checkComponentPermission(
10571 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10572 callingPid, callingUid, -1)
10573 == PackageManager.PERMISSION_GRANTED) {
10574 if (uidRemoved) {
10575 final Bundle intentExtras = intent.getExtras();
10576 final int uid = intentExtras != null
10577 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10578 if (uid >= 0) {
10579 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10580 synchronized (bs) {
10581 bs.removeUidStatsLocked(uid);
10582 }
10583 }
10584 } else {
10585 Uri data = intent.getData();
10586 String ssp;
10587 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10588 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10589 uninstallPackageLocked(ssp,
10590 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10591 }
10592 }
10593 }
10594 } else {
10595 String msg = "Permission Denial: " + intent.getAction()
10596 + " broadcast from " + callerPackage + " (pid=" + callingPid
10597 + ", uid=" + callingUid + ")"
10598 + " requires "
10599 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10600 Log.w(TAG, msg);
10601 throw new SecurityException(msg);
10602 }
10603 }
10604
10605 /*
10606 * If this is the time zone changed action, queue up a message that will reset the timezone
10607 * of all currently running processes. This message will get queued up before the broadcast
10608 * happens.
10609 */
10610 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10611 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10612 }
10613
10614 // Add to the sticky list if requested.
10615 if (sticky) {
10616 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10617 callingPid, callingUid)
10618 != PackageManager.PERMISSION_GRANTED) {
10619 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10620 + callingPid + ", uid=" + callingUid
10621 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10622 Log.w(TAG, msg);
10623 throw new SecurityException(msg);
10624 }
10625 if (requiredPermission != null) {
10626 Log.w(TAG, "Can't broadcast sticky intent " + intent
10627 + " and enforce permission " + requiredPermission);
10628 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10629 }
10630 if (intent.getComponent() != null) {
10631 throw new SecurityException(
10632 "Sticky broadcasts can't target a specific component");
10633 }
10634 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10635 if (list == null) {
10636 list = new ArrayList<Intent>();
10637 mStickyBroadcasts.put(intent.getAction(), list);
10638 }
10639 int N = list.size();
10640 int i;
10641 for (i=0; i<N; i++) {
10642 if (intent.filterEquals(list.get(i))) {
10643 // This sticky already exists, replace it.
10644 list.set(i, new Intent(intent));
10645 break;
10646 }
10647 }
10648 if (i >= N) {
10649 list.add(new Intent(intent));
10650 }
10651 }
10652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010653 // Figure out who all will receive this broadcast.
10654 List receivers = null;
10655 List<BroadcastFilter> registeredReceivers = null;
10656 try {
10657 if (intent.getComponent() != null) {
10658 // Broadcast is going to one specific receiver class...
10659 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010660 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010661 if (ai != null) {
10662 receivers = new ArrayList();
10663 ResolveInfo ri = new ResolveInfo();
10664 ri.activityInfo = ai;
10665 receivers.add(ri);
10666 }
10667 } else {
10668 // Need to resolve the intent to interested receivers...
10669 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10670 == 0) {
10671 receivers =
10672 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010673 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010674 }
Mihai Preda074edef2009-05-18 17:13:31 +020010675 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010676 }
10677 } catch (RemoteException ex) {
10678 // pm is in same process, this will never happen.
10679 }
10680
10681 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10682 if (!ordered && NR > 0) {
10683 // If we are not serializing this broadcast, then send the
10684 // registered receivers separately so they don't wait for the
10685 // components to be launched.
10686 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10687 callerPackage, callingPid, callingUid, requiredPermission,
10688 registeredReceivers, resultTo, resultCode, resultData, map,
10689 ordered);
10690 if (DEBUG_BROADCAST) Log.v(
10691 TAG, "Enqueueing parallel broadcast " + r
10692 + ": prev had " + mParallelBroadcasts.size());
10693 mParallelBroadcasts.add(r);
10694 scheduleBroadcastsLocked();
10695 registeredReceivers = null;
10696 NR = 0;
10697 }
10698
10699 // Merge into one list.
10700 int ir = 0;
10701 if (receivers != null) {
10702 // A special case for PACKAGE_ADDED: do not allow the package
10703 // being added to see this broadcast. This prevents them from
10704 // using this as a back door to get run as soon as they are
10705 // installed. Maybe in the future we want to have a special install
10706 // broadcast or such for apps, but we'd like to deliberately make
10707 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010708 boolean skip = false;
10709 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010710 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010711 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10712 skip = true;
10713 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10714 skip = true;
10715 }
10716 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010717 ? intent.getData().getSchemeSpecificPart()
10718 : null;
10719 if (skipPackage != null && receivers != null) {
10720 int NT = receivers.size();
10721 for (int it=0; it<NT; it++) {
10722 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10723 if (curt.activityInfo.packageName.equals(skipPackage)) {
10724 receivers.remove(it);
10725 it--;
10726 NT--;
10727 }
10728 }
10729 }
10730
10731 int NT = receivers != null ? receivers.size() : 0;
10732 int it = 0;
10733 ResolveInfo curt = null;
10734 BroadcastFilter curr = null;
10735 while (it < NT && ir < NR) {
10736 if (curt == null) {
10737 curt = (ResolveInfo)receivers.get(it);
10738 }
10739 if (curr == null) {
10740 curr = registeredReceivers.get(ir);
10741 }
10742 if (curr.getPriority() >= curt.priority) {
10743 // Insert this broadcast record into the final list.
10744 receivers.add(it, curr);
10745 ir++;
10746 curr = null;
10747 it++;
10748 NT++;
10749 } else {
10750 // Skip to the next ResolveInfo in the final list.
10751 it++;
10752 curt = null;
10753 }
10754 }
10755 }
10756 while (ir < NR) {
10757 if (receivers == null) {
10758 receivers = new ArrayList();
10759 }
10760 receivers.add(registeredReceivers.get(ir));
10761 ir++;
10762 }
10763
10764 if ((receivers != null && receivers.size() > 0)
10765 || resultTo != null) {
10766 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10767 callerPackage, callingPid, callingUid, requiredPermission,
10768 receivers, resultTo, resultCode, resultData, map, ordered);
10769 if (DEBUG_BROADCAST) Log.v(
10770 TAG, "Enqueueing ordered broadcast " + r
10771 + ": prev had " + mOrderedBroadcasts.size());
10772 if (DEBUG_BROADCAST) {
10773 int seq = r.intent.getIntExtra("seq", -1);
10774 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10775 }
10776 mOrderedBroadcasts.add(r);
10777 scheduleBroadcastsLocked();
10778 }
10779
10780 return BROADCAST_SUCCESS;
10781 }
10782
10783 public final int broadcastIntent(IApplicationThread caller,
10784 Intent intent, String resolvedType, IIntentReceiver resultTo,
10785 int resultCode, String resultData, Bundle map,
10786 String requiredPermission, boolean serialized, boolean sticky) {
10787 // Refuse possible leaked file descriptors
10788 if (intent != null && intent.hasFileDescriptors() == true) {
10789 throw new IllegalArgumentException("File descriptors passed in Intent");
10790 }
10791
10792 synchronized(this) {
10793 if (!mSystemReady) {
10794 // if the caller really truly claims to know what they're doing, go
10795 // ahead and allow the broadcast without launching any receivers
10796 int flags = intent.getFlags();
10797 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10798 intent = new Intent(intent);
10799 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10800 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10801 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10802 + " before boot completion");
10803 throw new IllegalStateException("Cannot broadcast before boot completed");
10804 }
10805 }
10806
10807 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10808 final int callingPid = Binder.getCallingPid();
10809 final int callingUid = Binder.getCallingUid();
10810 final long origId = Binder.clearCallingIdentity();
10811 int res = broadcastIntentLocked(callerApp,
10812 callerApp != null ? callerApp.info.packageName : null,
10813 intent, resolvedType, resultTo,
10814 resultCode, resultData, map, requiredPermission, serialized,
10815 sticky, callingPid, callingUid);
10816 Binder.restoreCallingIdentity(origId);
10817 return res;
10818 }
10819 }
10820
10821 int broadcastIntentInPackage(String packageName, int uid,
10822 Intent intent, String resolvedType, IIntentReceiver resultTo,
10823 int resultCode, String resultData, Bundle map,
10824 String requiredPermission, boolean serialized, boolean sticky) {
10825 synchronized(this) {
10826 final long origId = Binder.clearCallingIdentity();
10827 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10828 resultTo, resultCode, resultData, map, requiredPermission,
10829 serialized, sticky, -1, uid);
10830 Binder.restoreCallingIdentity(origId);
10831 return res;
10832 }
10833 }
10834
10835 public final void unbroadcastIntent(IApplicationThread caller,
10836 Intent intent) {
10837 // Refuse possible leaked file descriptors
10838 if (intent != null && intent.hasFileDescriptors() == true) {
10839 throw new IllegalArgumentException("File descriptors passed in Intent");
10840 }
10841
10842 synchronized(this) {
10843 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10844 != PackageManager.PERMISSION_GRANTED) {
10845 String msg = "Permission Denial: unbroadcastIntent() from pid="
10846 + Binder.getCallingPid()
10847 + ", uid=" + Binder.getCallingUid()
10848 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10849 Log.w(TAG, msg);
10850 throw new SecurityException(msg);
10851 }
10852 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10853 if (list != null) {
10854 int N = list.size();
10855 int i;
10856 for (i=0; i<N; i++) {
10857 if (intent.filterEquals(list.get(i))) {
10858 list.remove(i);
10859 break;
10860 }
10861 }
10862 }
10863 }
10864 }
10865
10866 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10867 String resultData, Bundle resultExtras, boolean resultAbort,
10868 boolean explicit) {
10869 if (mOrderedBroadcasts.size() == 0) {
10870 if (explicit) {
10871 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10872 }
10873 return false;
10874 }
10875 BroadcastRecord r = mOrderedBroadcasts.get(0);
10876 if (r.receiver == null) {
10877 if (explicit) {
10878 Log.w(TAG, "finishReceiver called but none active");
10879 }
10880 return false;
10881 }
10882 if (r.receiver != receiver) {
10883 Log.w(TAG, "finishReceiver called but active receiver is different");
10884 return false;
10885 }
10886 int state = r.state;
10887 r.state = r.IDLE;
10888 if (state == r.IDLE) {
10889 if (explicit) {
10890 Log.w(TAG, "finishReceiver called but state is IDLE");
10891 }
10892 }
10893 r.receiver = null;
10894 r.intent.setComponent(null);
10895 if (r.curApp != null) {
10896 r.curApp.curReceiver = null;
10897 }
10898 if (r.curFilter != null) {
10899 r.curFilter.receiverList.curBroadcast = null;
10900 }
10901 r.curFilter = null;
10902 r.curApp = null;
10903 r.curComponent = null;
10904 r.curReceiver = null;
10905 mPendingBroadcast = null;
10906
10907 r.resultCode = resultCode;
10908 r.resultData = resultData;
10909 r.resultExtras = resultExtras;
10910 r.resultAbort = resultAbort;
10911
10912 // We will process the next receiver right now if this is finishing
10913 // an app receiver (which is always asynchronous) or after we have
10914 // come back from calling a receiver.
10915 return state == BroadcastRecord.APP_RECEIVE
10916 || state == BroadcastRecord.CALL_DONE_RECEIVE;
10917 }
10918
10919 public void finishReceiver(IBinder who, int resultCode, String resultData,
10920 Bundle resultExtras, boolean resultAbort) {
10921 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
10922
10923 // Refuse possible leaked file descriptors
10924 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
10925 throw new IllegalArgumentException("File descriptors passed in Bundle");
10926 }
10927
10928 boolean doNext;
10929
10930 final long origId = Binder.clearCallingIdentity();
10931
10932 synchronized(this) {
10933 doNext = finishReceiverLocked(
10934 who, resultCode, resultData, resultExtras, resultAbort, true);
10935 }
10936
10937 if (doNext) {
10938 processNextBroadcast(false);
10939 }
10940 trimApplications();
10941
10942 Binder.restoreCallingIdentity(origId);
10943 }
10944
10945 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
10946 if (r.nextReceiver > 0) {
10947 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10948 if (curReceiver instanceof BroadcastFilter) {
10949 BroadcastFilter bf = (BroadcastFilter) curReceiver;
10950 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
10951 System.identityHashCode(r),
10952 r.intent.getAction(),
10953 r.nextReceiver - 1,
10954 System.identityHashCode(bf));
10955 } else {
10956 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10957 System.identityHashCode(r),
10958 r.intent.getAction(),
10959 r.nextReceiver - 1,
10960 ((ResolveInfo)curReceiver).toString());
10961 }
10962 } else {
10963 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
10964 + r);
10965 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10966 System.identityHashCode(r),
10967 r.intent.getAction(),
10968 r.nextReceiver,
10969 "NONE");
10970 }
10971 }
10972
10973 private final void broadcastTimeout() {
10974 synchronized (this) {
10975 if (mOrderedBroadcasts.size() == 0) {
10976 return;
10977 }
10978 long now = SystemClock.uptimeMillis();
10979 BroadcastRecord r = mOrderedBroadcasts.get(0);
10980 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
10981 if (DEBUG_BROADCAST) Log.v(TAG,
10982 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
10983 + (r.startTime + BROADCAST_TIMEOUT));
10984 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
10985 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
10986 return;
10987 }
10988
10989 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
10990 r.startTime = now;
10991 r.anrCount++;
10992
10993 // Current receiver has passed its expiration date.
10994 if (r.nextReceiver <= 0) {
10995 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
10996 return;
10997 }
10998
10999 ProcessRecord app = null;
11000
11001 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11002 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11003 logBroadcastReceiverDiscard(r);
11004 if (curReceiver instanceof BroadcastFilter) {
11005 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11006 if (bf.receiverList.pid != 0
11007 && bf.receiverList.pid != MY_PID) {
11008 synchronized (this.mPidsSelfLocked) {
11009 app = this.mPidsSelfLocked.get(
11010 bf.receiverList.pid);
11011 }
11012 }
11013 } else {
11014 app = r.curApp;
11015 }
11016
11017 if (app != null) {
11018 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11019 }
11020
11021 if (mPendingBroadcast == r) {
11022 mPendingBroadcast = null;
11023 }
11024
11025 // Move on to the next receiver.
11026 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11027 r.resultExtras, r.resultAbort, true);
11028 scheduleBroadcastsLocked();
11029 }
11030 }
11031
11032 private final void processCurBroadcastLocked(BroadcastRecord r,
11033 ProcessRecord app) throws RemoteException {
11034 if (app.thread == null) {
11035 throw new RemoteException();
11036 }
11037 r.receiver = app.thread.asBinder();
11038 r.curApp = app;
11039 app.curReceiver = r;
11040 updateLRUListLocked(app, true);
11041
11042 // Tell the application to launch this receiver.
11043 r.intent.setComponent(r.curComponent);
11044
11045 boolean started = false;
11046 try {
11047 if (DEBUG_BROADCAST) Log.v(TAG,
11048 "Delivering to component " + r.curComponent
11049 + ": " + r);
11050 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11051 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11052 started = true;
11053 } finally {
11054 if (!started) {
11055 r.receiver = null;
11056 r.curApp = null;
11057 app.curReceiver = null;
11058 }
11059 }
11060
11061 }
11062
11063 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11064 Intent intent, int resultCode, String data,
11065 Bundle extras, boolean ordered) throws RemoteException {
11066 if (app != null && app.thread != null) {
11067 // If we have an app thread, do the call through that so it is
11068 // correctly ordered with other one-way calls.
11069 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11070 data, extras, ordered);
11071 } else {
11072 receiver.performReceive(intent, resultCode, data, extras, ordered);
11073 }
11074 }
11075
11076 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11077 BroadcastFilter filter, boolean ordered) {
11078 boolean skip = false;
11079 if (filter.requiredPermission != null) {
11080 int perm = checkComponentPermission(filter.requiredPermission,
11081 r.callingPid, r.callingUid, -1);
11082 if (perm != PackageManager.PERMISSION_GRANTED) {
11083 Log.w(TAG, "Permission Denial: broadcasting "
11084 + r.intent.toString()
11085 + " from " + r.callerPackage + " (pid="
11086 + r.callingPid + ", uid=" + r.callingUid + ")"
11087 + " requires " + filter.requiredPermission
11088 + " due to registered receiver " + filter);
11089 skip = true;
11090 }
11091 }
11092 if (r.requiredPermission != null) {
11093 int perm = checkComponentPermission(r.requiredPermission,
11094 filter.receiverList.pid, filter.receiverList.uid, -1);
11095 if (perm != PackageManager.PERMISSION_GRANTED) {
11096 Log.w(TAG, "Permission Denial: receiving "
11097 + r.intent.toString()
11098 + " to " + filter.receiverList.app
11099 + " (pid=" + filter.receiverList.pid
11100 + ", uid=" + filter.receiverList.uid + ")"
11101 + " requires " + r.requiredPermission
11102 + " due to sender " + r.callerPackage
11103 + " (uid " + r.callingUid + ")");
11104 skip = true;
11105 }
11106 }
11107
11108 if (!skip) {
11109 // If this is not being sent as an ordered broadcast, then we
11110 // don't want to touch the fields that keep track of the current
11111 // state of ordered broadcasts.
11112 if (ordered) {
11113 r.receiver = filter.receiverList.receiver.asBinder();
11114 r.curFilter = filter;
11115 filter.receiverList.curBroadcast = r;
11116 r.state = BroadcastRecord.CALL_IN_RECEIVE;
11117 }
11118 try {
11119 if (DEBUG_BROADCAST) {
11120 int seq = r.intent.getIntExtra("seq", -1);
11121 Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
11122 + " app=" + filter.receiverList.app);
11123 }
11124 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11125 new Intent(r.intent), r.resultCode,
11126 r.resultData, r.resultExtras, r.ordered);
11127 if (ordered) {
11128 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11129 }
11130 } catch (RemoteException e) {
11131 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11132 if (ordered) {
11133 r.receiver = null;
11134 r.curFilter = null;
11135 filter.receiverList.curBroadcast = null;
11136 }
11137 }
11138 }
11139 }
11140
11141 private final void processNextBroadcast(boolean fromMsg) {
11142 synchronized(this) {
11143 BroadcastRecord r;
11144
11145 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11146 + mParallelBroadcasts.size() + " broadcasts, "
11147 + mOrderedBroadcasts.size() + " serialized broadcasts");
11148
11149 updateCpuStats();
11150
11151 if (fromMsg) {
11152 mBroadcastsScheduled = false;
11153 }
11154
11155 // First, deliver any non-serialized broadcasts right away.
11156 while (mParallelBroadcasts.size() > 0) {
11157 r = mParallelBroadcasts.remove(0);
11158 final int N = r.receivers.size();
11159 for (int i=0; i<N; i++) {
11160 Object target = r.receivers.get(i);
11161 if (DEBUG_BROADCAST) Log.v(TAG,
11162 "Delivering non-serialized to registered "
11163 + target + ": " + r);
11164 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11165 }
11166 }
11167
11168 // Now take care of the next serialized one...
11169
11170 // If we are waiting for a process to come up to handle the next
11171 // broadcast, then do nothing at this point. Just in case, we
11172 // check that the process we're waiting for still exists.
11173 if (mPendingBroadcast != null) {
11174 Log.i(TAG, "processNextBroadcast: waiting for "
11175 + mPendingBroadcast.curApp);
11176
11177 boolean isDead;
11178 synchronized (mPidsSelfLocked) {
11179 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11180 }
11181 if (!isDead) {
11182 // It's still alive, so keep waiting
11183 return;
11184 } else {
11185 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11186 + " died before responding to broadcast");
11187 mPendingBroadcast = null;
11188 }
11189 }
11190
11191 do {
11192 if (mOrderedBroadcasts.size() == 0) {
11193 // No more broadcasts pending, so all done!
11194 scheduleAppGcsLocked();
11195 return;
11196 }
11197 r = mOrderedBroadcasts.get(0);
11198 boolean forceReceive = false;
11199
11200 // Ensure that even if something goes awry with the timeout
11201 // detection, we catch "hung" broadcasts here, discard them,
11202 // and continue to make progress.
11203 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11204 long now = SystemClock.uptimeMillis();
11205 if (r.dispatchTime > 0) {
11206 if ((numReceivers > 0) &&
11207 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11208 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11209 + " now=" + now
11210 + " dispatchTime=" + r.dispatchTime
11211 + " startTime=" + r.startTime
11212 + " intent=" + r.intent
11213 + " numReceivers=" + numReceivers
11214 + " nextReceiver=" + r.nextReceiver
11215 + " state=" + r.state);
11216 broadcastTimeout(); // forcibly finish this broadcast
11217 forceReceive = true;
11218 r.state = BroadcastRecord.IDLE;
11219 }
11220 }
11221
11222 if (r.state != BroadcastRecord.IDLE) {
11223 if (DEBUG_BROADCAST) Log.d(TAG,
11224 "processNextBroadcast() called when not idle (state="
11225 + r.state + ")");
11226 return;
11227 }
11228
11229 if (r.receivers == null || r.nextReceiver >= numReceivers
11230 || r.resultAbort || forceReceive) {
11231 // No more receivers for this broadcast! Send the final
11232 // result if requested...
11233 if (r.resultTo != null) {
11234 try {
11235 if (DEBUG_BROADCAST) {
11236 int seq = r.intent.getIntExtra("seq", -1);
11237 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11238 + " seq=" + seq + " app=" + r.callerApp);
11239 }
11240 performReceive(r.callerApp, r.resultTo,
11241 new Intent(r.intent), r.resultCode,
11242 r.resultData, r.resultExtras, false);
11243 } catch (RemoteException e) {
11244 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11245 }
11246 }
11247
11248 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11249 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11250
11251 // ... and on to the next...
11252 mOrderedBroadcasts.remove(0);
11253 r = null;
11254 continue;
11255 }
11256 } while (r == null);
11257
11258 // Get the next receiver...
11259 int recIdx = r.nextReceiver++;
11260
11261 // Keep track of when this receiver started, and make sure there
11262 // is a timeout message pending to kill it if need be.
11263 r.startTime = SystemClock.uptimeMillis();
11264 if (recIdx == 0) {
11265 r.dispatchTime = r.startTime;
11266
11267 if (DEBUG_BROADCAST) Log.v(TAG,
11268 "Submitting BROADCAST_TIMEOUT_MSG for "
11269 + (r.startTime + BROADCAST_TIMEOUT));
11270 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11271 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11272 }
11273
11274 Object nextReceiver = r.receivers.get(recIdx);
11275 if (nextReceiver instanceof BroadcastFilter) {
11276 // Simple case: this is a registered receiver who gets
11277 // a direct call.
11278 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11279 if (DEBUG_BROADCAST) Log.v(TAG,
11280 "Delivering serialized to registered "
11281 + filter + ": " + r);
11282 deliverToRegisteredReceiver(r, filter, r.ordered);
11283 if (r.receiver == null || !r.ordered) {
11284 // The receiver has already finished, so schedule to
11285 // process the next one.
11286 r.state = BroadcastRecord.IDLE;
11287 scheduleBroadcastsLocked();
11288 }
11289 return;
11290 }
11291
11292 // Hard case: need to instantiate the receiver, possibly
11293 // starting its application process to host it.
11294
11295 ResolveInfo info =
11296 (ResolveInfo)nextReceiver;
11297
11298 boolean skip = false;
11299 int perm = checkComponentPermission(info.activityInfo.permission,
11300 r.callingPid, r.callingUid,
11301 info.activityInfo.exported
11302 ? -1 : info.activityInfo.applicationInfo.uid);
11303 if (perm != PackageManager.PERMISSION_GRANTED) {
11304 Log.w(TAG, "Permission Denial: broadcasting "
11305 + r.intent.toString()
11306 + " from " + r.callerPackage + " (pid=" + r.callingPid
11307 + ", uid=" + r.callingUid + ")"
11308 + " requires " + info.activityInfo.permission
11309 + " due to receiver " + info.activityInfo.packageName
11310 + "/" + info.activityInfo.name);
11311 skip = true;
11312 }
11313 if (r.callingUid != Process.SYSTEM_UID &&
11314 r.requiredPermission != null) {
11315 try {
11316 perm = ActivityThread.getPackageManager().
11317 checkPermission(r.requiredPermission,
11318 info.activityInfo.applicationInfo.packageName);
11319 } catch (RemoteException e) {
11320 perm = PackageManager.PERMISSION_DENIED;
11321 }
11322 if (perm != PackageManager.PERMISSION_GRANTED) {
11323 Log.w(TAG, "Permission Denial: receiving "
11324 + r.intent + " to "
11325 + info.activityInfo.applicationInfo.packageName
11326 + " requires " + r.requiredPermission
11327 + " due to sender " + r.callerPackage
11328 + " (uid " + r.callingUid + ")");
11329 skip = true;
11330 }
11331 }
11332 if (r.curApp != null && r.curApp.crashing) {
11333 // If the target process is crashing, just skip it.
11334 skip = true;
11335 }
11336
11337 if (skip) {
11338 r.receiver = null;
11339 r.curFilter = null;
11340 r.state = BroadcastRecord.IDLE;
11341 scheduleBroadcastsLocked();
11342 return;
11343 }
11344
11345 r.state = BroadcastRecord.APP_RECEIVE;
11346 String targetProcess = info.activityInfo.processName;
11347 r.curComponent = new ComponentName(
11348 info.activityInfo.applicationInfo.packageName,
11349 info.activityInfo.name);
11350 r.curReceiver = info.activityInfo;
11351
11352 // Is this receiver's application already running?
11353 ProcessRecord app = getProcessRecordLocked(targetProcess,
11354 info.activityInfo.applicationInfo.uid);
11355 if (app != null && app.thread != null) {
11356 try {
11357 processCurBroadcastLocked(r, app);
11358 return;
11359 } catch (RemoteException e) {
11360 Log.w(TAG, "Exception when sending broadcast to "
11361 + r.curComponent, e);
11362 }
11363
11364 // If a dead object exception was thrown -- fall through to
11365 // restart the application.
11366 }
11367
11368 // Not running -- get it started, and enqueue this history record
11369 // to be executed when the app comes up.
11370 if ((r.curApp=startProcessLocked(targetProcess,
11371 info.activityInfo.applicationInfo, true,
11372 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11373 "broadcast", r.curComponent)) == null) {
11374 // Ah, this recipient is unavailable. Finish it if necessary,
11375 // and mark the broadcast record as ready for the next.
11376 Log.w(TAG, "Unable to launch app "
11377 + info.activityInfo.applicationInfo.packageName + "/"
11378 + info.activityInfo.applicationInfo.uid + " for broadcast "
11379 + r.intent + ": process is bad");
11380 logBroadcastReceiverDiscard(r);
11381 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11382 r.resultExtras, r.resultAbort, true);
11383 scheduleBroadcastsLocked();
11384 r.state = BroadcastRecord.IDLE;
11385 return;
11386 }
11387
11388 mPendingBroadcast = r;
11389 }
11390 }
11391
11392 // =========================================================
11393 // INSTRUMENTATION
11394 // =========================================================
11395
11396 public boolean startInstrumentation(ComponentName className,
11397 String profileFile, int flags, Bundle arguments,
11398 IInstrumentationWatcher watcher) {
11399 // Refuse possible leaked file descriptors
11400 if (arguments != null && arguments.hasFileDescriptors()) {
11401 throw new IllegalArgumentException("File descriptors passed in Bundle");
11402 }
11403
11404 synchronized(this) {
11405 InstrumentationInfo ii = null;
11406 ApplicationInfo ai = null;
11407 try {
11408 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011409 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011410 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011411 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011412 } catch (PackageManager.NameNotFoundException e) {
11413 }
11414 if (ii == null) {
11415 reportStartInstrumentationFailure(watcher, className,
11416 "Unable to find instrumentation info for: " + className);
11417 return false;
11418 }
11419 if (ai == null) {
11420 reportStartInstrumentationFailure(watcher, className,
11421 "Unable to find instrumentation target package: " + ii.targetPackage);
11422 return false;
11423 }
11424
11425 int match = mContext.getPackageManager().checkSignatures(
11426 ii.targetPackage, ii.packageName);
11427 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11428 String msg = "Permission Denial: starting instrumentation "
11429 + className + " from pid="
11430 + Binder.getCallingPid()
11431 + ", uid=" + Binder.getCallingPid()
11432 + " not allowed because package " + ii.packageName
11433 + " does not have a signature matching the target "
11434 + ii.targetPackage;
11435 reportStartInstrumentationFailure(watcher, className, msg);
11436 throw new SecurityException(msg);
11437 }
11438
11439 final long origId = Binder.clearCallingIdentity();
11440 uninstallPackageLocked(ii.targetPackage, -1, true);
11441 ProcessRecord app = addAppLocked(ai);
11442 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011443 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011444 app.instrumentationProfileFile = profileFile;
11445 app.instrumentationArguments = arguments;
11446 app.instrumentationWatcher = watcher;
11447 app.instrumentationResultClass = className;
11448 Binder.restoreCallingIdentity(origId);
11449 }
11450
11451 return true;
11452 }
11453
11454 /**
11455 * Report errors that occur while attempting to start Instrumentation. Always writes the
11456 * error to the logs, but if somebody is watching, send the report there too. This enables
11457 * the "am" command to report errors with more information.
11458 *
11459 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11460 * @param cn The component name of the instrumentation.
11461 * @param report The error report.
11462 */
11463 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11464 ComponentName cn, String report) {
11465 Log.w(TAG, report);
11466 try {
11467 if (watcher != null) {
11468 Bundle results = new Bundle();
11469 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11470 results.putString("Error", report);
11471 watcher.instrumentationStatus(cn, -1, results);
11472 }
11473 } catch (RemoteException e) {
11474 Log.w(TAG, e);
11475 }
11476 }
11477
11478 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11479 if (app.instrumentationWatcher != null) {
11480 try {
11481 // NOTE: IInstrumentationWatcher *must* be oneway here
11482 app.instrumentationWatcher.instrumentationFinished(
11483 app.instrumentationClass,
11484 resultCode,
11485 results);
11486 } catch (RemoteException e) {
11487 }
11488 }
11489 app.instrumentationWatcher = null;
11490 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011491 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011492 app.instrumentationProfileFile = null;
11493 app.instrumentationArguments = null;
11494
11495 uninstallPackageLocked(app.processName, -1, false);
11496 }
11497
11498 public void finishInstrumentation(IApplicationThread target,
11499 int resultCode, Bundle results) {
11500 // Refuse possible leaked file descriptors
11501 if (results != null && results.hasFileDescriptors()) {
11502 throw new IllegalArgumentException("File descriptors passed in Intent");
11503 }
11504
11505 synchronized(this) {
11506 ProcessRecord app = getRecordForAppLocked(target);
11507 if (app == null) {
11508 Log.w(TAG, "finishInstrumentation: no app for " + target);
11509 return;
11510 }
11511 final long origId = Binder.clearCallingIdentity();
11512 finishInstrumentationLocked(app, resultCode, results);
11513 Binder.restoreCallingIdentity(origId);
11514 }
11515 }
11516
11517 // =========================================================
11518 // CONFIGURATION
11519 // =========================================================
11520
11521 public ConfigurationInfo getDeviceConfigurationInfo() {
11522 ConfigurationInfo config = new ConfigurationInfo();
11523 synchronized (this) {
11524 config.reqTouchScreen = mConfiguration.touchscreen;
11525 config.reqKeyboardType = mConfiguration.keyboard;
11526 config.reqNavigation = mConfiguration.navigation;
11527 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11528 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11529 }
11530 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11531 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11532 }
11533 }
11534 return config;
11535 }
11536
11537 public Configuration getConfiguration() {
11538 Configuration ci;
11539 synchronized(this) {
11540 ci = new Configuration(mConfiguration);
11541 }
11542 return ci;
11543 }
11544
11545 public void updateConfiguration(Configuration values) {
11546 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11547 "updateConfiguration()");
11548
11549 synchronized(this) {
11550 if (values == null && mWindowManager != null) {
11551 // sentinel: fetch the current configuration from the window manager
11552 values = mWindowManager.computeNewConfiguration();
11553 }
11554
11555 final long origId = Binder.clearCallingIdentity();
11556 updateConfigurationLocked(values, null);
11557 Binder.restoreCallingIdentity(origId);
11558 }
11559 }
11560
11561 /**
11562 * Do either or both things: (1) change the current configuration, and (2)
11563 * make sure the given activity is running with the (now) current
11564 * configuration. Returns true if the activity has been left running, or
11565 * false if <var>starting</var> is being destroyed to match the new
11566 * configuration.
11567 */
11568 public boolean updateConfigurationLocked(Configuration values,
11569 HistoryRecord starting) {
11570 int changes = 0;
11571
11572 boolean kept = true;
11573
11574 if (values != null) {
11575 Configuration newConfig = new Configuration(mConfiguration);
11576 changes = newConfig.updateFrom(values);
11577 if (changes != 0) {
11578 if (DEBUG_SWITCH) {
11579 Log.i(TAG, "Updating configuration to: " + values);
11580 }
11581
11582 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11583
11584 if (values.locale != null) {
11585 saveLocaleLocked(values.locale,
11586 !values.locale.equals(mConfiguration.locale),
11587 values.userSetLocale);
11588 }
11589
11590 mConfiguration = newConfig;
11591
11592 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11593 msg.obj = new Configuration(mConfiguration);
11594 mHandler.sendMessage(msg);
11595
11596 final int N = mLRUProcesses.size();
11597 for (int i=0; i<N; i++) {
11598 ProcessRecord app = mLRUProcesses.get(i);
11599 try {
11600 if (app.thread != null) {
11601 app.thread.scheduleConfigurationChanged(mConfiguration);
11602 }
11603 } catch (Exception e) {
11604 }
11605 }
11606 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11607 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11608 null, false, false, MY_PID, Process.SYSTEM_UID);
11609 }
11610 }
11611
11612 if (changes != 0 && starting == null) {
11613 // If the configuration changed, and the caller is not already
11614 // in the process of starting an activity, then find the top
11615 // activity to check if its configuration needs to change.
11616 starting = topRunningActivityLocked(null);
11617 }
11618
11619 if (starting != null) {
11620 kept = ensureActivityConfigurationLocked(starting, changes);
11621 if (kept) {
11622 // If this didn't result in the starting activity being
11623 // destroyed, then we need to make sure at this point that all
11624 // other activities are made visible.
11625 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11626 + ", ensuring others are correct.");
11627 ensureActivitiesVisibleLocked(starting, changes);
11628 }
11629 }
11630
11631 return kept;
11632 }
11633
11634 private final boolean relaunchActivityLocked(HistoryRecord r,
11635 int changes, boolean andResume) {
11636 List<ResultInfo> results = null;
11637 List<Intent> newIntents = null;
11638 if (andResume) {
11639 results = r.results;
11640 newIntents = r.newIntents;
11641 }
11642 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11643 + " with results=" + results + " newIntents=" + newIntents
11644 + " andResume=" + andResume);
11645 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11646 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11647 r.task.taskId, r.shortComponentName);
11648
11649 r.startFreezingScreenLocked(r.app, 0);
11650
11651 try {
11652 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11653 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11654 changes, !andResume);
11655 // Note: don't need to call pauseIfSleepingLocked() here, because
11656 // the caller will only pass in 'andResume' if this activity is
11657 // currently resumed, which implies we aren't sleeping.
11658 } catch (RemoteException e) {
11659 return false;
11660 }
11661
11662 if (andResume) {
11663 r.results = null;
11664 r.newIntents = null;
11665 }
11666
11667 return true;
11668 }
11669
11670 /**
11671 * Make sure the given activity matches the current configuration. Returns
11672 * false if the activity had to be destroyed. Returns true if the
11673 * configuration is the same, or the activity will remain running as-is
11674 * for whatever reason. Ensures the HistoryRecord is updated with the
11675 * correct configuration and all other bookkeeping is handled.
11676 */
11677 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11678 int globalChanges) {
11679 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11680
11681 // Short circuit: if the two configurations are the exact same
11682 // object (the common case), then there is nothing to do.
11683 Configuration newConfig = mConfiguration;
11684 if (r.configuration == newConfig) {
11685 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11686 return true;
11687 }
11688
11689 // We don't worry about activities that are finishing.
11690 if (r.finishing) {
11691 if (DEBUG_SWITCH) Log.i(TAG,
11692 "Configuration doesn't matter in finishing " + r);
11693 r.stopFreezingScreenLocked(false);
11694 return true;
11695 }
11696
11697 // Okay we now are going to make this activity have the new config.
11698 // But then we need to figure out how it needs to deal with that.
11699 Configuration oldConfig = r.configuration;
11700 r.configuration = newConfig;
11701
11702 // If the activity isn't currently running, just leave the new
11703 // configuration and it will pick that up next time it starts.
11704 if (r.app == null || r.app.thread == null) {
11705 if (DEBUG_SWITCH) Log.i(TAG,
11706 "Configuration doesn't matter not running " + r);
11707 r.stopFreezingScreenLocked(false);
11708 return true;
11709 }
11710
11711 // If the activity isn't persistent, there is a chance we will
11712 // need to restart it.
11713 if (!r.persistent) {
11714
11715 // Figure out what has changed between the two configurations.
11716 int changes = oldConfig.diff(newConfig);
11717 if (DEBUG_SWITCH) {
11718 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11719 + Integer.toHexString(changes) + ", handles=0x"
11720 + Integer.toHexString(r.info.configChanges));
11721 }
11722 if ((changes&(~r.info.configChanges)) != 0) {
11723 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11724 r.configChangeFlags |= changes;
11725 r.startFreezingScreenLocked(r.app, globalChanges);
11726 if (r.app == null || r.app.thread == null) {
11727 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11728 destroyActivityLocked(r, true);
11729 } else if (r.state == ActivityState.PAUSING) {
11730 // A little annoying: we are waiting for this activity to
11731 // finish pausing. Let's not do anything now, but just
11732 // flag that it needs to be restarted when done pausing.
11733 r.configDestroy = true;
11734 return true;
11735 } else if (r.state == ActivityState.RESUMED) {
11736 // Try to optimize this case: the configuration is changing
11737 // and we need to restart the top, resumed activity.
11738 // Instead of doing the normal handshaking, just say
11739 // "restart!".
11740 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11741 relaunchActivityLocked(r, r.configChangeFlags, true);
11742 r.configChangeFlags = 0;
11743 } else {
11744 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11745 relaunchActivityLocked(r, r.configChangeFlags, false);
11746 r.configChangeFlags = 0;
11747 }
11748
11749 // All done... tell the caller we weren't able to keep this
11750 // activity around.
11751 return false;
11752 }
11753 }
11754
11755 // Default case: the activity can handle this new configuration, so
11756 // hand it over. Note that we don't need to give it the new
11757 // configuration, since we always send configuration changes to all
11758 // process when they happen so it can just use whatever configuration
11759 // it last got.
11760 if (r.app != null && r.app.thread != null) {
11761 try {
11762 r.app.thread.scheduleActivityConfigurationChanged(r);
11763 } catch (RemoteException e) {
11764 // If process died, whatever.
11765 }
11766 }
11767 r.stopFreezingScreenLocked(false);
11768
11769 return true;
11770 }
11771
11772 /**
11773 * Save the locale. You must be inside a synchronized (this) block.
11774 */
11775 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11776 if(isDiff) {
11777 SystemProperties.set("user.language", l.getLanguage());
11778 SystemProperties.set("user.region", l.getCountry());
11779 }
11780
11781 if(isPersist) {
11782 SystemProperties.set("persist.sys.language", l.getLanguage());
11783 SystemProperties.set("persist.sys.country", l.getCountry());
11784 SystemProperties.set("persist.sys.localevar", l.getVariant());
11785 }
11786 }
11787
11788 // =========================================================
11789 // LIFETIME MANAGEMENT
11790 // =========================================================
11791
11792 private final int computeOomAdjLocked(
11793 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11794 if (mAdjSeq == app.adjSeq) {
11795 // This adjustment has already been computed.
11796 return app.curAdj;
11797 }
11798
11799 if (app.thread == null) {
11800 app.adjSeq = mAdjSeq;
11801 return (app.curAdj=EMPTY_APP_ADJ);
11802 }
11803
11804 app.isForeground = false;
11805
The Android Open Source Project4df24232009-03-05 14:34:35 -080011806 // Determine the importance of the process, starting with most
11807 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011808 int adj;
11809 int N;
11810 if (app == TOP_APP || app.instrumentationClass != null
11811 || app.persistentActivities > 0) {
11812 // The last app on the list is the foreground app.
11813 adj = FOREGROUND_APP_ADJ;
11814 app.isForeground = true;
11815 } else if (app.curReceiver != null ||
11816 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11817 // An app that is currently receiving a broadcast also
11818 // counts as being in the foreground.
11819 adj = FOREGROUND_APP_ADJ;
11820 } else if (app.executingServices.size() > 0) {
11821 // An app that is currently executing a service callback also
11822 // counts as being in the foreground.
11823 adj = FOREGROUND_APP_ADJ;
11824 } else if (app.foregroundServices || app.forcingToForeground != null) {
11825 // The user is aware of this app, so make it visible.
11826 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011827 } else if (app == mHomeProcess) {
11828 // This process is hosting what we currently consider to be the
11829 // home app, so we don't want to let it go into the background.
11830 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011831 } else if ((N=app.activities.size()) != 0) {
11832 // This app is in the background with paused activities.
11833 adj = hiddenAdj;
11834 for (int j=0; j<N; j++) {
11835 if (((HistoryRecord)app.activities.get(j)).visible) {
11836 // This app has a visible activity!
11837 adj = VISIBLE_APP_ADJ;
11838 break;
11839 }
11840 }
11841 } else {
11842 // A very not-needed process.
11843 adj = EMPTY_APP_ADJ;
11844 }
11845
The Android Open Source Project4df24232009-03-05 14:34:35 -080011846 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011847 // there are applications dependent on our services or providers, but
11848 // this gives us a baseline and makes sure we don't get into an
11849 // infinite recursion.
11850 app.adjSeq = mAdjSeq;
11851 app.curRawAdj = adj;
11852 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11853
11854 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11855 // If this process has active services running in it, we would
11856 // like to avoid killing it unless it would prevent the current
11857 // application from running.
11858 if (adj > hiddenAdj) {
11859 adj = hiddenAdj;
11860 }
11861 final long now = SystemClock.uptimeMillis();
11862 // This process is more important if the top activity is
11863 // bound to the service.
11864 Iterator jt = app.services.iterator();
11865 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11866 ServiceRecord s = (ServiceRecord)jt.next();
11867 if (s.startRequested) {
11868 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
11869 // This service has seen some activity within
11870 // recent memory, so we will keep its process ahead
11871 // of the background processes.
11872 if (adj > SECONDARY_SERVER_ADJ) {
11873 adj = SECONDARY_SERVER_ADJ;
11874 }
11875 } else {
11876 // This service has been inactive for too long, just
11877 // put it with the rest of the background processes.
11878 if (adj > hiddenAdj) {
11879 adj = hiddenAdj;
11880 }
11881 }
11882 }
11883 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
11884 Iterator<ConnectionRecord> kt
11885 = s.connections.values().iterator();
11886 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11887 // XXX should compute this based on the max of
11888 // all connected clients.
11889 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011890 if (cr.binding.client == app) {
11891 // Binding to ourself is not interesting.
11892 continue;
11893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011894 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
11895 ProcessRecord client = cr.binding.client;
11896 int myHiddenAdj = hiddenAdj;
11897 if (myHiddenAdj > client.hiddenAdj) {
11898 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
11899 myHiddenAdj = client.hiddenAdj;
11900 } else {
11901 myHiddenAdj = VISIBLE_APP_ADJ;
11902 }
11903 }
11904 int clientAdj = computeOomAdjLocked(
11905 client, myHiddenAdj, TOP_APP);
11906 if (adj > clientAdj) {
11907 adj = clientAdj > VISIBLE_APP_ADJ
11908 ? clientAdj : VISIBLE_APP_ADJ;
11909 }
11910 }
11911 HistoryRecord a = cr.activity;
11912 //if (a != null) {
11913 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
11914 //}
11915 if (a != null && adj > FOREGROUND_APP_ADJ &&
11916 (a.state == ActivityState.RESUMED
11917 || a.state == ActivityState.PAUSING)) {
11918 adj = FOREGROUND_APP_ADJ;
11919 }
11920 }
11921 }
11922 }
11923 }
11924
11925 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11926 // If this process has published any content providers, then
11927 // its adjustment makes it at least as important as any of the
11928 // processes using those providers, and no less important than
11929 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
11930 if (adj > CONTENT_PROVIDER_ADJ) {
11931 adj = CONTENT_PROVIDER_ADJ;
11932 }
11933 Iterator jt = app.pubProviders.values().iterator();
11934 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11935 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
11936 if (cpr.clients.size() != 0) {
11937 Iterator<ProcessRecord> kt = cpr.clients.iterator();
11938 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11939 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011940 if (client == app) {
11941 // Being our own client is not interesting.
11942 continue;
11943 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011944 int myHiddenAdj = hiddenAdj;
11945 if (myHiddenAdj > client.hiddenAdj) {
11946 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
11947 myHiddenAdj = client.hiddenAdj;
11948 } else {
11949 myHiddenAdj = FOREGROUND_APP_ADJ;
11950 }
11951 }
11952 int clientAdj = computeOomAdjLocked(
11953 client, myHiddenAdj, TOP_APP);
11954 if (adj > clientAdj) {
11955 adj = clientAdj > FOREGROUND_APP_ADJ
11956 ? clientAdj : FOREGROUND_APP_ADJ;
11957 }
11958 }
11959 }
11960 // If the provider has external (non-framework) process
11961 // dependencies, ensure that its adjustment is at least
11962 // FOREGROUND_APP_ADJ.
11963 if (cpr.externals != 0) {
11964 if (adj > FOREGROUND_APP_ADJ) {
11965 adj = FOREGROUND_APP_ADJ;
11966 }
11967 }
11968 }
11969 }
11970
11971 app.curRawAdj = adj;
11972
11973 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
11974 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
11975 if (adj > app.maxAdj) {
11976 adj = app.maxAdj;
11977 }
11978
11979 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070011980 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
11981 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
11982 : Process.THREAD_GROUP_DEFAULT;
11983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011984 return adj;
11985 }
11986
11987 /**
11988 * Ask a given process to GC right now.
11989 */
11990 final void performAppGcLocked(ProcessRecord app) {
11991 try {
11992 app.lastRequestedGc = SystemClock.uptimeMillis();
11993 if (app.thread != null) {
11994 app.thread.processInBackground();
11995 }
11996 } catch (Exception e) {
11997 // whatever.
11998 }
11999 }
12000
12001 /**
12002 * Returns true if things are idle enough to perform GCs.
12003 */
12004 private final boolean canGcNow() {
12005 return mParallelBroadcasts.size() == 0
12006 && mOrderedBroadcasts.size() == 0
12007 && (mSleeping || (mResumedActivity != null &&
12008 mResumedActivity.idle));
12009 }
12010
12011 /**
12012 * Perform GCs on all processes that are waiting for it, but only
12013 * if things are idle.
12014 */
12015 final void performAppGcsLocked() {
12016 final int N = mProcessesToGc.size();
12017 if (N <= 0) {
12018 return;
12019 }
12020 if (canGcNow()) {
12021 while (mProcessesToGc.size() > 0) {
12022 ProcessRecord proc = mProcessesToGc.remove(0);
12023 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12024 // To avoid spamming the system, we will GC processes one
12025 // at a time, waiting a few seconds between each.
12026 performAppGcLocked(proc);
12027 scheduleAppGcsLocked();
12028 return;
12029 }
12030 }
12031 }
12032 }
12033
12034 /**
12035 * If all looks good, perform GCs on all processes waiting for them.
12036 */
12037 final void performAppGcsIfAppropriateLocked() {
12038 if (canGcNow()) {
12039 performAppGcsLocked();
12040 return;
12041 }
12042 // Still not idle, wait some more.
12043 scheduleAppGcsLocked();
12044 }
12045
12046 /**
12047 * Schedule the execution of all pending app GCs.
12048 */
12049 final void scheduleAppGcsLocked() {
12050 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12051 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12052 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12053 }
12054
12055 /**
12056 * Set up to ask a process to GC itself. This will either do it
12057 * immediately, or put it on the list of processes to gc the next
12058 * time things are idle.
12059 */
12060 final void scheduleAppGcLocked(ProcessRecord app) {
12061 long now = SystemClock.uptimeMillis();
12062 if ((app.lastRequestedGc+5000) > now) {
12063 return;
12064 }
12065 if (!mProcessesToGc.contains(app)) {
12066 mProcessesToGc.add(app);
12067 scheduleAppGcsLocked();
12068 }
12069 }
12070
12071 private final boolean updateOomAdjLocked(
12072 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12073 app.hiddenAdj = hiddenAdj;
12074
12075 if (app.thread == null) {
12076 return true;
12077 }
12078
12079 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12080
12081 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12082 //Thread priority adjustment is disabled out to see
12083 //how the kernel scheduler performs.
12084 if (false) {
12085 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12086 app.setIsForeground = app.isForeground;
12087 if (app.pid != MY_PID) {
12088 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12089 + " to " + (app.isForeground
12090 ? Process.THREAD_PRIORITY_FOREGROUND
12091 : Process.THREAD_PRIORITY_DEFAULT));
12092 try {
12093 Process.setThreadPriority(app.pid, app.isForeground
12094 ? Process.THREAD_PRIORITY_FOREGROUND
12095 : Process.THREAD_PRIORITY_DEFAULT);
12096 } catch (RuntimeException e) {
12097 Log.w(TAG, "Exception trying to set priority of application thread "
12098 + app.pid, e);
12099 }
12100 }
12101 }
12102 }
12103 if (app.pid != 0 && app.pid != MY_PID) {
12104 if (app.curRawAdj != app.setRawAdj) {
12105 if (app.curRawAdj > FOREGROUND_APP_ADJ
12106 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12107 // If this app is transitioning from foreground to
12108 // non-foreground, have it do a gc.
12109 scheduleAppGcLocked(app);
12110 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12111 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12112 // Likewise do a gc when an app is moving in to the
12113 // background (such as a service stopping).
12114 scheduleAppGcLocked(app);
12115 }
12116 app.setRawAdj = app.curRawAdj;
12117 }
12118 if (adj != app.setAdj) {
12119 if (Process.setOomAdj(app.pid, adj)) {
12120 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12121 TAG, "Set app " + app.processName +
12122 " oom adj to " + adj);
12123 app.setAdj = adj;
12124 } else {
12125 return false;
12126 }
12127 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012128 if (app.setSchedGroup != app.curSchedGroup) {
12129 app.setSchedGroup = app.curSchedGroup;
12130 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12131 "Setting process group of " + app.processName
12132 + " to " + app.curSchedGroup);
12133 if (true) {
12134 try {
12135 Process.setProcessGroup(app.pid, app.curSchedGroup);
12136 } catch (Exception e) {
12137 Log.w(TAG, "Failed setting process group of " + app.pid
12138 + " to " + app.curSchedGroup);
12139 }
12140 }
12141 if (false) {
12142 if (app.thread != null) {
12143 try {
12144 app.thread.setSchedulingGroup(app.curSchedGroup);
12145 } catch (RemoteException e) {
12146 }
12147 }
12148 }
12149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012150 }
12151
12152 return true;
12153 }
12154
12155 private final HistoryRecord resumedAppLocked() {
12156 HistoryRecord resumedActivity = mResumedActivity;
12157 if (resumedActivity == null || resumedActivity.app == null) {
12158 resumedActivity = mPausingActivity;
12159 if (resumedActivity == null || resumedActivity.app == null) {
12160 resumedActivity = topRunningActivityLocked(null);
12161 }
12162 }
12163 return resumedActivity;
12164 }
12165
12166 private final boolean updateOomAdjLocked(ProcessRecord app) {
12167 final HistoryRecord TOP_ACT = resumedAppLocked();
12168 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12169 int curAdj = app.curAdj;
12170 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12171 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12172
12173 mAdjSeq++;
12174
12175 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12176 if (res) {
12177 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12178 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12179 if (nowHidden != wasHidden) {
12180 // Changed to/from hidden state, so apps after it in the LRU
12181 // list may also be changed.
12182 updateOomAdjLocked();
12183 }
12184 }
12185 return res;
12186 }
12187
12188 private final boolean updateOomAdjLocked() {
12189 boolean didOomAdj = true;
12190 final HistoryRecord TOP_ACT = resumedAppLocked();
12191 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12192
12193 if (false) {
12194 RuntimeException e = new RuntimeException();
12195 e.fillInStackTrace();
12196 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12197 }
12198
12199 mAdjSeq++;
12200
12201 // First try updating the OOM adjustment for each of the
12202 // application processes based on their current state.
12203 int i = mLRUProcesses.size();
12204 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12205 while (i > 0) {
12206 i--;
12207 ProcessRecord app = mLRUProcesses.get(i);
12208 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12209 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12210 && app.curAdj == curHiddenAdj) {
12211 curHiddenAdj++;
12212 }
12213 } else {
12214 didOomAdj = false;
12215 }
12216 }
12217
12218 // todo: for now pretend like OOM ADJ didn't work, because things
12219 // aren't behaving as expected on Linux -- it's not killing processes.
12220 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12221 }
12222
12223 private final void trimApplications() {
12224 synchronized (this) {
12225 int i;
12226
12227 // First remove any unused application processes whose package
12228 // has been removed.
12229 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12230 final ProcessRecord app = mRemovedProcesses.get(i);
12231 if (app.activities.size() == 0
12232 && app.curReceiver == null && app.services.size() == 0) {
12233 Log.i(
12234 TAG, "Exiting empty application process "
12235 + app.processName + " ("
12236 + (app.thread != null ? app.thread.asBinder() : null)
12237 + ")\n");
12238 if (app.pid > 0 && app.pid != MY_PID) {
12239 Process.killProcess(app.pid);
12240 } else {
12241 try {
12242 app.thread.scheduleExit();
12243 } catch (Exception e) {
12244 // Ignore exceptions.
12245 }
12246 }
12247 cleanUpApplicationRecordLocked(app, false, -1);
12248 mRemovedProcesses.remove(i);
12249
12250 if (app.persistent) {
12251 if (app.persistent) {
12252 addAppLocked(app.info);
12253 }
12254 }
12255 }
12256 }
12257
12258 // Now try updating the OOM adjustment for each of the
12259 // application processes based on their current state.
12260 // If the setOomAdj() API is not supported, then go with our
12261 // back-up plan...
12262 if (!updateOomAdjLocked()) {
12263
12264 // Count how many processes are running services.
12265 int numServiceProcs = 0;
12266 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12267 final ProcessRecord app = mLRUProcesses.get(i);
12268
12269 if (app.persistent || app.services.size() != 0
12270 || app.curReceiver != null
12271 || app.persistentActivities > 0) {
12272 // Don't count processes holding services against our
12273 // maximum process count.
12274 if (localLOGV) Log.v(
12275 TAG, "Not trimming app " + app + " with services: "
12276 + app.services);
12277 numServiceProcs++;
12278 }
12279 }
12280
12281 int curMaxProcs = mProcessLimit;
12282 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12283 if (mAlwaysFinishActivities) {
12284 curMaxProcs = 1;
12285 }
12286 curMaxProcs += numServiceProcs;
12287
12288 // Quit as many processes as we can to get down to the desired
12289 // process count. First remove any processes that no longer
12290 // have activites running in them.
12291 for ( i=0;
12292 i<mLRUProcesses.size()
12293 && mLRUProcesses.size() > curMaxProcs;
12294 i++) {
12295 final ProcessRecord app = mLRUProcesses.get(i);
12296 // Quit an application only if it is not currently
12297 // running any activities.
12298 if (!app.persistent && app.activities.size() == 0
12299 && app.curReceiver == null && app.services.size() == 0) {
12300 Log.i(
12301 TAG, "Exiting empty application process "
12302 + app.processName + " ("
12303 + (app.thread != null ? app.thread.asBinder() : null)
12304 + ")\n");
12305 if (app.pid > 0 && app.pid != MY_PID) {
12306 Process.killProcess(app.pid);
12307 } else {
12308 try {
12309 app.thread.scheduleExit();
12310 } catch (Exception e) {
12311 // Ignore exceptions.
12312 }
12313 }
12314 // todo: For now we assume the application is not buggy
12315 // or evil, and will quit as a result of our request.
12316 // Eventually we need to drive this off of the death
12317 // notification, and kill the process if it takes too long.
12318 cleanUpApplicationRecordLocked(app, false, i);
12319 i--;
12320 }
12321 }
12322
12323 // If we still have too many processes, now from the least
12324 // recently used process we start finishing activities.
12325 if (Config.LOGV) Log.v(
12326 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12327 " of " + curMaxProcs + " processes");
12328 for ( i=0;
12329 i<mLRUProcesses.size()
12330 && mLRUProcesses.size() > curMaxProcs;
12331 i++) {
12332 final ProcessRecord app = mLRUProcesses.get(i);
12333 // Quit the application only if we have a state saved for
12334 // all of its activities.
12335 boolean canQuit = !app.persistent && app.curReceiver == null
12336 && app.services.size() == 0
12337 && app.persistentActivities == 0;
12338 int NUMA = app.activities.size();
12339 int j;
12340 if (Config.LOGV) Log.v(
12341 TAG, "Looking to quit " + app.processName);
12342 for (j=0; j<NUMA && canQuit; j++) {
12343 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12344 if (Config.LOGV) Log.v(
12345 TAG, " " + r.intent.getComponent().flattenToShortString()
12346 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12347 canQuit = (r.haveState || !r.stateNotNeeded)
12348 && !r.visible && r.stopped;
12349 }
12350 if (canQuit) {
12351 // Finish all of the activities, and then the app itself.
12352 for (j=0; j<NUMA; j++) {
12353 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12354 if (!r.finishing) {
12355 destroyActivityLocked(r, false);
12356 }
12357 r.resultTo = null;
12358 }
12359 Log.i(TAG, "Exiting application process "
12360 + app.processName + " ("
12361 + (app.thread != null ? app.thread.asBinder() : null)
12362 + ")\n");
12363 if (app.pid > 0 && app.pid != MY_PID) {
12364 Process.killProcess(app.pid);
12365 } else {
12366 try {
12367 app.thread.scheduleExit();
12368 } catch (Exception e) {
12369 // Ignore exceptions.
12370 }
12371 }
12372 // todo: For now we assume the application is not buggy
12373 // or evil, and will quit as a result of our request.
12374 // Eventually we need to drive this off of the death
12375 // notification, and kill the process if it takes too long.
12376 cleanUpApplicationRecordLocked(app, false, i);
12377 i--;
12378 //dump();
12379 }
12380 }
12381
12382 }
12383
12384 int curMaxActivities = MAX_ACTIVITIES;
12385 if (mAlwaysFinishActivities) {
12386 curMaxActivities = 1;
12387 }
12388
12389 // Finally, if there are too many activities now running, try to
12390 // finish as many as we can to get back down to the limit.
12391 for ( i=0;
12392 i<mLRUActivities.size()
12393 && mLRUActivities.size() > curMaxActivities;
12394 i++) {
12395 final HistoryRecord r
12396 = (HistoryRecord)mLRUActivities.get(i);
12397
12398 // We can finish this one if we have its icicle saved and
12399 // it is not persistent.
12400 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12401 && r.stopped && !r.persistent && !r.finishing) {
12402 final int origSize = mLRUActivities.size();
12403 destroyActivityLocked(r, true);
12404
12405 // This will remove it from the LRU list, so keep
12406 // our index at the same value. Note that this check to
12407 // see if the size changes is just paranoia -- if
12408 // something unexpected happens, we don't want to end up
12409 // in an infinite loop.
12410 if (origSize > mLRUActivities.size()) {
12411 i--;
12412 }
12413 }
12414 }
12415 }
12416 }
12417
12418 /** This method sends the specified signal to each of the persistent apps */
12419 public void signalPersistentProcesses(int sig) throws RemoteException {
12420 if (sig != Process.SIGNAL_USR1) {
12421 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12422 }
12423
12424 synchronized (this) {
12425 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12426 != PackageManager.PERMISSION_GRANTED) {
12427 throw new SecurityException("Requires permission "
12428 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12429 }
12430
12431 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12432 ProcessRecord r = mLRUProcesses.get(i);
12433 if (r.thread != null && r.persistent) {
12434 Process.sendSignal(r.pid, sig);
12435 }
12436 }
12437 }
12438 }
12439
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012440 public boolean profileControl(String process, boolean start,
12441 String path) throws RemoteException {
12442
12443 synchronized (this) {
12444 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12445 // its own permission.
12446 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12447 != PackageManager.PERMISSION_GRANTED) {
12448 throw new SecurityException("Requires permission "
12449 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12450 }
12451
12452 ProcessRecord proc = null;
12453 try {
12454 int pid = Integer.parseInt(process);
12455 synchronized (mPidsSelfLocked) {
12456 proc = mPidsSelfLocked.get(pid);
12457 }
12458 } catch (NumberFormatException e) {
12459 }
12460
12461 if (proc == null) {
12462 HashMap<String, SparseArray<ProcessRecord>> all
12463 = mProcessNames.getMap();
12464 SparseArray<ProcessRecord> procs = all.get(process);
12465 if (procs != null && procs.size() > 0) {
12466 proc = procs.valueAt(0);
12467 }
12468 }
12469
12470 if (proc == null || proc.thread == null) {
12471 throw new IllegalArgumentException("Unknown process: " + process);
12472 }
12473
12474 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12475 if (isSecure) {
12476 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12477 throw new SecurityException("Process not debuggable: " + proc);
12478 }
12479 }
12480
12481 try {
12482 proc.thread.profilerControl(start, path);
12483 return true;
12484 } catch (RemoteException e) {
12485 throw new IllegalStateException("Process disappeared");
12486 }
12487 }
12488 }
12489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012490 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12491 public void monitor() {
12492 synchronized (this) { }
12493 }
12494}