blob: fb697056b82a9eb73bbb4a05b9a11a9df1d84485 [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;
Amith Yamasanieaeb6632009-06-03 15:16:10 -070065import android.os.BatteryStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.os.Binder;
67import android.os.Bundle;
68import android.os.Environment;
69import android.os.FileUtils;
70import android.os.Handler;
71import android.os.IBinder;
72import android.os.IPermissionController;
73import android.os.Looper;
74import android.os.Message;
75import android.os.Parcel;
76import android.os.ParcelFileDescriptor;
77import android.os.PowerManager;
78import android.os.Process;
79import android.os.RemoteException;
80import android.os.ServiceManager;
81import android.os.SystemClock;
82import android.os.SystemProperties;
83import android.provider.Checkin;
84import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020085import android.server.data.CrashData;
86import android.server.data.StackTraceElementData;
87import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.text.TextUtils;
89import android.util.Config;
90import android.util.EventLog;
91import android.util.Log;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020092import android.util.LogPrinter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093import android.util.PrintWriterPrinter;
94import android.util.SparseArray;
95import android.view.Gravity;
96import android.view.LayoutInflater;
97import android.view.View;
98import android.view.WindowManager;
99import android.view.WindowManagerPolicy;
100
101import dalvik.system.Zygote;
102
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200103import java.io.ByteArrayInputStream;
104import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105import java.io.File;
106import java.io.FileDescriptor;
107import java.io.FileInputStream;
108import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200109import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.PrintWriter;
111import java.lang.IllegalStateException;
112import java.lang.ref.WeakReference;
113import java.util.ArrayList;
114import java.util.HashMap;
115import java.util.HashSet;
116import java.util.Iterator;
117import java.util.List;
118import java.util.Locale;
119import java.util.Map;
120
121public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
122 static final String TAG = "ActivityManager";
123 static final boolean DEBUG = false;
124 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
125 static final boolean DEBUG_SWITCH = localLOGV || false;
126 static final boolean DEBUG_TASKS = localLOGV || false;
127 static final boolean DEBUG_PAUSE = localLOGV || false;
128 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
129 static final boolean DEBUG_TRANSITION = localLOGV || false;
130 static final boolean DEBUG_BROADCAST = localLOGV || false;
131 static final boolean DEBUG_SERVICE = localLOGV || false;
132 static final boolean DEBUG_VISBILITY = localLOGV || false;
133 static final boolean DEBUG_PROCESSES = localLOGV || false;
134 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700135 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700136 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean VALIDATE_TOKENS = false;
138 static final boolean SHOW_ACTIVITY_START_TIME = true;
139
140 // Control over CPU and battery monitoring.
141 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
142 static final boolean MONITOR_CPU_USAGE = true;
143 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
144 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
145 static final boolean MONITOR_THREAD_CPU_USAGE = false;
146
147 // Event log tags
148 static final int LOG_CONFIGURATION_CHANGED = 2719;
149 static final int LOG_CPU = 2721;
150 static final int LOG_AM_FINISH_ACTIVITY = 30001;
151 static final int LOG_TASK_TO_FRONT = 30002;
152 static final int LOG_AM_NEW_INTENT = 30003;
153 static final int LOG_AM_CREATE_TASK = 30004;
154 static final int LOG_AM_CREATE_ACTIVITY = 30005;
155 static final int LOG_AM_RESTART_ACTIVITY = 30006;
156 static final int LOG_AM_RESUME_ACTIVITY = 30007;
157 static final int LOG_ANR = 30008;
158 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
159 static final int LOG_AM_PROCESS_BOUND = 30010;
160 static final int LOG_AM_PROCESS_DIED = 30011;
161 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
162 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
163 static final int LOG_AM_PROCESS_START = 30014;
164 static final int LOG_AM_PROCESS_BAD = 30015;
165 static final int LOG_AM_PROCESS_GOOD = 30016;
166 static final int LOG_AM_LOW_MEMORY = 30017;
167 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
168 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
169 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
170 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
171 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
172 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
173 static final int LOG_AM_CREATE_SERVICE = 30030;
174 static final int LOG_AM_DESTROY_SERVICE = 30031;
175 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
176 static final int LOG_AM_DROP_PROCESS = 30033;
177 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
178 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
179 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
180
181 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
182 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
183
Dianne Hackborn1655be42009-05-08 14:29:01 -0700184 // The flags that are set for all calls we make to the package manager.
185 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700186 | PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 private static final String SYSTEM_SECURE = "ro.secure";
189
190 // This is the maximum number of application processes we would like
191 // to have running. Due to the asynchronous nature of things, we can
192 // temporarily go beyond this limit.
193 static final int MAX_PROCESSES = 2;
194
195 // Set to false to leave processes running indefinitely, relying on
196 // the kernel killing them as resources are required.
197 static final boolean ENFORCE_PROCESS_LIMIT = false;
198
199 // This is the maximum number of activities that we would like to have
200 // running at a given time.
201 static final int MAX_ACTIVITIES = 20;
202
203 // Maximum number of recent tasks that we can remember.
204 static final int MAX_RECENT_TASKS = 20;
205
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700206 // Amount of time after a call to stopAppSwitches() during which we will
207 // prevent further untrusted switches from happening.
208 static final long APP_SWITCH_DELAY_TIME = 5*1000;
209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 // How long until we reset a task when the user returns to it. Currently
211 // 30 minutes.
212 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
213
214 // Set to true to disable the icon that is shown while a new activity
215 // is being started.
216 static final boolean SHOW_APP_STARTING_ICON = true;
217
218 // How long we wait until giving up on the last activity to pause. This
219 // is short because it directly impacts the responsiveness of starting the
220 // next activity.
221 static final int PAUSE_TIMEOUT = 500;
222
223 /**
224 * How long we can hold the launch wake lock before giving up.
225 */
226 static final int LAUNCH_TIMEOUT = 10*1000;
227
228 // How long we wait for a launched process to attach to the activity manager
229 // before we decide it's never going to come up for real.
230 static final int PROC_START_TIMEOUT = 10*1000;
231
232 // How long we wait until giving up on the last activity telling us it
233 // is idle.
234 static final int IDLE_TIMEOUT = 10*1000;
235
236 // How long to wait after going idle before forcing apps to GC.
237 static final int GC_TIMEOUT = 5*1000;
238
239 // How long we wait until giving up on an activity telling us it has
240 // finished destroying itself.
241 static final int DESTROY_TIMEOUT = 10*1000;
242
243 // How long we allow a receiver to run before giving up on it.
244 static final int BROADCAST_TIMEOUT = 10*1000;
245
246 // How long we wait for a service to finish executing.
247 static final int SERVICE_TIMEOUT = 20*1000;
248
249 // How long a service needs to be running until restarting its process
250 // is no longer considered to be a relaunch of the service.
251 static final int SERVICE_RESTART_DURATION = 5*1000;
252
253 // Maximum amount of time for there to be no activity on a service before
254 // we consider it non-essential and allow its process to go on the
255 // LRU background list.
256 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
257
258 // How long we wait until we timeout on key dispatching.
259 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
260
261 // The minimum time we allow between crashes, for us to consider this
262 // application to be bad and stop and its services and reject broadcasts.
263 static final int MIN_CRASH_INTERVAL = 60*1000;
264
265 // How long we wait until we timeout on key dispatching during instrumentation.
266 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
267
268 // OOM adjustments for processes in various states:
269
270 // This is a process without anything currently running in it. Definitely
271 // the first to go! Value set in system/rootdir/init.rc on startup.
272 // This value is initalized in the constructor, careful when refering to
273 // this static variable externally.
274 static int EMPTY_APP_ADJ;
275
276 // This is a process with a content provider that does not have any clients
277 // attached to it. If it did have any clients, its adjustment would be the
278 // one for the highest-priority of those processes.
279 static int CONTENT_PROVIDER_ADJ;
280
281 // This is a process only hosting activities that are not visible,
282 // so it can be killed without any disruption. Value set in
283 // system/rootdir/init.rc on startup.
284 final int HIDDEN_APP_MAX_ADJ;
285 static int HIDDEN_APP_MIN_ADJ;
286
The Android Open Source Project4df24232009-03-05 14:34:35 -0800287 // This is a process holding the home application -- we want to try
288 // avoiding killing it, even if it would normally be in the background,
289 // because the user interacts with it so much.
290 final int HOME_APP_ADJ;
291
Christopher Tate6fa95972009-06-05 18:43:55 -0700292 // This is a process currently hosting a backup operation. Killing it
293 // is not entirely fatal but is generally a bad idea.
294 final int BACKUP_APP_ADJ;
295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 // This is a process holding a secondary server -- killing it will not
297 // have much of an impact as far as the user is concerned. Value set in
298 // system/rootdir/init.rc on startup.
299 final int SECONDARY_SERVER_ADJ;
300
301 // This is a process only hosting activities that are visible to the
302 // user, so we'd prefer they don't disappear. Value set in
303 // system/rootdir/init.rc on startup.
304 final int VISIBLE_APP_ADJ;
305
306 // This is the process running the current foreground app. We'd really
307 // rather not kill it! Value set in system/rootdir/init.rc on startup.
308 final int FOREGROUND_APP_ADJ;
309
310 // This is a process running a core server, such as telephony. Definitely
311 // don't want to kill it, but doing so is not completely fatal.
312 static final int CORE_SERVER_ADJ = -12;
313
314 // The system process runs at the default adjustment.
315 static final int SYSTEM_ADJ = -16;
316
317 // Memory pages are 4K.
318 static final int PAGE_SIZE = 4*1024;
319
320 // Corresponding memory levels for above adjustments.
321 final int EMPTY_APP_MEM;
322 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800323 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700324 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 final int SECONDARY_SERVER_MEM;
326 final int VISIBLE_APP_MEM;
327 final int FOREGROUND_APP_MEM;
328
329 final int MY_PID;
330
331 static final String[] EMPTY_STRING_ARRAY = new String[0];
332
333 enum ActivityState {
334 INITIALIZING,
335 RESUMED,
336 PAUSING,
337 PAUSED,
338 STOPPING,
339 STOPPED,
340 FINISHING,
341 DESTROYING,
342 DESTROYED
343 }
344
345 /**
346 * The back history of all previous (and possibly still
347 * running) activities. It contains HistoryRecord objects.
348 */
349 final ArrayList mHistory = new ArrayList();
350
351 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700352 * Description of a request to start a new activity, which has been held
353 * due to app switches being disabled.
354 */
355 class PendingActivityLaunch {
356 HistoryRecord r;
357 HistoryRecord sourceRecord;
358 Uri[] grantedUriPermissions;
359 int grantedMode;
360 boolean onlyIfNeeded;
361 }
362
363 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
364 = new ArrayList<PendingActivityLaunch>();
365
366 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 * List of all active broadcasts that are to be executed immediately
368 * (without waiting for another broadcast to finish). Currently this only
369 * contains broadcasts to registered receivers, to avoid spinning up
370 * a bunch of processes to execute IntentReceiver components.
371 */
372 final ArrayList<BroadcastRecord> mParallelBroadcasts
373 = new ArrayList<BroadcastRecord>();
374
375 /**
376 * List of all active broadcasts that are to be executed one at a time.
377 * The object at the top of the list is the currently activity broadcasts;
378 * those after it are waiting for the top to finish..
379 */
380 final ArrayList<BroadcastRecord> mOrderedBroadcasts
381 = new ArrayList<BroadcastRecord>();
382
383 /**
384 * Set when we current have a BROADCAST_INTENT_MSG in flight.
385 */
386 boolean mBroadcastsScheduled = false;
387
388 /**
389 * Set to indicate whether to issue an onUserLeaving callback when a
390 * newly launched activity is being brought in front of us.
391 */
392 boolean mUserLeaving = false;
393
394 /**
395 * When we are in the process of pausing an activity, before starting the
396 * next one, this variable holds the activity that is currently being paused.
397 */
398 HistoryRecord mPausingActivity = null;
399
400 /**
401 * Current activity that is resumed, or null if there is none.
402 */
403 HistoryRecord mResumedActivity = null;
404
405 /**
406 * Activity we have told the window manager to have key focus.
407 */
408 HistoryRecord mFocusedActivity = null;
409
410 /**
411 * This is the last activity that we put into the paused state. This is
412 * used to determine if we need to do an activity transition while sleeping,
413 * when we normally hold the top activity paused.
414 */
415 HistoryRecord mLastPausedActivity = null;
416
417 /**
418 * List of activities that are waiting for a new activity
419 * to become visible before completing whatever operation they are
420 * supposed to do.
421 */
422 final ArrayList mWaitingVisibleActivities = new ArrayList();
423
424 /**
425 * List of activities that are ready to be stopped, but waiting
426 * for the next activity to settle down before doing so. It contains
427 * HistoryRecord objects.
428 */
429 final ArrayList<HistoryRecord> mStoppingActivities
430 = new ArrayList<HistoryRecord>();
431
432 /**
433 * List of intents that were used to start the most recent tasks.
434 */
435 final ArrayList<TaskRecord> mRecentTasks
436 = new ArrayList<TaskRecord>();
437
438 /**
439 * List of activities that are ready to be finished, but waiting
440 * for the previous activity to settle down before doing so. It contains
441 * HistoryRecord objects.
442 */
443 final ArrayList mFinishingActivities = new ArrayList();
444
445 /**
446 * All of the applications we currently have running organized by name.
447 * The keys are strings of the application package name (as
448 * returned by the package manager), and the keys are ApplicationRecord
449 * objects.
450 */
451 final ProcessMap<ProcessRecord> mProcessNames
452 = new ProcessMap<ProcessRecord>();
453
454 /**
455 * The last time that various processes have crashed.
456 */
457 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
458
459 /**
460 * Set of applications that we consider to be bad, and will reject
461 * incoming broadcasts from (which the user has no control over).
462 * Processes are added to this set when they have crashed twice within
463 * a minimum amount of time; they are removed from it when they are
464 * later restarted (hopefully due to some user action). The value is the
465 * time it was added to the list.
466 */
467 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
468
469 /**
470 * All of the processes we currently have running organized by pid.
471 * The keys are the pid running the application.
472 *
473 * <p>NOTE: This object is protected by its own lock, NOT the global
474 * activity manager lock!
475 */
476 final SparseArray<ProcessRecord> mPidsSelfLocked
477 = new SparseArray<ProcessRecord>();
478
479 /**
480 * All of the processes that have been forced to be foreground. The key
481 * is the pid of the caller who requested it (we hold a death
482 * link on it).
483 */
484 abstract class ForegroundToken implements IBinder.DeathRecipient {
485 int pid;
486 IBinder token;
487 }
488 final SparseArray<ForegroundToken> mForegroundProcesses
489 = new SparseArray<ForegroundToken>();
490
491 /**
492 * List of records for processes that someone had tried to start before the
493 * system was ready. We don't start them at that point, but ensure they
494 * are started by the time booting is complete.
495 */
496 final ArrayList<ProcessRecord> mProcessesOnHold
497 = new ArrayList<ProcessRecord>();
498
499 /**
500 * List of records for processes that we have started and are waiting
501 * for them to call back. This is really only needed when running in
502 * single processes mode, in which case we do not have a unique pid for
503 * each process.
504 */
505 final ArrayList<ProcessRecord> mStartingProcesses
506 = new ArrayList<ProcessRecord>();
507
508 /**
509 * List of persistent applications that are in the process
510 * of being started.
511 */
512 final ArrayList<ProcessRecord> mPersistentStartingProcesses
513 = new ArrayList<ProcessRecord>();
514
515 /**
516 * Processes that are being forcibly torn down.
517 */
518 final ArrayList<ProcessRecord> mRemovedProcesses
519 = new ArrayList<ProcessRecord>();
520
521 /**
522 * List of running applications, sorted by recent usage.
523 * The first entry in the list is the least recently used.
524 * It contains ApplicationRecord objects. This list does NOT include
525 * any persistent application records (since we never want to exit them).
526 */
527 final ArrayList<ProcessRecord> mLRUProcesses
528 = new ArrayList<ProcessRecord>();
529
530 /**
531 * List of processes that should gc as soon as things are idle.
532 */
533 final ArrayList<ProcessRecord> mProcessesToGc
534 = new ArrayList<ProcessRecord>();
535
536 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800537 * This is the process holding what we currently consider to be
538 * the "home" activity.
539 */
540 private ProcessRecord mHomeProcess;
541
542 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 * List of running activities, sorted by recent usage.
544 * The first entry in the list is the least recently used.
545 * It contains HistoryRecord objects.
546 */
547 private final ArrayList mLRUActivities = new ArrayList();
548
549 /**
550 * Set of PendingResultRecord objects that are currently active.
551 */
552 final HashSet mPendingResultRecords = new HashSet();
553
554 /**
555 * Set of IntentSenderRecord objects that are currently active.
556 */
557 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
558 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
559
560 /**
561 * Intent broadcast that we have tried to start, but are
562 * waiting for its application's process to be created. We only
563 * need one (instead of a list) because we always process broadcasts
564 * one at a time, so no others can be started while waiting for this
565 * one.
566 */
567 BroadcastRecord mPendingBroadcast = null;
568
569 /**
570 * Keeps track of all IIntentReceivers that have been registered for
571 * broadcasts. Hash keys are the receiver IBinder, hash value is
572 * a ReceiverList.
573 */
574 final HashMap mRegisteredReceivers = new HashMap();
575
576 /**
577 * Resolver for broadcast intents to registered receivers.
578 * Holds BroadcastFilter (subclass of IntentFilter).
579 */
580 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
581 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
582 @Override
583 protected boolean allowFilterResult(
584 BroadcastFilter filter, List<BroadcastFilter> dest) {
585 IBinder target = filter.receiverList.receiver.asBinder();
586 for (int i=dest.size()-1; i>=0; i--) {
587 if (dest.get(i).receiverList.receiver.asBinder() == target) {
588 return false;
589 }
590 }
591 return true;
592 }
593 };
594
595 /**
596 * State of all active sticky broadcasts. Keys are the action of the
597 * sticky Intent, values are an ArrayList of all broadcasted intents with
598 * that action (which should usually be one).
599 */
600 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
601 new HashMap<String, ArrayList<Intent>>();
602
603 /**
604 * All currently running services.
605 */
606 final HashMap<ComponentName, ServiceRecord> mServices =
607 new HashMap<ComponentName, ServiceRecord>();
608
609 /**
610 * All currently running services indexed by the Intent used to start them.
611 */
612 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
613 new HashMap<Intent.FilterComparison, ServiceRecord>();
614
615 /**
616 * All currently bound service connections. Keys are the IBinder of
617 * the client's IServiceConnection.
618 */
619 final HashMap<IBinder, ConnectionRecord> mServiceConnections
620 = new HashMap<IBinder, ConnectionRecord>();
621
622 /**
623 * List of services that we have been asked to start,
624 * but haven't yet been able to. It is used to hold start requests
625 * while waiting for their corresponding application thread to get
626 * going.
627 */
628 final ArrayList<ServiceRecord> mPendingServices
629 = new ArrayList<ServiceRecord>();
630
631 /**
632 * List of services that are scheduled to restart following a crash.
633 */
634 final ArrayList<ServiceRecord> mRestartingServices
635 = new ArrayList<ServiceRecord>();
636
637 /**
638 * List of services that are in the process of being stopped.
639 */
640 final ArrayList<ServiceRecord> mStoppingServices
641 = new ArrayList<ServiceRecord>();
642
643 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700644 * Backup/restore process management
645 */
646 String mBackupAppName = null;
647 BackupRecord mBackupTarget = null;
648
649 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 * List of PendingThumbnailsRecord objects of clients who are still
651 * waiting to receive all of the thumbnails for a task.
652 */
653 final ArrayList mPendingThumbnails = new ArrayList();
654
655 /**
656 * List of HistoryRecord objects that have been finished and must
657 * still report back to a pending thumbnail receiver.
658 */
659 final ArrayList mCancelledThumbnails = new ArrayList();
660
661 /**
662 * All of the currently running global content providers. Keys are a
663 * string containing the provider name and values are a
664 * ContentProviderRecord object containing the data about it. Note
665 * that a single provider may be published under multiple names, so
666 * there may be multiple entries here for a single one in mProvidersByClass.
667 */
668 final HashMap mProvidersByName = new HashMap();
669
670 /**
671 * All of the currently running global content providers. Keys are a
672 * string containing the provider's implementation class and values are a
673 * ContentProviderRecord object containing the data about it.
674 */
675 final HashMap mProvidersByClass = new HashMap();
676
677 /**
678 * List of content providers who have clients waiting for them. The
679 * application is currently being launched and the provider will be
680 * removed from this list once it is published.
681 */
682 final ArrayList mLaunchingProviders = new ArrayList();
683
684 /**
685 * Global set of specific Uri permissions that have been granted.
686 */
687 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
688 = new SparseArray<HashMap<Uri, UriPermission>>();
689
690 /**
691 * Thread-local storage used to carry caller permissions over through
692 * indirect content-provider access.
693 * @see #ActivityManagerService.openContentUri()
694 */
695 private class Identity {
696 public int pid;
697 public int uid;
698
699 Identity(int _pid, int _uid) {
700 pid = _pid;
701 uid = _uid;
702 }
703 }
704 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
705
706 /**
707 * All information we have collected about the runtime performance of
708 * any user id that can impact battery performance.
709 */
710 final BatteryStatsService mBatteryStatsService;
711
712 /**
713 * information about component usage
714 */
715 final UsageStatsService mUsageStatsService;
716
717 /**
718 * Current configuration information. HistoryRecord objects are given
719 * a reference to this object to indicate which configuration they are
720 * currently running in, so this object must be kept immutable.
721 */
722 Configuration mConfiguration = new Configuration();
723
724 /**
725 * List of initialization arguments to pass to all processes when binding applications to them.
726 * For example, references to the commonly used services.
727 */
728 HashMap<String, IBinder> mAppBindArgs;
729
730 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700731 * Temporary to avoid allocations. Protected by main lock.
732 */
733 final StringBuilder mStringBuilder = new StringBuilder(256);
734
735 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 * Used to control how we initialize the service.
737 */
738 boolean mStartRunning = false;
739 ComponentName mTopComponent;
740 String mTopAction;
741 String mTopData;
742 boolean mSystemReady = false;
743 boolean mBooting = false;
744
745 Context mContext;
746
747 int mFactoryTest;
748
749 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700750 * The time at which we will allow normal application switches again,
751 * after a call to {@link #stopAppSwitches()}.
752 */
753 long mAppSwitchesAllowedTime;
754
755 /**
756 * This is set to true after the first switch after mAppSwitchesAllowedTime
757 * is set; any switches after that will clear the time.
758 */
759 boolean mDidAppSwitch;
760
761 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 * Set while we are wanting to sleep, to prevent any
763 * activities from being started/resumed.
764 */
765 boolean mSleeping = false;
766
767 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700768 * Set if we are shutting down the system, similar to sleeping.
769 */
770 boolean mShuttingDown = false;
771
772 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 * Set when the system is going to sleep, until we have
774 * successfully paused the current activity and released our wake lock.
775 * At that point the system is allowed to actually sleep.
776 */
777 PowerManager.WakeLock mGoingToSleep;
778
779 /**
780 * We don't want to allow the device to go to sleep while in the process
781 * of launching an activity. This is primarily to allow alarm intent
782 * receivers to launch an activity and get that to run before the device
783 * goes back to sleep.
784 */
785 PowerManager.WakeLock mLaunchingActivity;
786
787 /**
788 * Task identifier that activities are currently being started
789 * in. Incremented each time a new task is created.
790 * todo: Replace this with a TokenSpace class that generates non-repeating
791 * integers that won't wrap.
792 */
793 int mCurTask = 1;
794
795 /**
796 * Current sequence id for oom_adj computation traversal.
797 */
798 int mAdjSeq = 0;
799
800 /**
801 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
802 * is set, indicating the user wants processes started in such a way
803 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
804 * running in each process (thus no pre-initialized process, etc).
805 */
806 boolean mSimpleProcessManagement = false;
807
808 /**
809 * System monitoring: number of processes that died since the last
810 * N procs were started.
811 */
812 int[] mProcDeaths = new int[20];
813
814 String mDebugApp = null;
815 boolean mWaitForDebugger = false;
816 boolean mDebugTransient = false;
817 String mOrigDebugApp = null;
818 boolean mOrigWaitForDebugger = false;
819 boolean mAlwaysFinishActivities = false;
820 IActivityWatcher mWatcher = null;
821
822 /**
823 * Callback of last caller to {@link #requestPss}.
824 */
825 Runnable mRequestPssCallback;
826
827 /**
828 * Remaining processes for which we are waiting results from the last
829 * call to {@link #requestPss}.
830 */
831 final ArrayList<ProcessRecord> mRequestPssList
832 = new ArrayList<ProcessRecord>();
833
834 /**
835 * Runtime statistics collection thread. This object's lock is used to
836 * protect all related state.
837 */
838 final Thread mProcessStatsThread;
839
840 /**
841 * Used to collect process stats when showing not responding dialog.
842 * Protected by mProcessStatsThread.
843 */
844 final ProcessStats mProcessStats = new ProcessStats(
845 MONITOR_THREAD_CPU_USAGE);
846 long mLastCpuTime = 0;
847 long mLastWriteTime = 0;
848
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700849 long mInitialStartTime = 0;
850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 /**
852 * Set to true after the system has finished booting.
853 */
854 boolean mBooted = false;
855
856 int mProcessLimit = 0;
857
858 WindowManagerService mWindowManager;
859
860 static ActivityManagerService mSelf;
861 static ActivityThread mSystemThread;
862
863 private final class AppDeathRecipient implements IBinder.DeathRecipient {
864 final ProcessRecord mApp;
865 final int mPid;
866 final IApplicationThread mAppThread;
867
868 AppDeathRecipient(ProcessRecord app, int pid,
869 IApplicationThread thread) {
870 if (localLOGV) Log.v(
871 TAG, "New death recipient " + this
872 + " for thread " + thread.asBinder());
873 mApp = app;
874 mPid = pid;
875 mAppThread = thread;
876 }
877
878 public void binderDied() {
879 if (localLOGV) Log.v(
880 TAG, "Death received in " + this
881 + " for thread " + mAppThread.asBinder());
882 removeRequestedPss(mApp);
883 synchronized(ActivityManagerService.this) {
884 appDiedLocked(mApp, mPid, mAppThread);
885 }
886 }
887 }
888
889 static final int SHOW_ERROR_MSG = 1;
890 static final int SHOW_NOT_RESPONDING_MSG = 2;
891 static final int SHOW_FACTORY_ERROR_MSG = 3;
892 static final int UPDATE_CONFIGURATION_MSG = 4;
893 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
894 static final int WAIT_FOR_DEBUGGER_MSG = 6;
895 static final int BROADCAST_INTENT_MSG = 7;
896 static final int BROADCAST_TIMEOUT_MSG = 8;
897 static final int PAUSE_TIMEOUT_MSG = 9;
898 static final int IDLE_TIMEOUT_MSG = 10;
899 static final int IDLE_NOW_MSG = 11;
900 static final int SERVICE_TIMEOUT_MSG = 12;
901 static final int UPDATE_TIME_ZONE = 13;
902 static final int SHOW_UID_ERROR_MSG = 14;
903 static final int IM_FEELING_LUCKY_MSG = 15;
904 static final int LAUNCH_TIMEOUT_MSG = 16;
905 static final int DESTROY_TIMEOUT_MSG = 17;
906 static final int SERVICE_ERROR_MSG = 18;
907 static final int RESUME_TOP_ACTIVITY_MSG = 19;
908 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700909 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910
911 AlertDialog mUidAlert;
912
913 final Handler mHandler = new Handler() {
914 //public Handler() {
915 // if (localLOGV) Log.v(TAG, "Handler started!");
916 //}
917
918 public void handleMessage(Message msg) {
919 switch (msg.what) {
920 case SHOW_ERROR_MSG: {
921 HashMap data = (HashMap) msg.obj;
922 byte[] crashData = (byte[])data.get("crashData");
923 if (crashData != null) {
924 // This needs to be *un*synchronized to avoid deadlock.
925 ContentResolver resolver = mContext.getContentResolver();
926 Checkin.reportCrash(resolver, crashData);
927 }
928 synchronized (ActivityManagerService.this) {
929 ProcessRecord proc = (ProcessRecord)data.get("app");
930 if (proc != null && proc.crashDialog != null) {
931 Log.e(TAG, "App already has crash dialog: " + proc);
932 return;
933 }
934 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700935 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 Dialog d = new AppErrorDialog(
937 mContext, res, proc,
938 (Integer)data.get("flags"),
939 (String)data.get("shortMsg"),
940 (String)data.get("longMsg"));
941 d.show();
942 proc.crashDialog = d;
943 } else {
944 // The device is asleep, so just pretend that the user
945 // saw a crash dialog and hit "force quit".
946 res.set(0);
947 }
948 }
949 } break;
950 case SHOW_NOT_RESPONDING_MSG: {
951 synchronized (ActivityManagerService.this) {
952 HashMap data = (HashMap) msg.obj;
953 ProcessRecord proc = (ProcessRecord)data.get("app");
954 if (proc != null && proc.anrDialog != null) {
955 Log.e(TAG, "App already has anr dialog: " + proc);
956 return;
957 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800958
959 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
960 null, null, 0, null, null, null,
961 false, false, MY_PID, Process.SYSTEM_UID);
962
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
964 mContext, proc, (HistoryRecord)data.get("activity"));
965 d.show();
966 proc.anrDialog = d;
967 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700968
969 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 } break;
971 case SHOW_FACTORY_ERROR_MSG: {
972 Dialog d = new FactoryErrorDialog(
973 mContext, msg.getData().getCharSequence("msg"));
974 d.show();
975 enableScreenAfterBoot();
976 } break;
977 case UPDATE_CONFIGURATION_MSG: {
978 final ContentResolver resolver = mContext.getContentResolver();
979 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
980 } break;
981 case GC_BACKGROUND_PROCESSES_MSG: {
982 synchronized (ActivityManagerService.this) {
983 performAppGcsIfAppropriateLocked();
984 }
985 } break;
986 case WAIT_FOR_DEBUGGER_MSG: {
987 synchronized (ActivityManagerService.this) {
988 ProcessRecord app = (ProcessRecord)msg.obj;
989 if (msg.arg1 != 0) {
990 if (!app.waitedForDebugger) {
991 Dialog d = new AppWaitingForDebuggerDialog(
992 ActivityManagerService.this,
993 mContext, app);
994 app.waitDialog = d;
995 app.waitedForDebugger = true;
996 d.show();
997 }
998 } else {
999 if (app.waitDialog != null) {
1000 app.waitDialog.dismiss();
1001 app.waitDialog = null;
1002 }
1003 }
1004 }
1005 } break;
1006 case BROADCAST_INTENT_MSG: {
1007 if (DEBUG_BROADCAST) Log.v(
1008 TAG, "Received BROADCAST_INTENT_MSG");
1009 processNextBroadcast(true);
1010 } break;
1011 case BROADCAST_TIMEOUT_MSG: {
1012 broadcastTimeout();
1013 } break;
1014 case PAUSE_TIMEOUT_MSG: {
1015 IBinder token = (IBinder)msg.obj;
1016 // We don't at this point know if the activity is fullscreen,
1017 // so we need to be conservative and assume it isn't.
1018 Log.w(TAG, "Activity pause timeout for " + token);
1019 activityPaused(token, null, true);
1020 } break;
1021 case IDLE_TIMEOUT_MSG: {
1022 IBinder token = (IBinder)msg.obj;
1023 // We don't at this point know if the activity is fullscreen,
1024 // so we need to be conservative and assume it isn't.
1025 Log.w(TAG, "Activity idle timeout for " + token);
1026 activityIdleInternal(token, true);
1027 } break;
1028 case DESTROY_TIMEOUT_MSG: {
1029 IBinder token = (IBinder)msg.obj;
1030 // We don't at this point know if the activity is fullscreen,
1031 // so we need to be conservative and assume it isn't.
1032 Log.w(TAG, "Activity destroy timeout for " + token);
1033 activityDestroyed(token);
1034 } break;
1035 case IDLE_NOW_MSG: {
1036 IBinder token = (IBinder)msg.obj;
1037 activityIdle(token);
1038 } break;
1039 case SERVICE_TIMEOUT_MSG: {
1040 serviceTimeout((ProcessRecord)msg.obj);
1041 } break;
1042 case UPDATE_TIME_ZONE: {
1043 synchronized (ActivityManagerService.this) {
1044 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1045 ProcessRecord r = mLRUProcesses.get(i);
1046 if (r.thread != null) {
1047 try {
1048 r.thread.updateTimeZone();
1049 } catch (RemoteException ex) {
1050 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1051 }
1052 }
1053 }
1054 }
1055 break;
1056 }
1057 case SHOW_UID_ERROR_MSG: {
1058 // XXX This is a temporary dialog, no need to localize.
1059 AlertDialog d = new BaseErrorDialog(mContext);
1060 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1061 d.setCancelable(false);
1062 d.setTitle("System UIDs Inconsistent");
1063 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1064 d.setButton("I'm Feeling Lucky",
1065 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1066 mUidAlert = d;
1067 d.show();
1068 } break;
1069 case IM_FEELING_LUCKY_MSG: {
1070 if (mUidAlert != null) {
1071 mUidAlert.dismiss();
1072 mUidAlert = null;
1073 }
1074 } break;
1075 case LAUNCH_TIMEOUT_MSG: {
1076 synchronized (ActivityManagerService.this) {
1077 if (mLaunchingActivity.isHeld()) {
1078 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1079 mLaunchingActivity.release();
1080 }
1081 }
1082 } break;
1083 case SERVICE_ERROR_MSG: {
1084 ServiceRecord srv = (ServiceRecord)msg.obj;
1085 // This needs to be *un*synchronized to avoid deadlock.
1086 Checkin.logEvent(mContext.getContentResolver(),
1087 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1088 srv.name.toShortString());
1089 } break;
1090 case RESUME_TOP_ACTIVITY_MSG: {
1091 synchronized (ActivityManagerService.this) {
1092 resumeTopActivityLocked(null);
1093 }
1094 }
1095 case PROC_START_TIMEOUT_MSG: {
1096 ProcessRecord app = (ProcessRecord)msg.obj;
1097 synchronized (ActivityManagerService.this) {
1098 processStartTimedOutLocked(app);
1099 }
1100 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001101 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1102 synchronized (ActivityManagerService.this) {
1103 doPendingActivityLaunchesLocked(true);
1104 }
1105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 }
1107 }
1108 };
1109
1110 public static void setSystemProcess() {
1111 try {
1112 ActivityManagerService m = mSelf;
1113
1114 ServiceManager.addService("activity", m);
1115 ServiceManager.addService("meminfo", new MemBinder(m));
1116 if (MONITOR_CPU_USAGE) {
1117 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1118 }
1119 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1120 ServiceManager.addService("activity.services", new ServicesBinder(m));
1121 ServiceManager.addService("activity.senders", new SendersBinder(m));
1122 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1123 ServiceManager.addService("permission", new PermissionController(m));
1124
1125 ApplicationInfo info =
1126 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001127 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 synchronized (mSelf) {
1129 ProcessRecord app = mSelf.newProcessRecordLocked(
1130 mSystemThread.getApplicationThread(), info,
1131 info.processName);
1132 app.persistent = true;
1133 app.pid = Process.myPid();
1134 app.maxAdj = SYSTEM_ADJ;
1135 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1136 synchronized (mSelf.mPidsSelfLocked) {
1137 mSelf.mPidsSelfLocked.put(app.pid, app);
1138 }
1139 mSelf.updateLRUListLocked(app, true);
1140 }
1141 } catch (PackageManager.NameNotFoundException e) {
1142 throw new RuntimeException(
1143 "Unable to find android system package", e);
1144 }
1145 }
1146
1147 public void setWindowManager(WindowManagerService wm) {
1148 mWindowManager = wm;
1149 }
1150
1151 public static final Context main(int factoryTest) {
1152 AThread thr = new AThread();
1153 thr.start();
1154
1155 synchronized (thr) {
1156 while (thr.mService == null) {
1157 try {
1158 thr.wait();
1159 } catch (InterruptedException e) {
1160 }
1161 }
1162 }
1163
1164 ActivityManagerService m = thr.mService;
1165 mSelf = m;
1166 ActivityThread at = ActivityThread.systemMain();
1167 mSystemThread = at;
1168 Context context = at.getSystemContext();
1169 m.mContext = context;
1170 m.mFactoryTest = factoryTest;
1171 PowerManager pm =
1172 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1173 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1174 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1175 m.mLaunchingActivity.setReferenceCounted(false);
1176
1177 m.mBatteryStatsService.publish(context);
1178 m.mUsageStatsService.publish(context);
1179
1180 synchronized (thr) {
1181 thr.mReady = true;
1182 thr.notifyAll();
1183 }
1184
1185 m.startRunning(null, null, null, null);
1186
1187 return context;
1188 }
1189
1190 public static ActivityManagerService self() {
1191 return mSelf;
1192 }
1193
1194 static class AThread extends Thread {
1195 ActivityManagerService mService;
1196 boolean mReady = false;
1197
1198 public AThread() {
1199 super("ActivityManager");
1200 }
1201
1202 public void run() {
1203 Looper.prepare();
1204
1205 android.os.Process.setThreadPriority(
1206 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1207
1208 ActivityManagerService m = new ActivityManagerService();
1209
1210 synchronized (this) {
1211 mService = m;
1212 notifyAll();
1213 }
1214
1215 synchronized (this) {
1216 while (!mReady) {
1217 try {
1218 wait();
1219 } catch (InterruptedException e) {
1220 }
1221 }
1222 }
1223
1224 Looper.loop();
1225 }
1226 }
1227
1228 static class BroadcastsBinder extends Binder {
1229 ActivityManagerService mActivityManagerService;
1230 BroadcastsBinder(ActivityManagerService activityManagerService) {
1231 mActivityManagerService = activityManagerService;
1232 }
1233
1234 @Override
1235 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1236 mActivityManagerService.dumpBroadcasts(pw);
1237 }
1238 }
1239
1240 static class ServicesBinder extends Binder {
1241 ActivityManagerService mActivityManagerService;
1242 ServicesBinder(ActivityManagerService activityManagerService) {
1243 mActivityManagerService = activityManagerService;
1244 }
1245
1246 @Override
1247 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1248 mActivityManagerService.dumpServices(pw);
1249 }
1250 }
1251
1252 static class SendersBinder extends Binder {
1253 ActivityManagerService mActivityManagerService;
1254 SendersBinder(ActivityManagerService activityManagerService) {
1255 mActivityManagerService = activityManagerService;
1256 }
1257
1258 @Override
1259 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1260 mActivityManagerService.dumpSenders(pw);
1261 }
1262 }
1263
1264 static class ProvidersBinder extends Binder {
1265 ActivityManagerService mActivityManagerService;
1266 ProvidersBinder(ActivityManagerService activityManagerService) {
1267 mActivityManagerService = activityManagerService;
1268 }
1269
1270 @Override
1271 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1272 mActivityManagerService.dumpProviders(pw);
1273 }
1274 }
1275
1276 static class MemBinder extends Binder {
1277 ActivityManagerService mActivityManagerService;
1278 MemBinder(ActivityManagerService activityManagerService) {
1279 mActivityManagerService = activityManagerService;
1280 }
1281
1282 @Override
1283 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1284 ActivityManagerService service = mActivityManagerService;
1285 ArrayList<ProcessRecord> procs;
1286 synchronized (mActivityManagerService) {
1287 if (args != null && args.length > 0
1288 && args[0].charAt(0) != '-') {
1289 procs = new ArrayList<ProcessRecord>();
1290 int pid = -1;
1291 try {
1292 pid = Integer.parseInt(args[0]);
1293 } catch (NumberFormatException e) {
1294
1295 }
1296 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1297 ProcessRecord proc = service.mLRUProcesses.get(i);
1298 if (proc.pid == pid) {
1299 procs.add(proc);
1300 } else if (proc.processName.equals(args[0])) {
1301 procs.add(proc);
1302 }
1303 }
1304 if (procs.size() <= 0) {
1305 pw.println("No process found for: " + args[0]);
1306 return;
1307 }
1308 } else {
1309 procs = service.mLRUProcesses;
1310 }
1311 }
1312 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1313 }
1314 }
1315
1316 static class CpuBinder extends Binder {
1317 ActivityManagerService mActivityManagerService;
1318 CpuBinder(ActivityManagerService activityManagerService) {
1319 mActivityManagerService = activityManagerService;
1320 }
1321
1322 @Override
1323 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1324 synchronized (mActivityManagerService.mProcessStatsThread) {
1325 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1326 }
1327 }
1328 }
1329
1330 private ActivityManagerService() {
1331 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1332 if (v != null && Integer.getInteger(v) != 0) {
1333 mSimpleProcessManagement = true;
1334 }
1335 v = System.getenv("ANDROID_DEBUG_APP");
1336 if (v != null) {
1337 mSimpleProcessManagement = true;
1338 }
1339
1340 MY_PID = Process.myPid();
1341
1342 File dataDir = Environment.getDataDirectory();
1343 File systemDir = new File(dataDir, "system");
1344 systemDir.mkdirs();
1345 mBatteryStatsService = new BatteryStatsService(new File(
1346 systemDir, "batterystats.bin").toString());
1347 mBatteryStatsService.getActiveStatistics().readLocked();
1348 mBatteryStatsService.getActiveStatistics().writeLocked();
1349
1350 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001351 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352
1353 mConfiguration.makeDefault();
1354 mProcessStats.init();
1355
1356 // Add ourself to the Watchdog monitors.
1357 Watchdog.getInstance().addMonitor(this);
1358
1359 // These values are set in system/rootdir/init.rc on startup.
1360 FOREGROUND_APP_ADJ =
1361 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1362 VISIBLE_APP_ADJ =
1363 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1364 SECONDARY_SERVER_ADJ =
1365 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001366 BACKUP_APP_ADJ =
1367 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001368 HOME_APP_ADJ =
1369 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001370 HIDDEN_APP_MIN_ADJ =
1371 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1372 CONTENT_PROVIDER_ADJ =
1373 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1374 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1375 EMPTY_APP_ADJ =
1376 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1377 FOREGROUND_APP_MEM =
1378 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1379 VISIBLE_APP_MEM =
1380 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1381 SECONDARY_SERVER_MEM =
1382 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001383 BACKUP_APP_MEM =
1384 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001385 HOME_APP_MEM =
1386 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 HIDDEN_APP_MEM =
1388 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1389 EMPTY_APP_MEM =
1390 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1391
1392 mProcessStatsThread = new Thread("ProcessStats") {
1393 public void run() {
1394 while (true) {
1395 try {
1396 try {
1397 synchronized(this) {
1398 final long now = SystemClock.uptimeMillis();
1399 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1400 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1401 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1402 // + ", write delay=" + nextWriteDelay);
1403 if (nextWriteDelay < nextCpuDelay) {
1404 nextCpuDelay = nextWriteDelay;
1405 }
1406 if (nextCpuDelay > 0) {
1407 this.wait(nextCpuDelay);
1408 }
1409 }
1410 } catch (InterruptedException e) {
1411 }
1412
1413 updateCpuStatsNow();
1414 } catch (Exception e) {
1415 Log.e(TAG, "Unexpected exception collecting process stats", e);
1416 }
1417 }
1418 }
1419 };
1420 mProcessStatsThread.start();
1421 }
1422
1423 @Override
1424 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1425 throws RemoteException {
1426 try {
1427 return super.onTransact(code, data, reply, flags);
1428 } catch (RuntimeException e) {
1429 // The activity manager only throws security exceptions, so let's
1430 // log all others.
1431 if (!(e instanceof SecurityException)) {
1432 Log.e(TAG, "Activity Manager Crash", e);
1433 }
1434 throw e;
1435 }
1436 }
1437
1438 void updateCpuStats() {
1439 synchronized (mProcessStatsThread) {
1440 final long now = SystemClock.uptimeMillis();
1441 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1442 mProcessStatsThread.notify();
1443 }
1444 }
1445 }
1446
1447 void updateCpuStatsNow() {
1448 synchronized (mProcessStatsThread) {
1449 final long now = SystemClock.uptimeMillis();
1450 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 if (MONITOR_CPU_USAGE &&
1453 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1454 mLastCpuTime = now;
1455 haveNewCpuStats = true;
1456 mProcessStats.update();
1457 //Log.i(TAG, mProcessStats.printCurrentState());
1458 //Log.i(TAG, "Total CPU usage: "
1459 // + mProcessStats.getTotalCpuPercent() + "%");
1460
1461 // Log the cpu usage if the property is set.
1462 if ("true".equals(SystemProperties.get("events.cpu"))) {
1463 int user = mProcessStats.getLastUserTime();
1464 int system = mProcessStats.getLastSystemTime();
1465 int iowait = mProcessStats.getLastIoWaitTime();
1466 int irq = mProcessStats.getLastIrqTime();
1467 int softIrq = mProcessStats.getLastSoftIrqTime();
1468 int idle = mProcessStats.getLastIdleTime();
1469
1470 int total = user + system + iowait + irq + softIrq + idle;
1471 if (total == 0) total = 1;
1472
1473 EventLog.writeEvent(LOG_CPU,
1474 ((user+system+iowait+irq+softIrq) * 100) / total,
1475 (user * 100) / total,
1476 (system * 100) / total,
1477 (iowait * 100) / total,
1478 (irq * 100) / total,
1479 (softIrq * 100) / total);
1480 }
1481 }
1482
1483 synchronized(mBatteryStatsService.getActiveStatistics()) {
1484 synchronized(mPidsSelfLocked) {
1485 if (haveNewCpuStats) {
1486 if (mBatteryStatsService.isOnBattery()) {
1487 final int N = mProcessStats.countWorkingStats();
1488 for (int i=0; i<N; i++) {
1489 ProcessStats.Stats st
1490 = mProcessStats.getWorkingStats(i);
1491 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1492 if (pr != null) {
1493 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1494 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1495 }
1496 }
1497 }
1498 }
1499 }
1500
1501 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1502 mLastWriteTime = now;
1503 mBatteryStatsService.getActiveStatistics().writeLocked();
1504 }
1505 }
1506 }
1507 }
1508
1509 /**
1510 * Initialize the application bind args. These are passed to each
1511 * process when the bindApplication() IPC is sent to the process. They're
1512 * lazily setup to make sure the services are running when they're asked for.
1513 */
1514 private HashMap<String, IBinder> getCommonServicesLocked() {
1515 if (mAppBindArgs == null) {
1516 mAppBindArgs = new HashMap<String, IBinder>();
1517
1518 // Setup the application init args
1519 mAppBindArgs.put("package", ServiceManager.getService("package"));
1520 mAppBindArgs.put("window", ServiceManager.getService("window"));
1521 mAppBindArgs.put(Context.ALARM_SERVICE,
1522 ServiceManager.getService(Context.ALARM_SERVICE));
1523 }
1524 return mAppBindArgs;
1525 }
1526
1527 private final void setFocusedActivityLocked(HistoryRecord r) {
1528 if (mFocusedActivity != r) {
1529 mFocusedActivity = r;
1530 mWindowManager.setFocusedApp(r, true);
1531 }
1532 }
1533
1534 private final void updateLRUListLocked(ProcessRecord app,
1535 boolean oomAdj) {
1536 // put it on the LRU to keep track of when it should be exited.
1537 int lrui = mLRUProcesses.indexOf(app);
1538 if (lrui >= 0) mLRUProcesses.remove(lrui);
1539 mLRUProcesses.add(app);
1540 //Log.i(TAG, "Putting proc to front: " + app.processName);
1541 if (oomAdj) {
1542 updateOomAdjLocked();
1543 }
1544 }
1545
1546 private final boolean updateLRUListLocked(HistoryRecord r) {
1547 final boolean hadit = mLRUActivities.remove(r);
1548 mLRUActivities.add(r);
1549 return hadit;
1550 }
1551
1552 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1553 int i = mHistory.size()-1;
1554 while (i >= 0) {
1555 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1556 if (!r.finishing && r != notTop) {
1557 return r;
1558 }
1559 i--;
1560 }
1561 return null;
1562 }
1563
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001564 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1565 int i = mHistory.size()-1;
1566 while (i >= 0) {
1567 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1568 if (!r.finishing && !r.delayedResume && r != notTop) {
1569 return r;
1570 }
1571 i--;
1572 }
1573 return null;
1574 }
1575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 /**
1577 * This is a simplified version of topRunningActivityLocked that provides a number of
1578 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1579 *
1580 * @param token If non-null, any history records matching this token will be skipped.
1581 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1582 *
1583 * @return Returns the HistoryRecord of the next activity on the stack.
1584 */
1585 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1586 int i = mHistory.size()-1;
1587 while (i >= 0) {
1588 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1589 // Note: the taskId check depends on real taskId fields being non-zero
1590 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1591 return r;
1592 }
1593 i--;
1594 }
1595 return null;
1596 }
1597
1598 private final ProcessRecord getProcessRecordLocked(
1599 String processName, int uid) {
1600 if (uid == Process.SYSTEM_UID) {
1601 // The system gets to run in any process. If there are multiple
1602 // processes with the same uid, just pick the first (this
1603 // should never happen).
1604 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1605 processName);
1606 return procs != null ? procs.valueAt(0) : null;
1607 }
1608 ProcessRecord proc = mProcessNames.get(processName, uid);
1609 return proc;
1610 }
1611
1612 private boolean isNextTransitionForward() {
1613 int transit = mWindowManager.getPendingAppTransition();
1614 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1615 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1616 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1617 }
1618
1619 private final boolean realStartActivityLocked(HistoryRecord r,
1620 ProcessRecord app, boolean andResume, boolean checkConfig)
1621 throws RemoteException {
1622
1623 r.startFreezingScreenLocked(app, 0);
1624 mWindowManager.setAppVisibility(r, true);
1625
1626 // Have the window manager re-evaluate the orientation of
1627 // the screen based on the new activity order. Note that
1628 // as a result of this, it can call back into the activity
1629 // manager with a new orientation. We don't care about that,
1630 // because the activity is not currently running so we are
1631 // just restarting it anyway.
1632 if (checkConfig) {
1633 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001634 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 r.mayFreezeScreenLocked(app) ? r : null);
1636 updateConfigurationLocked(config, r);
1637 }
1638
1639 r.app = app;
1640
1641 if (localLOGV) Log.v(TAG, "Launching: " + r);
1642
1643 int idx = app.activities.indexOf(r);
1644 if (idx < 0) {
1645 app.activities.add(r);
1646 }
1647 updateLRUListLocked(app, true);
1648
1649 try {
1650 if (app.thread == null) {
1651 throw new RemoteException();
1652 }
1653 List<ResultInfo> results = null;
1654 List<Intent> newIntents = null;
1655 if (andResume) {
1656 results = r.results;
1657 newIntents = r.newIntents;
1658 }
1659 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1660 + " icicle=" + r.icicle
1661 + " with results=" + results + " newIntents=" + newIntents
1662 + " andResume=" + andResume);
1663 if (andResume) {
1664 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1665 System.identityHashCode(r),
1666 r.task.taskId, r.shortComponentName);
1667 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001668 if (r.isHomeActivity) {
1669 mHomeProcess = app;
1670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1672 r.info, r.icicle, results, newIntents, !andResume,
1673 isNextTransitionForward());
1674 // Update usage stats for launched activity
1675 updateUsageStats(r, true);
1676 } catch (RemoteException e) {
1677 if (r.launchFailed) {
1678 // This is the second time we failed -- finish activity
1679 // and give up.
1680 Log.e(TAG, "Second failure launching "
1681 + r.intent.getComponent().flattenToShortString()
1682 + ", giving up", e);
1683 appDiedLocked(app, app.pid, app.thread);
1684 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1685 "2nd-crash");
1686 return false;
1687 }
1688
1689 // This is the first time we failed -- restart process and
1690 // retry.
1691 app.activities.remove(r);
1692 throw e;
1693 }
1694
1695 r.launchFailed = false;
1696 if (updateLRUListLocked(r)) {
1697 Log.w(TAG, "Activity " + r
1698 + " being launched, but already in LRU list");
1699 }
1700
1701 if (andResume) {
1702 // As part of the process of launching, ActivityThread also performs
1703 // a resume.
1704 r.state = ActivityState.RESUMED;
1705 r.icicle = null;
1706 r.haveState = false;
1707 r.stopped = false;
1708 mResumedActivity = r;
1709 r.task.touchActiveTime();
1710 completeResumeLocked(r);
1711 pauseIfSleepingLocked();
1712 } else {
1713 // This activity is not starting in the resumed state... which
1714 // should look like we asked it to pause+stop (but remain visible),
1715 // and it has done so and reported back the current icicle and
1716 // other state.
1717 r.state = ActivityState.STOPPED;
1718 r.stopped = true;
1719 }
1720
1721 return true;
1722 }
1723
1724 private final void startSpecificActivityLocked(HistoryRecord r,
1725 boolean andResume, boolean checkConfig) {
1726 // Is this activity's application already running?
1727 ProcessRecord app = getProcessRecordLocked(r.processName,
1728 r.info.applicationInfo.uid);
1729
1730 if (r.startTime == 0) {
1731 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001732 if (mInitialStartTime == 0) {
1733 mInitialStartTime = r.startTime;
1734 }
1735 } else if (mInitialStartTime == 0) {
1736 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 }
1738
1739 if (app != null && app.thread != null) {
1740 try {
1741 realStartActivityLocked(r, app, andResume, checkConfig);
1742 return;
1743 } catch (RemoteException e) {
1744 Log.w(TAG, "Exception when starting activity "
1745 + r.intent.getComponent().flattenToShortString(), e);
1746 }
1747
1748 // If a dead object exception was thrown -- fall through to
1749 // restart the application.
1750 }
1751
1752 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1753 "activity", r.intent.getComponent());
1754 }
1755
1756 private final ProcessRecord startProcessLocked(String processName,
1757 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1758 String hostingType, ComponentName hostingName) {
1759 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1760 // We don't have to do anything more if:
1761 // (1) There is an existing application record; and
1762 // (2) The caller doesn't think it is dead, OR there is no thread
1763 // object attached to it so we know it couldn't have crashed; and
1764 // (3) There is a pid assigned to it, so it is either starting or
1765 // already running.
1766 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1767 + " app=" + app + " knownToBeDead=" + knownToBeDead
1768 + " thread=" + (app != null ? app.thread : null)
1769 + " pid=" + (app != null ? app.pid : -1));
1770 if (app != null &&
1771 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1772 return app;
1773 }
1774
1775 String hostingNameStr = hostingName != null
1776 ? hostingName.flattenToShortString() : null;
1777
1778 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1779 // If we are in the background, then check to see if this process
1780 // is bad. If so, we will just silently fail.
1781 if (mBadProcesses.get(info.processName, info.uid) != null) {
1782 return null;
1783 }
1784 } else {
1785 // When the user is explicitly starting a process, then clear its
1786 // crash count so that we won't make it bad until they see at
1787 // least one crash dialog again, and make the process good again
1788 // if it had been bad.
1789 mProcessCrashTimes.remove(info.processName, info.uid);
1790 if (mBadProcesses.get(info.processName, info.uid) != null) {
1791 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1792 info.processName);
1793 mBadProcesses.remove(info.processName, info.uid);
1794 if (app != null) {
1795 app.bad = false;
1796 }
1797 }
1798 }
1799
1800 if (app == null) {
1801 app = newProcessRecordLocked(null, info, processName);
1802 mProcessNames.put(processName, info.uid, app);
1803 } else {
1804 // If this is a new package in the process, add the package to the list
1805 app.addPackage(info.packageName);
1806 }
1807
1808 // If the system is not ready yet, then hold off on starting this
1809 // process until it is.
1810 if (!mSystemReady
1811 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1812 if (!mProcessesOnHold.contains(app)) {
1813 mProcessesOnHold.add(app);
1814 }
1815 return app;
1816 }
1817
1818 startProcessLocked(app, hostingType, hostingNameStr);
1819 return (app.pid != 0) ? app : null;
1820 }
1821
1822 private final void startProcessLocked(ProcessRecord app,
1823 String hostingType, String hostingNameStr) {
1824 if (app.pid > 0 && app.pid != MY_PID) {
1825 synchronized (mPidsSelfLocked) {
1826 mPidsSelfLocked.remove(app.pid);
1827 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1828 }
1829 app.pid = 0;
1830 }
1831
1832 mProcessesOnHold.remove(app);
1833
1834 updateCpuStats();
1835
1836 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1837 mProcDeaths[0] = 0;
1838
1839 try {
1840 int uid = app.info.uid;
1841 int[] gids = null;
1842 try {
1843 gids = mContext.getPackageManager().getPackageGids(
1844 app.info.packageName);
1845 } catch (PackageManager.NameNotFoundException e) {
1846 Log.w(TAG, "Unable to retrieve gids", e);
1847 }
1848 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1849 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1850 && mTopComponent != null
1851 && app.processName.equals(mTopComponent.getPackageName())) {
1852 uid = 0;
1853 }
1854 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1855 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1856 uid = 0;
1857 }
1858 }
1859 int debugFlags = 0;
1860 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1861 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1862 }
1863 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1864 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1865 }
1866 if ("1".equals(SystemProperties.get("debug.assert"))) {
1867 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1868 }
1869 int pid = Process.start("android.app.ActivityThread",
1870 mSimpleProcessManagement ? app.processName : null, uid, uid,
1871 gids, debugFlags, null);
1872 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1873 synchronized (bs) {
1874 if (bs.isOnBattery()) {
1875 app.batteryStats.incStartsLocked();
1876 }
1877 }
1878
1879 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1880 app.processName, hostingType,
1881 hostingNameStr != null ? hostingNameStr : "");
1882
1883 if (app.persistent) {
1884 Watchdog.getInstance().processStarted(app, app.processName, pid);
1885 }
1886
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001887 StringBuilder buf = mStringBuilder;
1888 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 buf.append("Start proc ");
1890 buf.append(app.processName);
1891 buf.append(" for ");
1892 buf.append(hostingType);
1893 if (hostingNameStr != null) {
1894 buf.append(" ");
1895 buf.append(hostingNameStr);
1896 }
1897 buf.append(": pid=");
1898 buf.append(pid);
1899 buf.append(" uid=");
1900 buf.append(uid);
1901 buf.append(" gids={");
1902 if (gids != null) {
1903 for (int gi=0; gi<gids.length; gi++) {
1904 if (gi != 0) buf.append(", ");
1905 buf.append(gids[gi]);
1906
1907 }
1908 }
1909 buf.append("}");
1910 Log.i(TAG, buf.toString());
1911 if (pid == 0 || pid == MY_PID) {
1912 // Processes are being emulated with threads.
1913 app.pid = MY_PID;
1914 app.removed = false;
1915 mStartingProcesses.add(app);
1916 } else if (pid > 0) {
1917 app.pid = pid;
1918 app.removed = false;
1919 synchronized (mPidsSelfLocked) {
1920 this.mPidsSelfLocked.put(pid, app);
1921 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1922 msg.obj = app;
1923 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1924 }
1925 } else {
1926 app.pid = 0;
1927 RuntimeException e = new RuntimeException(
1928 "Failure starting process " + app.processName
1929 + ": returned pid=" + pid);
1930 Log.e(TAG, e.getMessage(), e);
1931 }
1932 } catch (RuntimeException e) {
1933 // XXX do better error recovery.
1934 app.pid = 0;
1935 Log.e(TAG, "Failure starting process " + app.processName, e);
1936 }
1937 }
1938
1939 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1940 if (mPausingActivity != null) {
1941 RuntimeException e = new RuntimeException();
1942 Log.e(TAG, "Trying to pause when pause is already pending for "
1943 + mPausingActivity, e);
1944 }
1945 HistoryRecord prev = mResumedActivity;
1946 if (prev == null) {
1947 RuntimeException e = new RuntimeException();
1948 Log.e(TAG, "Trying to pause when nothing is resumed", e);
1949 resumeTopActivityLocked(null);
1950 return;
1951 }
1952 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
1953 mResumedActivity = null;
1954 mPausingActivity = prev;
1955 mLastPausedActivity = prev;
1956 prev.state = ActivityState.PAUSING;
1957 prev.task.touchActiveTime();
1958
1959 updateCpuStats();
1960
1961 if (prev.app != null && prev.app.thread != null) {
1962 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
1963 try {
1964 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
1965 System.identityHashCode(prev),
1966 prev.shortComponentName);
1967 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
1968 prev.configChangeFlags);
1969 updateUsageStats(prev, false);
1970 } catch (Exception e) {
1971 // Ignore exception, if process died other code will cleanup.
1972 Log.w(TAG, "Exception thrown during pause", e);
1973 mPausingActivity = null;
1974 mLastPausedActivity = null;
1975 }
1976 } else {
1977 mPausingActivity = null;
1978 mLastPausedActivity = null;
1979 }
1980
1981 // If we are not going to sleep, we want to ensure the device is
1982 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07001983 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 mLaunchingActivity.acquire();
1985 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
1986 // To be safe, don't allow the wake lock to be held for too long.
1987 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1988 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
1989 }
1990 }
1991
1992
1993 if (mPausingActivity != null) {
1994 // Have the window manager pause its key dispatching until the new
1995 // activity has started. If we're pausing the activity just because
1996 // the screen is being turned off and the UI is sleeping, don't interrupt
1997 // key dispatch; the same activity will pick it up again on wakeup.
1998 if (!uiSleeping) {
1999 prev.pauseKeyDispatchingLocked();
2000 } else {
2001 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2002 }
2003
2004 // Schedule a pause timeout in case the app doesn't respond.
2005 // We don't give it much time because this directly impacts the
2006 // responsiveness seen by the user.
2007 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2008 msg.obj = prev;
2009 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2010 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2011 } else {
2012 // This activity failed to schedule the
2013 // pause, so just treat it as being paused now.
2014 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2015 resumeTopActivityLocked(null);
2016 }
2017 }
2018
2019 private final void completePauseLocked() {
2020 HistoryRecord prev = mPausingActivity;
2021 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2022
2023 if (prev != null) {
2024 if (prev.finishing) {
2025 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2026 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2027 } else if (prev.app != null) {
2028 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2029 if (prev.waitingVisible) {
2030 prev.waitingVisible = false;
2031 mWaitingVisibleActivities.remove(prev);
2032 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2033 TAG, "Complete pause, no longer waiting: " + prev);
2034 }
2035 if (prev.configDestroy) {
2036 // The previous is being paused because the configuration
2037 // is changing, which means it is actually stopping...
2038 // To juggle the fact that we are also starting a new
2039 // instance right now, we need to first completely stop
2040 // the current instance before starting the new one.
2041 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2042 destroyActivityLocked(prev, true);
2043 } else {
2044 mStoppingActivities.add(prev);
2045 if (mStoppingActivities.size() > 3) {
2046 // If we already have a few activities waiting to stop,
2047 // then give up on things going idle and start clearing
2048 // them out.
2049 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2050 Message msg = Message.obtain();
2051 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2052 mHandler.sendMessage(msg);
2053 }
2054 }
2055 } else {
2056 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2057 prev = null;
2058 }
2059 mPausingActivity = null;
2060 }
2061
Dianne Hackborn55280a92009-05-07 15:53:46 -07002062 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002063 resumeTopActivityLocked(prev);
2064 } else {
2065 if (mGoingToSleep.isHeld()) {
2066 mGoingToSleep.release();
2067 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002068 if (mShuttingDown) {
2069 notifyAll();
2070 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 }
2072
2073 if (prev != null) {
2074 prev.resumeKeyDispatchingLocked();
2075 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002076
2077 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2078 long diff = 0;
2079 synchronized (mProcessStatsThread) {
2080 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2081 }
2082 if (diff > 0) {
2083 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2084 synchronized (bsi) {
2085 BatteryStatsImpl.Uid.Proc ps =
2086 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2087 prev.info.packageName);
2088 if (ps != null) {
2089 ps.addForegroundTimeLocked(diff);
2090 }
2091 }
2092 }
2093 }
2094 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 }
2096
2097 /**
2098 * Once we know that we have asked an application to put an activity in
2099 * the resumed state (either by launching it or explicitly telling it),
2100 * this function updates the rest of our state to match that fact.
2101 */
2102 private final void completeResumeLocked(HistoryRecord next) {
2103 next.idle = false;
2104 next.results = null;
2105 next.newIntents = null;
2106
2107 // schedule an idle timeout in case the app doesn't do it for us.
2108 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2109 msg.obj = next;
2110 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2111
2112 if (false) {
2113 // The activity was never told to pause, so just keep
2114 // things going as-is. To maintain our own state,
2115 // we need to emulate it coming back and saying it is
2116 // idle.
2117 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2118 msg.obj = next;
2119 mHandler.sendMessage(msg);
2120 }
2121
2122 next.thumbnail = null;
2123 setFocusedActivityLocked(next);
2124 next.resumeKeyDispatchingLocked();
2125 ensureActivitiesVisibleLocked(null, 0);
2126 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002127
2128 // Mark the point when the activity is resuming
2129 // TODO: To be more accurate, the mark should be before the onCreate,
2130 // not after the onResume. But for subsequent starts, onResume is fine.
2131 if (next.app != null) {
2132 synchronized (mProcessStatsThread) {
2133 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2134 }
2135 } else {
2136 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2137 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 }
2139
2140 /**
2141 * Make sure that all activities that need to be visible (that is, they
2142 * currently can be seen by the user) actually are.
2143 */
2144 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2145 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2146 if (DEBUG_VISBILITY) Log.v(
2147 TAG, "ensureActivitiesVisible behind " + top
2148 + " configChanges=0x" + Integer.toHexString(configChanges));
2149
2150 // If the top activity is not fullscreen, then we need to
2151 // make sure any activities under it are now visible.
2152 final int count = mHistory.size();
2153 int i = count-1;
2154 while (mHistory.get(i) != top) {
2155 i--;
2156 }
2157 HistoryRecord r;
2158 boolean behindFullscreen = false;
2159 for (; i>=0; i--) {
2160 r = (HistoryRecord)mHistory.get(i);
2161 if (DEBUG_VISBILITY) Log.v(
2162 TAG, "Make visible? " + r + " finishing=" + r.finishing
2163 + " state=" + r.state);
2164 if (r.finishing) {
2165 continue;
2166 }
2167
2168 final boolean doThisProcess = onlyThisProcess == null
2169 || onlyThisProcess.equals(r.processName);
2170
2171 // First: if this is not the current activity being started, make
2172 // sure it matches the current configuration.
2173 if (r != starting && doThisProcess) {
2174 ensureActivityConfigurationLocked(r, 0);
2175 }
2176
2177 if (r.app == null || r.app.thread == null) {
2178 if (onlyThisProcess == null
2179 || onlyThisProcess.equals(r.processName)) {
2180 // This activity needs to be visible, but isn't even
2181 // running... get it started, but don't resume it
2182 // at this point.
2183 if (DEBUG_VISBILITY) Log.v(
2184 TAG, "Start and freeze screen for " + r);
2185 if (r != starting) {
2186 r.startFreezingScreenLocked(r.app, configChanges);
2187 }
2188 if (!r.visible) {
2189 if (DEBUG_VISBILITY) Log.v(
2190 TAG, "Starting and making visible: " + r);
2191 mWindowManager.setAppVisibility(r, true);
2192 }
2193 if (r != starting) {
2194 startSpecificActivityLocked(r, false, false);
2195 }
2196 }
2197
2198 } else if (r.visible) {
2199 // If this activity is already visible, then there is nothing
2200 // else to do here.
2201 if (DEBUG_VISBILITY) Log.v(
2202 TAG, "Skipping: already visible at " + r);
2203 r.stopFreezingScreenLocked(false);
2204
2205 } else if (onlyThisProcess == null) {
2206 // This activity is not currently visible, but is running.
2207 // Tell it to become visible.
2208 r.visible = true;
2209 if (r.state != ActivityState.RESUMED && r != starting) {
2210 // If this activity is paused, tell it
2211 // to now show its window.
2212 if (DEBUG_VISBILITY) Log.v(
2213 TAG, "Making visible and scheduling visibility: " + r);
2214 try {
2215 mWindowManager.setAppVisibility(r, true);
2216 r.app.thread.scheduleWindowVisibility(r, true);
2217 r.stopFreezingScreenLocked(false);
2218 } catch (Exception e) {
2219 // Just skip on any failure; we'll make it
2220 // visible when it next restarts.
2221 Log.w(TAG, "Exception thrown making visibile: "
2222 + r.intent.getComponent(), e);
2223 }
2224 }
2225 }
2226
2227 // Aggregate current change flags.
2228 configChanges |= r.configChangeFlags;
2229
2230 if (r.fullscreen) {
2231 // At this point, nothing else needs to be shown
2232 if (DEBUG_VISBILITY) Log.v(
2233 TAG, "Stopping: fullscreen at " + r);
2234 behindFullscreen = true;
2235 i--;
2236 break;
2237 }
2238 }
2239
2240 // Now for any activities that aren't visible to the user, make
2241 // sure they no longer are keeping the screen frozen.
2242 while (i >= 0) {
2243 r = (HistoryRecord)mHistory.get(i);
2244 if (DEBUG_VISBILITY) Log.v(
2245 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2246 + " state=" + r.state
2247 + " behindFullscreen=" + behindFullscreen);
2248 if (!r.finishing) {
2249 if (behindFullscreen) {
2250 if (r.visible) {
2251 if (DEBUG_VISBILITY) Log.v(
2252 TAG, "Making invisible: " + r);
2253 r.visible = false;
2254 try {
2255 mWindowManager.setAppVisibility(r, false);
2256 if ((r.state == ActivityState.STOPPING
2257 || r.state == ActivityState.STOPPED)
2258 && r.app != null && r.app.thread != null) {
2259 if (DEBUG_VISBILITY) Log.v(
2260 TAG, "Scheduling invisibility: " + r);
2261 r.app.thread.scheduleWindowVisibility(r, false);
2262 }
2263 } catch (Exception e) {
2264 // Just skip on any failure; we'll make it
2265 // visible when it next restarts.
2266 Log.w(TAG, "Exception thrown making hidden: "
2267 + r.intent.getComponent(), e);
2268 }
2269 } else {
2270 if (DEBUG_VISBILITY) Log.v(
2271 TAG, "Already invisible: " + r);
2272 }
2273 } else if (r.fullscreen) {
2274 if (DEBUG_VISBILITY) Log.v(
2275 TAG, "Now behindFullscreen: " + r);
2276 behindFullscreen = true;
2277 }
2278 }
2279 i--;
2280 }
2281 }
2282
2283 /**
2284 * Version of ensureActivitiesVisible that can easily be called anywhere.
2285 */
2286 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2287 int configChanges) {
2288 HistoryRecord r = topRunningActivityLocked(null);
2289 if (r != null) {
2290 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2291 }
2292 }
2293
2294 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2295 if (resumed) {
2296 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2297 } else {
2298 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2299 }
2300 }
2301
2302 /**
2303 * Ensure that the top activity in the stack is resumed.
2304 *
2305 * @param prev The previously resumed activity, for when in the process
2306 * of pausing; can be null to call from elsewhere.
2307 *
2308 * @return Returns true if something is being resumed, or false if
2309 * nothing happened.
2310 */
2311 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2312 // Find the first activity that is not finishing.
2313 HistoryRecord next = topRunningActivityLocked(null);
2314
2315 // Remember how we'll process this pause/resume situation, and ensure
2316 // that the state is reset however we wind up proceeding.
2317 final boolean userLeaving = mUserLeaving;
2318 mUserLeaving = false;
2319
2320 if (next == null) {
2321 // There are no more activities! Let's just start up the
2322 // Launcher...
2323 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2324 && mTopAction == null) {
2325 // We are running in factory test mode, but unable to find
2326 // the factory test app, so just sit around displaying the
2327 // error message and don't try to start anything.
2328 return false;
2329 }
2330 Intent intent = new Intent(
2331 mTopAction,
2332 mTopData != null ? Uri.parse(mTopData) : null);
2333 intent.setComponent(mTopComponent);
2334 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2335 intent.addCategory(Intent.CATEGORY_HOME);
2336 }
2337 ActivityInfo aInfo =
2338 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002339 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002340 if (aInfo != null) {
2341 intent.setComponent(new ComponentName(
2342 aInfo.applicationInfo.packageName, aInfo.name));
2343 // Don't do this if the home app is currently being
2344 // instrumented.
2345 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2346 aInfo.applicationInfo.uid);
2347 if (app == null || app.instrumentationClass == null) {
2348 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2349 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002350 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002351 }
2352 }
2353 return true;
2354 }
2355
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002356 next.delayedResume = false;
2357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002358 // If the top activity is the resumed one, nothing to do.
2359 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2360 // Make sure we have executed any pending transitions, since there
2361 // should be nothing left to do at this point.
2362 mWindowManager.executeAppTransition();
2363 return false;
2364 }
2365
2366 // If we are sleeping, and there is no resumed activity, and the top
2367 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002368 if ((mSleeping || mShuttingDown)
2369 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002370 // Make sure we have executed any pending transitions, since there
2371 // should be nothing left to do at this point.
2372 mWindowManager.executeAppTransition();
2373 return false;
2374 }
2375
2376 // The activity may be waiting for stop, but that is no longer
2377 // appropriate for it.
2378 mStoppingActivities.remove(next);
2379 mWaitingVisibleActivities.remove(next);
2380
2381 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2382
2383 // If we are currently pausing an activity, then don't do anything
2384 // until that is done.
2385 if (mPausingActivity != null) {
2386 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2387 return false;
2388 }
2389
2390 // We need to start pausing the current activity so the top one
2391 // can be resumed...
2392 if (mResumedActivity != null) {
2393 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2394 startPausingLocked(userLeaving, false);
2395 return true;
2396 }
2397
2398 if (prev != null && prev != next) {
2399 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2400 prev.waitingVisible = true;
2401 mWaitingVisibleActivities.add(prev);
2402 if (DEBUG_SWITCH) Log.v(
2403 TAG, "Resuming top, waiting visible to hide: " + prev);
2404 } else {
2405 // The next activity is already visible, so hide the previous
2406 // activity's windows right now so we can show the new one ASAP.
2407 // We only do this if the previous is finishing, which should mean
2408 // it is on top of the one being resumed so hiding it quickly
2409 // is good. Otherwise, we want to do the normal route of allowing
2410 // the resumed activity to be shown so we can decide if the
2411 // previous should actually be hidden depending on whether the
2412 // new one is found to be full-screen or not.
2413 if (prev.finishing) {
2414 mWindowManager.setAppVisibility(prev, false);
2415 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2416 + prev + ", waitingVisible="
2417 + (prev != null ? prev.waitingVisible : null)
2418 + ", nowVisible=" + next.nowVisible);
2419 } else {
2420 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2421 + prev + ", waitingVisible="
2422 + (prev != null ? prev.waitingVisible : null)
2423 + ", nowVisible=" + next.nowVisible);
2424 }
2425 }
2426 }
2427
2428 // We are starting up the next activity, so tell the window manager
2429 // that the previous one will be hidden soon. This way it can know
2430 // to ignore it when computing the desired screen orientation.
2431 if (prev != null) {
2432 if (prev.finishing) {
2433 if (DEBUG_TRANSITION) Log.v(TAG,
2434 "Prepare close transition: prev=" + prev);
2435 mWindowManager.prepareAppTransition(prev.task == next.task
2436 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2437 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2438 mWindowManager.setAppWillBeHidden(prev);
2439 mWindowManager.setAppVisibility(prev, false);
2440 } else {
2441 if (DEBUG_TRANSITION) Log.v(TAG,
2442 "Prepare open transition: prev=" + prev);
2443 mWindowManager.prepareAppTransition(prev.task == next.task
2444 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2445 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2446 }
2447 if (false) {
2448 mWindowManager.setAppWillBeHidden(prev);
2449 mWindowManager.setAppVisibility(prev, false);
2450 }
2451 } else if (mHistory.size() > 1) {
2452 if (DEBUG_TRANSITION) Log.v(TAG,
2453 "Prepare open transition: no previous");
2454 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2455 }
2456
2457 if (next.app != null && next.app.thread != null) {
2458 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2459
2460 // This activity is now becoming visible.
2461 mWindowManager.setAppVisibility(next, true);
2462
2463 HistoryRecord lastResumedActivity = mResumedActivity;
2464 ActivityState lastState = next.state;
2465
2466 updateCpuStats();
2467
2468 next.state = ActivityState.RESUMED;
2469 mResumedActivity = next;
2470 next.task.touchActiveTime();
2471 updateLRUListLocked(next.app, true);
2472 updateLRUListLocked(next);
2473
2474 // Have the window manager re-evaluate the orientation of
2475 // the screen based on the new activity order.
2476 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002477 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 next.mayFreezeScreenLocked(next.app) ? next : null);
2479 if (config != null) {
2480 next.frozenBeforeDestroy = true;
2481 }
2482 if (!updateConfigurationLocked(config, next)) {
2483 // The configuration update wasn't able to keep the existing
2484 // instance of the activity, and instead started a new one.
2485 // We should be all done, but let's just make sure our activity
2486 // is still at the top and schedule another run if something
2487 // weird happened.
2488 HistoryRecord nextNext = topRunningActivityLocked(null);
2489 if (DEBUG_SWITCH) Log.i(TAG,
2490 "Activity config changed during resume: " + next
2491 + ", new next: " + nextNext);
2492 if (nextNext != next) {
2493 // Do over!
2494 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2495 }
2496 mWindowManager.executeAppTransition();
2497 return true;
2498 }
2499
2500 try {
2501 // Deliver all pending results.
2502 ArrayList a = next.results;
2503 if (a != null) {
2504 final int N = a.size();
2505 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002506 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002507 TAG, "Delivering results to " + next
2508 + ": " + a);
2509 next.app.thread.scheduleSendResult(next, a);
2510 }
2511 }
2512
2513 if (next.newIntents != null) {
2514 next.app.thread.scheduleNewIntent(next.newIntents, next);
2515 }
2516
2517 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2518 System.identityHashCode(next),
2519 next.task.taskId, next.shortComponentName);
2520 updateUsageStats(next, true);
2521
2522 next.app.thread.scheduleResumeActivity(next,
2523 isNextTransitionForward());
2524 pauseIfSleepingLocked();
2525
2526 } catch (Exception e) {
2527 // Whoops, need to restart this activity!
2528 next.state = lastState;
2529 mResumedActivity = lastResumedActivity;
2530 if (Config.LOGD) Log.d(TAG,
2531 "Restarting because process died: " + next);
2532 if (!next.hasBeenLaunched) {
2533 next.hasBeenLaunched = true;
2534 } else {
2535 if (SHOW_APP_STARTING_ICON) {
2536 mWindowManager.setAppStartingWindow(
2537 next, next.packageName, next.theme,
2538 next.nonLocalizedLabel,
2539 next.labelRes, next.icon, null, true);
2540 }
2541 }
2542 startSpecificActivityLocked(next, true, false);
2543 return true;
2544 }
2545
2546 // From this point on, if something goes wrong there is no way
2547 // to recover the activity.
2548 try {
2549 next.visible = true;
2550 completeResumeLocked(next);
2551 } catch (Exception e) {
2552 // If any exception gets thrown, toss away this
2553 // activity and try the next one.
2554 Log.w(TAG, "Exception thrown during resume of " + next, e);
2555 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2556 "resume-exception");
2557 return true;
2558 }
2559
2560 // Didn't need to use the icicle, and it is now out of date.
2561 next.icicle = null;
2562 next.haveState = false;
2563 next.stopped = false;
2564
2565 } else {
2566 // Whoops, need to restart this activity!
2567 if (!next.hasBeenLaunched) {
2568 next.hasBeenLaunched = true;
2569 } else {
2570 if (SHOW_APP_STARTING_ICON) {
2571 mWindowManager.setAppStartingWindow(
2572 next, next.packageName, next.theme,
2573 next.nonLocalizedLabel,
2574 next.labelRes, next.icon, null, true);
2575 }
2576 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2577 }
2578 startSpecificActivityLocked(next, true, true);
2579 }
2580
2581 return true;
2582 }
2583
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002584 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2585 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 final int NH = mHistory.size();
2587
2588 int addPos = -1;
2589
2590 if (!newTask) {
2591 // If starting in an existing task, find where that is...
2592 HistoryRecord next = null;
2593 boolean startIt = true;
2594 for (int i = NH-1; i >= 0; i--) {
2595 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2596 if (p.finishing) {
2597 continue;
2598 }
2599 if (p.task == r.task) {
2600 // Here it is! Now, if this is not yet visible to the
2601 // user, then just add it without starting; it will
2602 // get started when the user navigates back to it.
2603 addPos = i+1;
2604 if (!startIt) {
2605 mHistory.add(addPos, r);
2606 r.inHistory = true;
2607 r.task.numActivities++;
2608 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2609 r.info.screenOrientation, r.fullscreen);
2610 if (VALIDATE_TOKENS) {
2611 mWindowManager.validateAppTokens(mHistory);
2612 }
2613 return;
2614 }
2615 break;
2616 }
2617 if (p.fullscreen) {
2618 startIt = false;
2619 }
2620 next = p;
2621 }
2622 }
2623
2624 // Place a new activity at top of stack, so it is next to interact
2625 // with the user.
2626 if (addPos < 0) {
2627 addPos = mHistory.size();
2628 }
2629
2630 // If we are not placing the new activity frontmost, we do not want
2631 // to deliver the onUserLeaving callback to the actual frontmost
2632 // activity
2633 if (addPos < NH) {
2634 mUserLeaving = false;
2635 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2636 }
2637
2638 // Slot the activity into the history stack and proceed
2639 mHistory.add(addPos, r);
2640 r.inHistory = true;
2641 r.frontOfTask = newTask;
2642 r.task.numActivities++;
2643 if (NH > 0) {
2644 // We want to show the starting preview window if we are
2645 // switching to a new task, or the next activity's process is
2646 // not currently running.
2647 boolean showStartingIcon = newTask;
2648 ProcessRecord proc = r.app;
2649 if (proc == null) {
2650 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2651 }
2652 if (proc == null || proc.thread == null) {
2653 showStartingIcon = true;
2654 }
2655 if (DEBUG_TRANSITION) Log.v(TAG,
2656 "Prepare open transition: starting " + r);
2657 mWindowManager.prepareAppTransition(newTask
2658 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2659 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2660 mWindowManager.addAppToken(
2661 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2662 boolean doShow = true;
2663 if (newTask) {
2664 // Even though this activity is starting fresh, we still need
2665 // to reset it to make sure we apply affinities to move any
2666 // existing activities from other tasks in to it.
2667 // If the caller has requested that the target task be
2668 // reset, then do so.
2669 if ((r.intent.getFlags()
2670 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2671 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002672 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 }
2674 }
2675 if (SHOW_APP_STARTING_ICON && doShow) {
2676 // Figure out if we are transitioning from another activity that is
2677 // "has the same starting icon" as the next one. This allows the
2678 // window manager to keep the previous window it had previously
2679 // created, if it still had one.
2680 HistoryRecord prev = mResumedActivity;
2681 if (prev != null) {
2682 // We don't want to reuse the previous starting preview if:
2683 // (1) The current activity is in a different task.
2684 if (prev.task != r.task) prev = null;
2685 // (2) The current activity is already displayed.
2686 else if (prev.nowVisible) prev = null;
2687 }
2688 mWindowManager.setAppStartingWindow(
2689 r, r.packageName, r.theme, r.nonLocalizedLabel,
2690 r.labelRes, r.icon, prev, showStartingIcon);
2691 }
2692 } else {
2693 // If this is the first activity, don't do any fancy animations,
2694 // because there is nothing for it to animate on top of.
2695 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2696 r.info.screenOrientation, r.fullscreen);
2697 }
2698 if (VALIDATE_TOKENS) {
2699 mWindowManager.validateAppTokens(mHistory);
2700 }
2701
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002702 if (doResume) {
2703 resumeTopActivityLocked(null);
2704 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 }
2706
2707 /**
2708 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002709 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2710 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002711 * an instance of that activity in the stack and, if found, finish all
2712 * activities on top of it and return the instance.
2713 *
2714 * @param newR Description of the new activity being started.
2715 * @return Returns the old activity that should be continue to be used,
2716 * or null if none was found.
2717 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002718 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 HistoryRecord newR, boolean doClear) {
2720 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002721
2722 // First find the requested task.
2723 while (i > 0) {
2724 i--;
2725 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2726 if (r.task.taskId == taskId) {
2727 i++;
2728 break;
2729 }
2730 }
2731
2732 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002733 while (i > 0) {
2734 i--;
2735 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2736 if (r.finishing) {
2737 continue;
2738 }
2739 if (r.task.taskId != taskId) {
2740 return null;
2741 }
2742 if (r.realActivity.equals(newR.realActivity)) {
2743 // Here it is! Now finish everything in front...
2744 HistoryRecord ret = r;
2745 if (doClear) {
2746 while (i < (mHistory.size()-1)) {
2747 i++;
2748 r = (HistoryRecord)mHistory.get(i);
2749 if (r.finishing) {
2750 continue;
2751 }
2752 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2753 null, "clear")) {
2754 i--;
2755 }
2756 }
2757 }
2758
2759 // Finally, if this is a normal launch mode (that is, not
2760 // expecting onNewIntent()), then we will finish the current
2761 // instance of the activity so a new fresh one can be started.
2762 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2763 if (!ret.finishing) {
2764 int index = indexOfTokenLocked(ret, false);
2765 if (index >= 0) {
2766 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2767 null, "clear");
2768 }
2769 return null;
2770 }
2771 }
2772
2773 return ret;
2774 }
2775 }
2776
2777 return null;
2778 }
2779
2780 /**
2781 * Find the activity in the history stack within the given task. Returns
2782 * the index within the history at which it's found, or < 0 if not found.
2783 */
2784 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2785 int i = mHistory.size();
2786 while (i > 0) {
2787 i--;
2788 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2789 if (candidate.task.taskId != task) {
2790 break;
2791 }
2792 if (candidate.realActivity.equals(r.realActivity)) {
2793 return i;
2794 }
2795 }
2796
2797 return -1;
2798 }
2799
2800 /**
2801 * Reorder the history stack so that the activity at the given index is
2802 * brought to the front.
2803 */
2804 private final HistoryRecord moveActivityToFrontLocked(int where) {
2805 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2806 int top = mHistory.size();
2807 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2808 mHistory.add(top, newTop);
2809 oldTop.frontOfTask = false;
2810 newTop.frontOfTask = true;
2811 return newTop;
2812 }
2813
2814 /**
2815 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2816 * method will be called at the proper time.
2817 */
2818 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2819 boolean sent = false;
2820 if (r.state == ActivityState.RESUMED
2821 && r.app != null && r.app.thread != null) {
2822 try {
2823 ArrayList<Intent> ar = new ArrayList<Intent>();
2824 ar.add(new Intent(intent));
2825 r.app.thread.scheduleNewIntent(ar, r);
2826 sent = true;
2827 } catch (Exception e) {
2828 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2829 }
2830 }
2831 if (!sent) {
2832 r.addNewIntentLocked(new Intent(intent));
2833 }
2834 }
2835
2836 private final void logStartActivity(int tag, HistoryRecord r,
2837 TaskRecord task) {
2838 EventLog.writeEvent(tag,
2839 System.identityHashCode(r), task.taskId,
2840 r.shortComponentName, r.intent.getAction(),
2841 r.intent.getType(), r.intent.getDataString(),
2842 r.intent.getFlags());
2843 }
2844
2845 private final int startActivityLocked(IApplicationThread caller,
2846 Intent intent, String resolvedType,
2847 Uri[] grantedUriPermissions,
2848 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2849 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002850 int callingPid, int callingUid, boolean onlyIfNeeded,
2851 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002852 Log.i(TAG, "Starting activity: " + intent);
2853
2854 HistoryRecord sourceRecord = null;
2855 HistoryRecord resultRecord = null;
2856 if (resultTo != null) {
2857 int index = indexOfTokenLocked(resultTo, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002858 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002859 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2860 if (index >= 0) {
2861 sourceRecord = (HistoryRecord)mHistory.get(index);
2862 if (requestCode >= 0 && !sourceRecord.finishing) {
2863 resultRecord = sourceRecord;
2864 }
2865 }
2866 }
2867
2868 int launchFlags = intent.getFlags();
2869
2870 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2871 && sourceRecord != null) {
2872 // Transfer the result target from the source activity to the new
2873 // one being started, including any failures.
2874 if (requestCode >= 0) {
2875 return START_FORWARD_AND_REQUEST_CONFLICT;
2876 }
2877 resultRecord = sourceRecord.resultTo;
2878 resultWho = sourceRecord.resultWho;
2879 requestCode = sourceRecord.requestCode;
2880 sourceRecord.resultTo = null;
2881 if (resultRecord != null) {
2882 resultRecord.removeResultsLocked(
2883 sourceRecord, resultWho, requestCode);
2884 }
2885 }
2886
2887 int err = START_SUCCESS;
2888
2889 if (intent.getComponent() == null) {
2890 // We couldn't find a class that can handle the given Intent.
2891 // That's the end of that!
2892 err = START_INTENT_NOT_RESOLVED;
2893 }
2894
2895 if (err == START_SUCCESS && aInfo == null) {
2896 // We couldn't find the specific class specified in the Intent.
2897 // Also the end of the line.
2898 err = START_CLASS_NOT_FOUND;
2899 }
2900
2901 ProcessRecord callerApp = null;
2902 if (err == START_SUCCESS && caller != null) {
2903 callerApp = getRecordForAppLocked(caller);
2904 if (callerApp != null) {
2905 callingPid = callerApp.pid;
2906 callingUid = callerApp.info.uid;
2907 } else {
2908 Log.w(TAG, "Unable to find app for caller " + caller
2909 + " (pid=" + callingPid + ") when starting: "
2910 + intent.toString());
2911 err = START_PERMISSION_DENIED;
2912 }
2913 }
2914
2915 if (err != START_SUCCESS) {
2916 if (resultRecord != null) {
2917 sendActivityResultLocked(-1,
2918 resultRecord, resultWho, requestCode,
2919 Activity.RESULT_CANCELED, null);
2920 }
2921 return err;
2922 }
2923
2924 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2925 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2926 if (perm != PackageManager.PERMISSION_GRANTED) {
2927 if (resultRecord != null) {
2928 sendActivityResultLocked(-1,
2929 resultRecord, resultWho, requestCode,
2930 Activity.RESULT_CANCELED, null);
2931 }
2932 String msg = "Permission Denial: starting " + intent.toString()
2933 + " from " + callerApp + " (pid=" + callingPid
2934 + ", uid=" + callingUid + ")"
2935 + " requires " + aInfo.permission;
2936 Log.w(TAG, msg);
2937 throw new SecurityException(msg);
2938 }
2939
2940 if (mWatcher != null) {
2941 boolean abort = false;
2942 try {
2943 // The Intent we give to the watcher has the extra data
2944 // stripped off, since it can contain private information.
2945 Intent watchIntent = intent.cloneFilter();
2946 abort = !mWatcher.activityStarting(watchIntent,
2947 aInfo.applicationInfo.packageName);
2948 } catch (RemoteException e) {
2949 mWatcher = null;
2950 }
2951
2952 if (abort) {
2953 if (resultRecord != null) {
2954 sendActivityResultLocked(-1,
2955 resultRecord, resultWho, requestCode,
2956 Activity.RESULT_CANCELED, null);
2957 }
2958 // We pretend to the caller that it was really started, but
2959 // they will just get a cancel result.
2960 return START_SUCCESS;
2961 }
2962 }
2963
2964 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
2965 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002966 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002968 if (mResumedActivity == null
2969 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2970 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2971 PendingActivityLaunch pal = new PendingActivityLaunch();
2972 pal.r = r;
2973 pal.sourceRecord = sourceRecord;
2974 pal.grantedUriPermissions = grantedUriPermissions;
2975 pal.grantedMode = grantedMode;
2976 pal.onlyIfNeeded = onlyIfNeeded;
2977 mPendingActivityLaunches.add(pal);
2978 return START_SWITCHES_CANCELED;
2979 }
2980 }
2981
2982 if (mDidAppSwitch) {
2983 // This is the second allowed switch since we stopped switches,
2984 // so now just generally allow switches. Use case: user presses
2985 // home (switches disabled, switch to home, mDidAppSwitch now true);
2986 // user taps a home icon (coming from home so allowed, we hit here
2987 // and now allow anyone to switch again).
2988 mAppSwitchesAllowedTime = 0;
2989 } else {
2990 mDidAppSwitch = true;
2991 }
2992
2993 doPendingActivityLaunchesLocked(false);
2994
2995 return startActivityUncheckedLocked(r, sourceRecord,
2996 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
2997 }
2998
2999 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3000 final int N = mPendingActivityLaunches.size();
3001 if (N <= 0) {
3002 return;
3003 }
3004 for (int i=0; i<N; i++) {
3005 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3006 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3007 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3008 doResume && i == (N-1));
3009 }
3010 mPendingActivityLaunches.clear();
3011 }
3012
3013 private final int startActivityUncheckedLocked(HistoryRecord r,
3014 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3015 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3016 final Intent intent = r.intent;
3017 final int callingUid = r.launchedFromUid;
3018
3019 int launchFlags = intent.getFlags();
3020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003021 // We'll invoke onUserLeaving before onPause only if the launching
3022 // activity did not explicitly state that this is an automated launch.
3023 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3024 if (DEBUG_USER_LEAVING) Log.v(TAG,
3025 "startActivity() => mUserLeaving=" + mUserLeaving);
3026
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003027 // If the caller has asked not to resume at this point, we make note
3028 // of this in the record so that we can skip it when trying to find
3029 // the top running activity.
3030 if (!doResume) {
3031 r.delayedResume = true;
3032 }
3033
3034 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3035 != 0 ? r : null;
3036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003037 // If the onlyIfNeeded flag is set, then we can do this if the activity
3038 // being launched is the same as the one making the call... or, as
3039 // a special case, if we do not know the caller then we count the
3040 // current top activity as the caller.
3041 if (onlyIfNeeded) {
3042 HistoryRecord checkedCaller = sourceRecord;
3043 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003044 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003045 }
3046 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3047 // Caller is not the same as launcher, so always needed.
3048 onlyIfNeeded = false;
3049 }
3050 }
3051
3052 if (grantedUriPermissions != null && callingUid > 0) {
3053 for (int i=0; i<grantedUriPermissions.length; i++) {
3054 grantUriPermissionLocked(callingUid, r.packageName,
3055 grantedUriPermissions[i], grantedMode, r);
3056 }
3057 }
3058
3059 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3060 intent, r);
3061
3062 if (sourceRecord == null) {
3063 // This activity is not being started from another... in this
3064 // case we -always- start a new task.
3065 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3066 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3067 + intent);
3068 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3069 }
3070 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3071 // The original activity who is starting us is running as a single
3072 // instance... this new activity it is starting must go on its
3073 // own task.
3074 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3075 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3076 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3077 // The activity being started is a single instance... it always
3078 // gets launched into its own task.
3079 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3080 }
3081
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003082 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003083 // For whatever reason this activity is being launched into a new
3084 // task... yet the caller has requested a result back. Well, that
3085 // is pretty messed up, so instead immediately send back a cancel
3086 // and let the new task continue launched as normal without a
3087 // dependency on its originator.
3088 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3089 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003090 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 Activity.RESULT_CANCELED, null);
3092 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003093 }
3094
3095 boolean addingToTask = false;
3096 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3097 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3098 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3099 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3100 // If bring to front is requested, and no result is requested, and
3101 // we can find a task that was started with this same
3102 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003103 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 // See if there is a task to bring to the front. If this is
3105 // a SINGLE_INSTANCE activity, there can be one and only one
3106 // instance of it in the history, and it is always in its own
3107 // unique task, so we do a special search.
3108 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3109 ? findTaskLocked(intent, r.info)
3110 : findActivityLocked(intent, r.info);
3111 if (taskTop != null) {
3112 if (taskTop.task.intent == null) {
3113 // This task was started because of movement of
3114 // the activity based on affinity... now that we
3115 // are actually launching it, we can assign the
3116 // base intent.
3117 taskTop.task.setIntent(intent, r.info);
3118 }
3119 // If the target task is not in the front, then we need
3120 // to bring it to the front... except... well, with
3121 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3122 // to have the same behavior as if a new instance was
3123 // being started, which means not bringing it to the front
3124 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003125 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 if (curTop.task != taskTop.task) {
3127 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3128 boolean callerAtFront = sourceRecord == null
3129 || curTop.task == sourceRecord.task;
3130 if (callerAtFront) {
3131 // We really do want to push this one into the
3132 // user's face, right now.
3133 moveTaskToFrontLocked(taskTop.task);
3134 }
3135 }
3136 // If the caller has requested that the target task be
3137 // reset, then do so.
3138 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3139 taskTop = resetTaskIfNeededLocked(taskTop, r);
3140 }
3141 if (onlyIfNeeded) {
3142 // We don't need to start a new activity, and
3143 // the client said not to do anything if that
3144 // is the case, so this is it! And for paranoia, make
3145 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003146 if (doResume) {
3147 resumeTopActivityLocked(null);
3148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149 return START_RETURN_INTENT_TO_CALLER;
3150 }
3151 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3152 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3153 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3154 // In this situation we want to remove all activities
3155 // from the task up to the one being started. In most
3156 // cases this means we are resetting the task to its
3157 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003158 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 taskTop.task.taskId, r, true);
3160 if (top != null) {
3161 if (top.frontOfTask) {
3162 // Activity aliases may mean we use different
3163 // intents for the top activity, so make sure
3164 // the task now has the identity of the new
3165 // intent.
3166 top.task.setIntent(r.intent, r.info);
3167 }
3168 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3169 deliverNewIntentLocked(top, r.intent);
3170 } else {
3171 // A special case: we need to
3172 // start the activity because it is not currently
3173 // running, and the caller has asked to clear the
3174 // current task to have this activity at the top.
3175 addingToTask = true;
3176 // Now pretend like this activity is being started
3177 // by the top of its task, so it is put in the
3178 // right place.
3179 sourceRecord = taskTop;
3180 }
3181 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3182 // In this case the top activity on the task is the
3183 // same as the one being launched, so we take that
3184 // as a request to bring the task to the foreground.
3185 // If the top activity in the task is the root
3186 // activity, deliver this new intent to it if it
3187 // desires.
3188 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3189 && taskTop.realActivity.equals(r.realActivity)) {
3190 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3191 if (taskTop.frontOfTask) {
3192 taskTop.task.setIntent(r.intent, r.info);
3193 }
3194 deliverNewIntentLocked(taskTop, r.intent);
3195 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3196 // In this case we are launching the root activity
3197 // of the task, but with a different intent. We
3198 // should start a new instance on top.
3199 addingToTask = true;
3200 sourceRecord = taskTop;
3201 }
3202 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3203 // In this case an activity is being launched in to an
3204 // existing task, without resetting that task. This
3205 // is typically the situation of launching an activity
3206 // from a notification or shortcut. We want to place
3207 // the new activity on top of the current task.
3208 addingToTask = true;
3209 sourceRecord = taskTop;
3210 } else if (!taskTop.task.rootWasReset) {
3211 // In this case we are launching in to an existing task
3212 // that has not yet been started from its front door.
3213 // The current task has been brought to the front.
3214 // Ideally, we'd probably like to place this new task
3215 // at the bottom of its stack, but that's a little hard
3216 // to do with the current organization of the code so
3217 // for now we'll just drop it.
3218 taskTop.task.setIntent(r.intent, r.info);
3219 }
3220 if (!addingToTask) {
3221 // We didn't do anything... but it was needed (a.k.a., client
3222 // don't use that intent!) And for paranoia, make
3223 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003224 if (doResume) {
3225 resumeTopActivityLocked(null);
3226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 return START_TASK_TO_FRONT;
3228 }
3229 }
3230 }
3231 }
3232
3233 //String uri = r.intent.toURI();
3234 //Intent intent2 = new Intent(uri);
3235 //Log.i(TAG, "Given intent: " + r.intent);
3236 //Log.i(TAG, "URI is: " + uri);
3237 //Log.i(TAG, "To intent: " + intent2);
3238
3239 if (r.packageName != null) {
3240 // If the activity being launched is the same as the one currently
3241 // at the top, then we need to check if it should only be launched
3242 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003243 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3244 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003245 if (top.realActivity.equals(r.realActivity)) {
3246 if (top.app != null && top.app.thread != null) {
3247 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3248 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3249 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3250 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3251 // For paranoia, make sure we have correctly
3252 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003253 if (doResume) {
3254 resumeTopActivityLocked(null);
3255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 if (onlyIfNeeded) {
3257 // We don't need to start a new activity, and
3258 // the client said not to do anything if that
3259 // is the case, so this is it!
3260 return START_RETURN_INTENT_TO_CALLER;
3261 }
3262 deliverNewIntentLocked(top, r.intent);
3263 return START_DELIVERED_TO_TOP;
3264 }
3265 }
3266 }
3267 }
3268
3269 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003270 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003272 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003273 Activity.RESULT_CANCELED, null);
3274 }
3275 return START_CLASS_NOT_FOUND;
3276 }
3277
3278 boolean newTask = false;
3279
3280 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003281 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003282 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3283 // todo: should do better management of integers.
3284 mCurTask++;
3285 if (mCurTask <= 0) {
3286 mCurTask = 1;
3287 }
3288 r.task = new TaskRecord(mCurTask, r.info, intent,
3289 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3290 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3291 + " in new task " + r.task);
3292 newTask = true;
3293 addRecentTask(r.task);
3294
3295 } else if (sourceRecord != null) {
3296 if (!addingToTask &&
3297 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3298 // In this case, we are adding the activity to an existing
3299 // task, but the caller has asked to clear that task if the
3300 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003301 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003302 sourceRecord.task.taskId, r, true);
3303 if (top != null) {
3304 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3305 deliverNewIntentLocked(top, r.intent);
3306 // For paranoia, make sure we have correctly
3307 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003308 if (doResume) {
3309 resumeTopActivityLocked(null);
3310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003311 return START_DELIVERED_TO_TOP;
3312 }
3313 } else if (!addingToTask &&
3314 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3315 // In this case, we are launching an activity in our own task
3316 // that may already be running somewhere in the history, and
3317 // we want to shuffle it to the front of the stack if so.
3318 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3319 if (where >= 0) {
3320 HistoryRecord top = moveActivityToFrontLocked(where);
3321 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3322 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003323 if (doResume) {
3324 resumeTopActivityLocked(null);
3325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 return START_DELIVERED_TO_TOP;
3327 }
3328 }
3329 // An existing activity is starting this new activity, so we want
3330 // to keep the new one in the same task as the one that is starting
3331 // it.
3332 r.task = sourceRecord.task;
3333 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3334 + " in existing task " + r.task);
3335
3336 } else {
3337 // This not being started from an existing activity, and not part
3338 // of a new task... just put it in the top task, though these days
3339 // this case should never happen.
3340 final int N = mHistory.size();
3341 HistoryRecord prev =
3342 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3343 r.task = prev != null
3344 ? prev.task
3345 : new TaskRecord(mCurTask, r.info, intent,
3346 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3347 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3348 + " in new guessed " + r.task);
3349 }
3350 if (newTask) {
3351 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3352 }
3353 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003354 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003355 return START_SUCCESS;
3356 }
3357
3358 public final int startActivity(IApplicationThread caller,
3359 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3360 int grantedMode, IBinder resultTo,
3361 String resultWho, int requestCode, boolean onlyIfNeeded,
3362 boolean debug) {
3363 // Refuse possible leaked file descriptors
3364 if (intent != null && intent.hasFileDescriptors()) {
3365 throw new IllegalArgumentException("File descriptors passed in Intent");
3366 }
3367
The Android Open Source Project4df24232009-03-05 14:34:35 -08003368 final boolean componentSpecified = intent.getComponent() != null;
3369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003370 // Don't modify the client's object!
3371 intent = new Intent(intent);
3372
3373 // Collect information about the target of the Intent.
3374 // Must do this before locking, because resolving the intent
3375 // may require launching a process to run its content provider.
3376 ActivityInfo aInfo;
3377 try {
3378 ResolveInfo rInfo =
3379 ActivityThread.getPackageManager().resolveIntent(
3380 intent, resolvedType,
3381 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003382 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003383 aInfo = rInfo != null ? rInfo.activityInfo : null;
3384 } catch (RemoteException e) {
3385 aInfo = null;
3386 }
3387
3388 if (aInfo != null) {
3389 // Store the found target back into the intent, because now that
3390 // we have it we never want to do this again. For example, if the
3391 // user navigates back to this point in the history, we should
3392 // always restart the exact same activity.
3393 intent.setComponent(new ComponentName(
3394 aInfo.applicationInfo.packageName, aInfo.name));
3395
3396 // Don't debug things in the system process
3397 if (debug) {
3398 if (!aInfo.processName.equals("system")) {
3399 setDebugApp(aInfo.processName, true, false);
3400 }
3401 }
3402 }
3403
3404 synchronized(this) {
3405 final long origId = Binder.clearCallingIdentity();
3406 int res = startActivityLocked(caller, intent, resolvedType,
3407 grantedUriPermissions, grantedMode, aInfo,
3408 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003409 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003410 Binder.restoreCallingIdentity(origId);
3411 return res;
3412 }
3413 }
3414
3415 public boolean startNextMatchingActivity(IBinder callingActivity,
3416 Intent intent) {
3417 // Refuse possible leaked file descriptors
3418 if (intent != null && intent.hasFileDescriptors() == true) {
3419 throw new IllegalArgumentException("File descriptors passed in Intent");
3420 }
3421
3422 synchronized (this) {
3423 int index = indexOfTokenLocked(callingActivity, false);
3424 if (index < 0) {
3425 return false;
3426 }
3427 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3428 if (r.app == null || r.app.thread == null) {
3429 // The caller is not running... d'oh!
3430 return false;
3431 }
3432 intent = new Intent(intent);
3433 // The caller is not allowed to change the data.
3434 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3435 // And we are resetting to find the next component...
3436 intent.setComponent(null);
3437
3438 ActivityInfo aInfo = null;
3439 try {
3440 List<ResolveInfo> resolves =
3441 ActivityThread.getPackageManager().queryIntentActivities(
3442 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003443 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003444
3445 // Look for the original activity in the list...
3446 final int N = resolves != null ? resolves.size() : 0;
3447 for (int i=0; i<N; i++) {
3448 ResolveInfo rInfo = resolves.get(i);
3449 if (rInfo.activityInfo.packageName.equals(r.packageName)
3450 && rInfo.activityInfo.name.equals(r.info.name)) {
3451 // We found the current one... the next matching is
3452 // after it.
3453 i++;
3454 if (i<N) {
3455 aInfo = resolves.get(i).activityInfo;
3456 }
3457 break;
3458 }
3459 }
3460 } catch (RemoteException e) {
3461 }
3462
3463 if (aInfo == null) {
3464 // Nobody who is next!
3465 return false;
3466 }
3467
3468 intent.setComponent(new ComponentName(
3469 aInfo.applicationInfo.packageName, aInfo.name));
3470 intent.setFlags(intent.getFlags()&~(
3471 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3472 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3473 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3474 Intent.FLAG_ACTIVITY_NEW_TASK));
3475
3476 // Okay now we need to start the new activity, replacing the
3477 // currently running activity. This is a little tricky because
3478 // we want to start the new one as if the current one is finished,
3479 // but not finish the current one first so that there is no flicker.
3480 // And thus...
3481 final boolean wasFinishing = r.finishing;
3482 r.finishing = true;
3483
3484 // Propagate reply information over to the new activity.
3485 final HistoryRecord resultTo = r.resultTo;
3486 final String resultWho = r.resultWho;
3487 final int requestCode = r.requestCode;
3488 r.resultTo = null;
3489 if (resultTo != null) {
3490 resultTo.removeResultsLocked(r, resultWho, requestCode);
3491 }
3492
3493 final long origId = Binder.clearCallingIdentity();
3494 // XXX we are not dealing with propagating grantedUriPermissions...
3495 // those are not yet exposed to user code, so there is no need.
3496 int res = startActivityLocked(r.app.thread, intent,
3497 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003498 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 Binder.restoreCallingIdentity(origId);
3500
3501 r.finishing = wasFinishing;
3502 if (res != START_SUCCESS) {
3503 return false;
3504 }
3505 return true;
3506 }
3507 }
3508
3509 final int startActivityInPackage(int uid,
3510 Intent intent, String resolvedType, IBinder resultTo,
3511 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003512 final boolean componentSpecified = intent.getComponent() != null;
3513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 // Don't modify the client's object!
3515 intent = new Intent(intent);
3516
3517 // Collect information about the target of the Intent.
3518 // Must do this before locking, because resolving the intent
3519 // may require launching a process to run its content provider.
3520 ActivityInfo aInfo;
3521 try {
3522 ResolveInfo rInfo =
3523 ActivityThread.getPackageManager().resolveIntent(
3524 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003525 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003526 aInfo = rInfo != null ? rInfo.activityInfo : null;
3527 } catch (RemoteException e) {
3528 aInfo = null;
3529 }
3530
3531 if (aInfo != null) {
3532 // Store the found target back into the intent, because now that
3533 // we have it we never want to do this again. For example, if the
3534 // user navigates back to this point in the history, we should
3535 // always restart the exact same activity.
3536 intent.setComponent(new ComponentName(
3537 aInfo.applicationInfo.packageName, aInfo.name));
3538 }
3539
3540 synchronized(this) {
3541 return startActivityLocked(null, intent, resolvedType,
3542 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003543 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003544 }
3545 }
3546
3547 private final void addRecentTask(TaskRecord task) {
3548 // Remove any existing entries that are the same kind of task.
3549 int N = mRecentTasks.size();
3550 for (int i=0; i<N; i++) {
3551 TaskRecord tr = mRecentTasks.get(i);
3552 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3553 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3554 mRecentTasks.remove(i);
3555 i--;
3556 N--;
3557 if (task.intent == null) {
3558 // If the new recent task we are adding is not fully
3559 // specified, then replace it with the existing recent task.
3560 task = tr;
3561 }
3562 }
3563 }
3564 if (N >= MAX_RECENT_TASKS) {
3565 mRecentTasks.remove(N-1);
3566 }
3567 mRecentTasks.add(0, task);
3568 }
3569
3570 public void setRequestedOrientation(IBinder token,
3571 int requestedOrientation) {
3572 synchronized (this) {
3573 int index = indexOfTokenLocked(token, false);
3574 if (index < 0) {
3575 return;
3576 }
3577 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3578 final long origId = Binder.clearCallingIdentity();
3579 mWindowManager.setAppOrientation(r, requestedOrientation);
3580 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003581 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 r.mayFreezeScreenLocked(r.app) ? r : null);
3583 if (config != null) {
3584 r.frozenBeforeDestroy = true;
3585 if (!updateConfigurationLocked(config, r)) {
3586 resumeTopActivityLocked(null);
3587 }
3588 }
3589 Binder.restoreCallingIdentity(origId);
3590 }
3591 }
3592
3593 public int getRequestedOrientation(IBinder token) {
3594 synchronized (this) {
3595 int index = indexOfTokenLocked(token, false);
3596 if (index < 0) {
3597 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3598 }
3599 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3600 return mWindowManager.getAppOrientation(r);
3601 }
3602 }
3603
3604 private final void stopActivityLocked(HistoryRecord r) {
3605 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3606 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3607 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3608 if (!r.finishing) {
3609 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3610 "no-history");
3611 }
3612 } else if (r.app != null && r.app.thread != null) {
3613 if (mFocusedActivity == r) {
3614 setFocusedActivityLocked(topRunningActivityLocked(null));
3615 }
3616 r.resumeKeyDispatchingLocked();
3617 try {
3618 r.stopped = false;
3619 r.state = ActivityState.STOPPING;
3620 if (DEBUG_VISBILITY) Log.v(
3621 TAG, "Stopping visible=" + r.visible + " for " + r);
3622 if (!r.visible) {
3623 mWindowManager.setAppVisibility(r, false);
3624 }
3625 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3626 } catch (Exception e) {
3627 // Maybe just ignore exceptions here... if the process
3628 // has crashed, our death notification will clean things
3629 // up.
3630 Log.w(TAG, "Exception thrown during pause", e);
3631 // Just in case, assume it to be stopped.
3632 r.stopped = true;
3633 r.state = ActivityState.STOPPED;
3634 if (r.configDestroy) {
3635 destroyActivityLocked(r, true);
3636 }
3637 }
3638 }
3639 }
3640
3641 /**
3642 * @return Returns true if the activity is being finished, false if for
3643 * some reason it is being left as-is.
3644 */
3645 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3646 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003647 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 TAG, "Finishing activity: token=" + token
3649 + ", result=" + resultCode + ", data=" + resultData);
3650
3651 int index = indexOfTokenLocked(token, false);
3652 if (index < 0) {
3653 return false;
3654 }
3655 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3656
3657 // Is this the last activity left?
3658 boolean lastActivity = true;
3659 for (int i=mHistory.size()-1; i>=0; i--) {
3660 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3661 if (!p.finishing && p != r) {
3662 lastActivity = false;
3663 break;
3664 }
3665 }
3666
3667 // If this is the last activity, but it is the home activity, then
3668 // just don't finish it.
3669 if (lastActivity) {
3670 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3671 return false;
3672 }
3673 }
3674
3675 finishActivityLocked(r, index, resultCode, resultData, reason);
3676 return true;
3677 }
3678
3679 /**
3680 * @return Returns true if this activity has been removed from the history
3681 * list, or false if it is still in the list and will be removed later.
3682 */
3683 private final boolean finishActivityLocked(HistoryRecord r, int index,
3684 int resultCode, Intent resultData, String reason) {
3685 if (r.finishing) {
3686 Log.w(TAG, "Duplicate finish request for " + r);
3687 return false;
3688 }
3689
3690 r.finishing = true;
3691 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3692 System.identityHashCode(r),
3693 r.task.taskId, r.shortComponentName, reason);
3694 r.task.numActivities--;
3695 if (r.frontOfTask && index < (mHistory.size()-1)) {
3696 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3697 if (next.task == r.task) {
3698 next.frontOfTask = true;
3699 }
3700 }
3701
3702 r.pauseKeyDispatchingLocked();
3703 if (mFocusedActivity == r) {
3704 setFocusedActivityLocked(topRunningActivityLocked(null));
3705 }
3706
3707 // send the result
3708 HistoryRecord resultTo = r.resultTo;
3709 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003710 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3711 + " who=" + r.resultWho + " req=" + r.requestCode
3712 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 if (r.info.applicationInfo.uid > 0) {
3714 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3715 r.packageName, resultData, r);
3716 }
3717 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3718 resultData);
3719 r.resultTo = null;
3720 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003721 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722
3723 // Make sure this HistoryRecord is not holding on to other resources,
3724 // because clients have remote IPC references to this object so we
3725 // can't assume that will go away and want to avoid circular IPC refs.
3726 r.results = null;
3727 r.pendingResults = null;
3728 r.newIntents = null;
3729 r.icicle = null;
3730
3731 if (mPendingThumbnails.size() > 0) {
3732 // There are clients waiting to receive thumbnails so, in case
3733 // this is an activity that someone is waiting for, add it
3734 // to the pending list so we can correctly update the clients.
3735 mCancelledThumbnails.add(r);
3736 }
3737
3738 if (mResumedActivity == r) {
3739 boolean endTask = index <= 0
3740 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3741 if (DEBUG_TRANSITION) Log.v(TAG,
3742 "Prepare close transition: finishing " + r);
3743 mWindowManager.prepareAppTransition(endTask
3744 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3745 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3746
3747 // Tell window manager to prepare for this one to be removed.
3748 mWindowManager.setAppVisibility(r, false);
3749
3750 if (mPausingActivity == null) {
3751 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3752 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3753 startPausingLocked(false, false);
3754 }
3755
3756 } else if (r.state != ActivityState.PAUSING) {
3757 // If the activity is PAUSING, we will complete the finish once
3758 // it is done pausing; else we can just directly finish it here.
3759 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3760 return finishCurrentActivityLocked(r, index,
3761 FINISH_AFTER_PAUSE) == null;
3762 } else {
3763 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3764 }
3765
3766 return false;
3767 }
3768
3769 private static final int FINISH_IMMEDIATELY = 0;
3770 private static final int FINISH_AFTER_PAUSE = 1;
3771 private static final int FINISH_AFTER_VISIBLE = 2;
3772
3773 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3774 int mode) {
3775 final int index = indexOfTokenLocked(r, false);
3776 if (index < 0) {
3777 return null;
3778 }
3779
3780 return finishCurrentActivityLocked(r, index, mode);
3781 }
3782
3783 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3784 int index, int mode) {
3785 // First things first: if this activity is currently visible,
3786 // and the resumed activity is not yet visible, then hold off on
3787 // finishing until the resumed one becomes visible.
3788 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3789 if (!mStoppingActivities.contains(r)) {
3790 mStoppingActivities.add(r);
3791 if (mStoppingActivities.size() > 3) {
3792 // If we already have a few activities waiting to stop,
3793 // then give up on things going idle and start clearing
3794 // them out.
3795 Message msg = Message.obtain();
3796 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3797 mHandler.sendMessage(msg);
3798 }
3799 }
3800 r.state = ActivityState.STOPPING;
3801 updateOomAdjLocked();
3802 return r;
3803 }
3804
3805 // make sure the record is cleaned out of other places.
3806 mStoppingActivities.remove(r);
3807 mWaitingVisibleActivities.remove(r);
3808 if (mResumedActivity == r) {
3809 mResumedActivity = null;
3810 }
3811 final ActivityState prevState = r.state;
3812 r.state = ActivityState.FINISHING;
3813
3814 if (mode == FINISH_IMMEDIATELY
3815 || prevState == ActivityState.STOPPED
3816 || prevState == ActivityState.INITIALIZING) {
3817 // If this activity is already stopped, we can just finish
3818 // it right now.
3819 return destroyActivityLocked(r, true) ? null : r;
3820 } else {
3821 // Need to go through the full pause cycle to get this
3822 // activity into the stopped state and then finish it.
3823 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3824 mFinishingActivities.add(r);
3825 resumeTopActivityLocked(null);
3826 }
3827 return r;
3828 }
3829
3830 /**
3831 * This is the internal entry point for handling Activity.finish().
3832 *
3833 * @param token The Binder token referencing the Activity we want to finish.
3834 * @param resultCode Result code, if any, from this Activity.
3835 * @param resultData Result data (Intent), if any, from this Activity.
3836 *
3837 * @result Returns true if the activity successfully finished, or false if it is still running.
3838 */
3839 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3840 // Refuse possible leaked file descriptors
3841 if (resultData != null && resultData.hasFileDescriptors() == true) {
3842 throw new IllegalArgumentException("File descriptors passed in Intent");
3843 }
3844
3845 synchronized(this) {
3846 if (mWatcher != null) {
3847 // Find the first activity that is not finishing.
3848 HistoryRecord next = topRunningActivityLocked(token, 0);
3849 if (next != null) {
3850 // ask watcher if this is allowed
3851 boolean resumeOK = true;
3852 try {
3853 resumeOK = mWatcher.activityResuming(next.packageName);
3854 } catch (RemoteException e) {
3855 mWatcher = null;
3856 }
3857
3858 if (!resumeOK) {
3859 return false;
3860 }
3861 }
3862 }
3863 final long origId = Binder.clearCallingIdentity();
3864 boolean res = requestFinishActivityLocked(token, resultCode,
3865 resultData, "app-request");
3866 Binder.restoreCallingIdentity(origId);
3867 return res;
3868 }
3869 }
3870
3871 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3872 String resultWho, int requestCode, int resultCode, Intent data) {
3873
3874 if (callingUid > 0) {
3875 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3876 data, r);
3877 }
3878
The Android Open Source Project10592532009-03-18 17:39:46 -07003879 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3880 + " : who=" + resultWho + " req=" + requestCode
3881 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3883 try {
3884 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3885 list.add(new ResultInfo(resultWho, requestCode,
3886 resultCode, data));
3887 r.app.thread.scheduleSendResult(r, list);
3888 return;
3889 } catch (Exception e) {
3890 Log.w(TAG, "Exception thrown sending result to " + r, e);
3891 }
3892 }
3893
3894 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3895 }
3896
3897 public final void finishSubActivity(IBinder token, String resultWho,
3898 int requestCode) {
3899 synchronized(this) {
3900 int index = indexOfTokenLocked(token, false);
3901 if (index < 0) {
3902 return;
3903 }
3904 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3905
3906 final long origId = Binder.clearCallingIdentity();
3907
3908 int i;
3909 for (i=mHistory.size()-1; i>=0; i--) {
3910 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3911 if (r.resultTo == self && r.requestCode == requestCode) {
3912 if ((r.resultWho == null && resultWho == null) ||
3913 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3914 finishActivityLocked(r, i,
3915 Activity.RESULT_CANCELED, null, "request-sub");
3916 }
3917 }
3918 }
3919
3920 Binder.restoreCallingIdentity(origId);
3921 }
3922 }
3923
3924 /**
3925 * Perform clean-up of service connections in an activity record.
3926 */
3927 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3928 // Throw away any services that have been bound by this activity.
3929 if (r.connections != null) {
3930 Iterator<ConnectionRecord> it = r.connections.iterator();
3931 while (it.hasNext()) {
3932 ConnectionRecord c = it.next();
3933 removeConnectionLocked(c, null, r);
3934 }
3935 r.connections = null;
3936 }
3937 }
3938
3939 /**
3940 * Perform the common clean-up of an activity record. This is called both
3941 * as part of destroyActivityLocked() (when destroying the client-side
3942 * representation) and cleaning things up as a result of its hosting
3943 * processing going away, in which case there is no remaining client-side
3944 * state to destroy so only the cleanup here is needed.
3945 */
3946 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
3947 if (mResumedActivity == r) {
3948 mResumedActivity = null;
3949 }
3950 if (mFocusedActivity == r) {
3951 mFocusedActivity = null;
3952 }
3953
3954 r.configDestroy = false;
3955 r.frozenBeforeDestroy = false;
3956
3957 // Make sure this record is no longer in the pending finishes list.
3958 // This could happen, for example, if we are trimming activities
3959 // down to the max limit while they are still waiting to finish.
3960 mFinishingActivities.remove(r);
3961 mWaitingVisibleActivities.remove(r);
3962
3963 // Remove any pending results.
3964 if (r.finishing && r.pendingResults != null) {
3965 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3966 PendingIntentRecord rec = apr.get();
3967 if (rec != null) {
3968 cancelIntentSenderLocked(rec, false);
3969 }
3970 }
3971 r.pendingResults = null;
3972 }
3973
3974 if (cleanServices) {
3975 cleanUpActivityServicesLocked(r);
3976 }
3977
3978 if (mPendingThumbnails.size() > 0) {
3979 // There are clients waiting to receive thumbnails so, in case
3980 // this is an activity that someone is waiting for, add it
3981 // to the pending list so we can correctly update the clients.
3982 mCancelledThumbnails.add(r);
3983 }
3984
3985 // Get rid of any pending idle timeouts.
3986 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3987 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3988 }
3989
3990 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
3991 if (r.state != ActivityState.DESTROYED) {
3992 mHistory.remove(r);
3993 r.inHistory = false;
3994 r.state = ActivityState.DESTROYED;
3995 mWindowManager.removeAppToken(r);
3996 if (VALIDATE_TOKENS) {
3997 mWindowManager.validateAppTokens(mHistory);
3998 }
3999 cleanUpActivityServicesLocked(r);
4000 removeActivityUriPermissionsLocked(r);
4001 }
4002 }
4003
4004 /**
4005 * Destroy the current CLIENT SIDE instance of an activity. This may be
4006 * called both when actually finishing an activity, or when performing
4007 * a configuration switch where we destroy the current client-side object
4008 * but then create a new client-side object for this same HistoryRecord.
4009 */
4010 private final boolean destroyActivityLocked(HistoryRecord r,
4011 boolean removeFromApp) {
4012 if (DEBUG_SWITCH) Log.v(
4013 TAG, "Removing activity: token=" + r
4014 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4015 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4016 System.identityHashCode(r),
4017 r.task.taskId, r.shortComponentName);
4018
4019 boolean removedFromHistory = false;
4020
4021 cleanUpActivityLocked(r, false);
4022
4023 if (r.app != null) {
4024 if (removeFromApp) {
4025 int idx = r.app.activities.indexOf(r);
4026 if (idx >= 0) {
4027 r.app.activities.remove(idx);
4028 }
4029 if (r.persistent) {
4030 decPersistentCountLocked(r.app);
4031 }
4032 }
4033
4034 boolean skipDestroy = false;
4035
4036 try {
4037 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4038 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4039 r.configChangeFlags);
4040 } catch (Exception e) {
4041 // We can just ignore exceptions here... if the process
4042 // has crashed, our death notification will clean things
4043 // up.
4044 //Log.w(TAG, "Exception thrown during finish", e);
4045 if (r.finishing) {
4046 removeActivityFromHistoryLocked(r);
4047 removedFromHistory = true;
4048 skipDestroy = true;
4049 }
4050 }
4051
4052 r.app = null;
4053 r.nowVisible = false;
4054
4055 if (r.finishing && !skipDestroy) {
4056 r.state = ActivityState.DESTROYING;
4057 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4058 msg.obj = r;
4059 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4060 } else {
4061 r.state = ActivityState.DESTROYED;
4062 }
4063 } else {
4064 // remove this record from the history.
4065 if (r.finishing) {
4066 removeActivityFromHistoryLocked(r);
4067 removedFromHistory = true;
4068 } else {
4069 r.state = ActivityState.DESTROYED;
4070 }
4071 }
4072
4073 r.configChangeFlags = 0;
4074
4075 if (!mLRUActivities.remove(r)) {
4076 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4077 }
4078
4079 return removedFromHistory;
4080 }
4081
4082 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4083 ProcessRecord app)
4084 {
4085 int i = list.size();
4086 if (localLOGV) Log.v(
4087 TAG, "Removing app " + app + " from list " + list
4088 + " with " + i + " entries");
4089 while (i > 0) {
4090 i--;
4091 HistoryRecord r = (HistoryRecord)list.get(i);
4092 if (localLOGV) Log.v(
4093 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4094 if (r.app == app) {
4095 if (localLOGV) Log.v(TAG, "Removing this entry!");
4096 list.remove(i);
4097 }
4098 }
4099 }
4100
4101 /**
4102 * Main function for removing an existing process from the activity manager
4103 * as a result of that process going away. Clears out all connections
4104 * to the process.
4105 */
4106 private final void handleAppDiedLocked(ProcessRecord app,
4107 boolean restarting) {
4108 cleanUpApplicationRecordLocked(app, restarting, -1);
4109 if (!restarting) {
4110 mLRUProcesses.remove(app);
4111 }
4112
4113 // Just in case...
4114 if (mPausingActivity != null && mPausingActivity.app == app) {
4115 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4116 mPausingActivity = null;
4117 }
4118 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4119 mLastPausedActivity = null;
4120 }
4121
4122 // Remove this application's activities from active lists.
4123 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4124 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4125 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4126 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4127
4128 boolean atTop = true;
4129 boolean hasVisibleActivities = false;
4130
4131 // Clean out the history list.
4132 int i = mHistory.size();
4133 if (localLOGV) Log.v(
4134 TAG, "Removing app " + app + " from history with " + i + " entries");
4135 while (i > 0) {
4136 i--;
4137 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4138 if (localLOGV) Log.v(
4139 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4140 if (r.app == app) {
4141 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4142 if (localLOGV) Log.v(
4143 TAG, "Removing this entry! frozen=" + r.haveState
4144 + " finishing=" + r.finishing);
4145 mHistory.remove(i);
4146
4147 r.inHistory = false;
4148 mWindowManager.removeAppToken(r);
4149 if (VALIDATE_TOKENS) {
4150 mWindowManager.validateAppTokens(mHistory);
4151 }
4152 removeActivityUriPermissionsLocked(r);
4153
4154 } else {
4155 // We have the current state for this activity, so
4156 // it can be restarted later when needed.
4157 if (localLOGV) Log.v(
4158 TAG, "Keeping entry, setting app to null");
4159 if (r.visible) {
4160 hasVisibleActivities = true;
4161 }
4162 r.app = null;
4163 r.nowVisible = false;
4164 if (!r.haveState) {
4165 r.icicle = null;
4166 }
4167 }
4168
4169 cleanUpActivityLocked(r, true);
4170 r.state = ActivityState.STOPPED;
4171 }
4172 atTop = false;
4173 }
4174
4175 app.activities.clear();
4176
4177 if (app.instrumentationClass != null) {
4178 Log.w(TAG, "Crash of app " + app.processName
4179 + " running instrumentation " + app.instrumentationClass);
4180 Bundle info = new Bundle();
4181 info.putString("shortMsg", "Process crashed.");
4182 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4183 }
4184
4185 if (!restarting) {
4186 if (!resumeTopActivityLocked(null)) {
4187 // If there was nothing to resume, and we are not already
4188 // restarting this process, but there is a visible activity that
4189 // is hosted by the process... then make sure all visible
4190 // activities are running, taking care of restarting this
4191 // process.
4192 if (hasVisibleActivities) {
4193 ensureActivitiesVisibleLocked(null, 0);
4194 }
4195 }
4196 }
4197 }
4198
4199 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4200 IBinder threadBinder = thread.asBinder();
4201
4202 // Find the application record.
4203 int count = mLRUProcesses.size();
4204 int i;
4205 for (i=0; i<count; i++) {
4206 ProcessRecord rec = mLRUProcesses.get(i);
4207 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4208 return i;
4209 }
4210 }
4211 return -1;
4212 }
4213
4214 private final ProcessRecord getRecordForAppLocked(
4215 IApplicationThread thread) {
4216 if (thread == null) {
4217 return null;
4218 }
4219
4220 int appIndex = getLRURecordIndexForAppLocked(thread);
4221 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4222 }
4223
4224 private final void appDiedLocked(ProcessRecord app, int pid,
4225 IApplicationThread thread) {
4226
4227 mProcDeaths[0]++;
4228
4229 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4230 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4231 + ") has died.");
4232 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4233 if (localLOGV) Log.v(
4234 TAG, "Dying app: " + app + ", pid: " + pid
4235 + ", thread: " + thread.asBinder());
4236 boolean doLowMem = app.instrumentationClass == null;
4237 handleAppDiedLocked(app, false);
4238
4239 if (doLowMem) {
4240 // If there are no longer any background processes running,
4241 // and the app that died was not running instrumentation,
4242 // then tell everyone we are now low on memory.
4243 boolean haveBg = false;
4244 int count = mLRUProcesses.size();
4245 int i;
4246 for (i=0; i<count; i++) {
4247 ProcessRecord rec = mLRUProcesses.get(i);
4248 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4249 haveBg = true;
4250 break;
4251 }
4252 }
4253
4254 if (!haveBg) {
4255 Log.i(TAG, "Low Memory: No more background processes.");
4256 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4257 for (i=0; i<count; i++) {
4258 ProcessRecord rec = mLRUProcesses.get(i);
4259 if (rec.thread != null) {
4260 rec.lastRequestedGc = SystemClock.uptimeMillis();
4261 try {
4262 rec.thread.scheduleLowMemory();
4263 } catch (RemoteException e) {
4264 // Don't care if the process is gone.
4265 }
4266 }
4267 }
4268 }
4269 }
4270 } else if (Config.LOGD) {
4271 Log.d(TAG, "Received spurious death notification for thread "
4272 + thread.asBinder());
4273 }
4274 }
4275
4276 final String readFile(String filename) {
4277 try {
4278 FileInputStream fs = new FileInputStream(filename);
4279 byte[] inp = new byte[8192];
4280 int size = fs.read(inp);
4281 fs.close();
4282 return new String(inp, 0, 0, size);
4283 } catch (java.io.IOException e) {
4284 }
4285 return "";
4286 }
4287
4288 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4289 final String annotation) {
4290 if (app.notResponding || app.crashing) {
4291 return;
4292 }
4293
4294 // Log the ANR to the event log.
4295 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4296
4297 // If we are on a secure build and the application is not interesting to the user (it is
4298 // not visible or in the background), just kill it instead of displaying a dialog.
4299 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4300 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4301 Process.killProcess(app.pid);
4302 return;
4303 }
4304
4305 // DeviceMonitor.start();
4306
4307 String processInfo = null;
4308 if (MONITOR_CPU_USAGE) {
4309 updateCpuStatsNow();
4310 synchronized (mProcessStatsThread) {
4311 processInfo = mProcessStats.printCurrentState();
4312 }
4313 }
4314
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004315 StringBuilder info = mStringBuilder;
4316 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004317 info.append("ANR (application not responding) in process: ");
4318 info.append(app.processName);
4319 if (annotation != null) {
4320 info.append("\nAnnotation: ");
4321 info.append(annotation);
4322 }
4323 if (MONITOR_CPU_USAGE) {
4324 info.append("\nCPU usage:\n");
4325 info.append(processInfo);
4326 }
4327 Log.i(TAG, info.toString());
4328
4329 // The application is not responding. Dump as many thread traces as we can.
4330 boolean fileDump = prepareTraceFile(true);
4331 if (!fileDump) {
4332 // Dumping traces to the log, just dump the process that isn't responding so
4333 // we don't overflow the log
4334 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4335 } else {
4336 // Dumping traces to a file so dump all active processes we know about
4337 synchronized (this) {
4338 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4339 ProcessRecord r = mLRUProcesses.get(i);
4340 if (r.thread != null) {
4341 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4342 }
4343 }
4344 }
4345 }
4346
4347 if (mWatcher != null) {
4348 try {
4349 int res = mWatcher.appNotResponding(app.processName,
4350 app.pid, info.toString());
4351 if (res != 0) {
4352 if (res < 0) {
4353 // wait until the SIGQUIT has had a chance to process before killing the
4354 // process.
4355 try {
4356 wait(2000);
4357 } catch (InterruptedException e) {
4358 }
4359
4360 Process.killProcess(app.pid);
4361 return;
4362 }
4363 }
4364 } catch (RemoteException e) {
4365 mWatcher = null;
4366 }
4367 }
4368
4369 makeAppNotRespondingLocked(app,
4370 activity != null ? activity.shortComponentName : null,
4371 annotation != null ? "ANR " + annotation : "ANR",
4372 info.toString(), null);
4373 Message msg = Message.obtain();
4374 HashMap map = new HashMap();
4375 msg.what = SHOW_NOT_RESPONDING_MSG;
4376 msg.obj = map;
4377 map.put("app", app);
4378 if (activity != null) {
4379 map.put("activity", activity);
4380 }
4381
4382 mHandler.sendMessage(msg);
4383 return;
4384 }
4385
4386 /**
4387 * If a stack trace file has been configured, prepare the filesystem
4388 * by creating the directory if it doesn't exist and optionally
4389 * removing the old trace file.
4390 *
4391 * @param removeExisting If set, the existing trace file will be removed.
4392 * @return Returns true if the trace file preparations succeeded
4393 */
4394 public static boolean prepareTraceFile(boolean removeExisting) {
4395 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4396 boolean fileReady = false;
4397 if (!TextUtils.isEmpty(tracesPath)) {
4398 File f = new File(tracesPath);
4399 if (!f.exists()) {
4400 // Ensure the enclosing directory exists
4401 File dir = f.getParentFile();
4402 if (!dir.exists()) {
4403 fileReady = dir.mkdirs();
4404 FileUtils.setPermissions(dir.getAbsolutePath(),
4405 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4406 } else if (dir.isDirectory()) {
4407 fileReady = true;
4408 }
4409 } else if (removeExisting) {
4410 // Remove the previous traces file, so we don't fill the disk.
4411 // The VM will recreate it
4412 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4413 fileReady = f.delete();
4414 }
4415 }
4416
4417 return fileReady;
4418 }
4419
4420
4421 private final void decPersistentCountLocked(ProcessRecord app)
4422 {
4423 app.persistentActivities--;
4424 if (app.persistentActivities > 0) {
4425 // Still more of 'em...
4426 return;
4427 }
4428 if (app.persistent) {
4429 // Ah, but the application itself is persistent. Whatever!
4430 return;
4431 }
4432
4433 // App is no longer persistent... make sure it and the ones
4434 // following it in the LRU list have the correc oom_adj.
4435 updateOomAdjLocked();
4436 }
4437
4438 public void setPersistent(IBinder token, boolean isPersistent) {
4439 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4440 != PackageManager.PERMISSION_GRANTED) {
4441 String msg = "Permission Denial: setPersistent() from pid="
4442 + Binder.getCallingPid()
4443 + ", uid=" + Binder.getCallingUid()
4444 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4445 Log.w(TAG, msg);
4446 throw new SecurityException(msg);
4447 }
4448
4449 synchronized(this) {
4450 int index = indexOfTokenLocked(token, true);
4451 if (index < 0) {
4452 return;
4453 }
4454 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4455 ProcessRecord app = r.app;
4456
4457 if (localLOGV) Log.v(
4458 TAG, "Setting persistence " + isPersistent + ": " + r);
4459
4460 if (isPersistent) {
4461 if (r.persistent) {
4462 // Okay okay, I heard you already!
4463 if (localLOGV) Log.v(TAG, "Already persistent!");
4464 return;
4465 }
4466 r.persistent = true;
4467 app.persistentActivities++;
4468 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4469 if (app.persistentActivities > 1) {
4470 // We aren't the first...
4471 if (localLOGV) Log.v(TAG, "Not the first!");
4472 return;
4473 }
4474 if (app.persistent) {
4475 // This would be redundant.
4476 if (localLOGV) Log.v(TAG, "App is persistent!");
4477 return;
4478 }
4479
4480 // App is now persistent... make sure it and the ones
4481 // following it now have the correct oom_adj.
4482 final long origId = Binder.clearCallingIdentity();
4483 updateOomAdjLocked();
4484 Binder.restoreCallingIdentity(origId);
4485
4486 } else {
4487 if (!r.persistent) {
4488 // Okay okay, I heard you already!
4489 return;
4490 }
4491 r.persistent = false;
4492 final long origId = Binder.clearCallingIdentity();
4493 decPersistentCountLocked(app);
4494 Binder.restoreCallingIdentity(origId);
4495
4496 }
4497 }
4498 }
4499
4500 public boolean clearApplicationUserData(final String packageName,
4501 final IPackageDataObserver observer) {
4502 int uid = Binder.getCallingUid();
4503 int pid = Binder.getCallingPid();
4504 long callingId = Binder.clearCallingIdentity();
4505 try {
4506 IPackageManager pm = ActivityThread.getPackageManager();
4507 int pkgUid = -1;
4508 synchronized(this) {
4509 try {
4510 pkgUid = pm.getPackageUid(packageName);
4511 } catch (RemoteException e) {
4512 }
4513 if (pkgUid == -1) {
4514 Log.w(TAG, "Invalid packageName:" + packageName);
4515 return false;
4516 }
4517 if (uid == pkgUid || checkComponentPermission(
4518 android.Manifest.permission.CLEAR_APP_USER_DATA,
4519 pid, uid, -1)
4520 == PackageManager.PERMISSION_GRANTED) {
4521 restartPackageLocked(packageName, pkgUid);
4522 } else {
4523 throw new SecurityException(pid+" does not have permission:"+
4524 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4525 "for process:"+packageName);
4526 }
4527 }
4528
4529 try {
4530 //clear application user data
4531 pm.clearApplicationUserData(packageName, observer);
4532 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4533 Uri.fromParts("package", packageName, null));
4534 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4535 broadcastIntentLocked(null, null, intent,
4536 null, null, 0, null, null, null,
4537 false, false, MY_PID, Process.SYSTEM_UID);
4538 } catch (RemoteException e) {
4539 }
4540 } finally {
4541 Binder.restoreCallingIdentity(callingId);
4542 }
4543 return true;
4544 }
4545
4546 public void restartPackage(final String packageName) {
4547 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4548 != PackageManager.PERMISSION_GRANTED) {
4549 String msg = "Permission Denial: restartPackage() from pid="
4550 + Binder.getCallingPid()
4551 + ", uid=" + Binder.getCallingUid()
4552 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4553 Log.w(TAG, msg);
4554 throw new SecurityException(msg);
4555 }
4556
4557 long callingId = Binder.clearCallingIdentity();
4558 try {
4559 IPackageManager pm = ActivityThread.getPackageManager();
4560 int pkgUid = -1;
4561 synchronized(this) {
4562 try {
4563 pkgUid = pm.getPackageUid(packageName);
4564 } catch (RemoteException e) {
4565 }
4566 if (pkgUid == -1) {
4567 Log.w(TAG, "Invalid packageName: " + packageName);
4568 return;
4569 }
4570 restartPackageLocked(packageName, pkgUid);
4571 }
4572 } finally {
4573 Binder.restoreCallingIdentity(callingId);
4574 }
4575 }
4576
4577 private void restartPackageLocked(final String packageName, int uid) {
4578 uninstallPackageLocked(packageName, uid, false);
4579 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4580 Uri.fromParts("package", packageName, null));
4581 intent.putExtra(Intent.EXTRA_UID, uid);
4582 broadcastIntentLocked(null, null, intent,
4583 null, null, 0, null, null, null,
4584 false, false, MY_PID, Process.SYSTEM_UID);
4585 }
4586
4587 private final void uninstallPackageLocked(String name, int uid,
4588 boolean callerWillRestart) {
4589 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4590
4591 int i, N;
4592
4593 final String procNamePrefix = name + ":";
4594 if (uid < 0) {
4595 try {
4596 uid = ActivityThread.getPackageManager().getPackageUid(name);
4597 } catch (RemoteException e) {
4598 }
4599 }
4600
4601 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4602 while (badApps.hasNext()) {
4603 SparseArray<Long> ba = badApps.next();
4604 if (ba.get(uid) != null) {
4605 badApps.remove();
4606 }
4607 }
4608
4609 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4610
4611 // Remove all processes this package may have touched: all with the
4612 // same UID (except for the system or root user), and all whose name
4613 // matches the package name.
4614 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4615 final int NA = apps.size();
4616 for (int ia=0; ia<NA; ia++) {
4617 ProcessRecord app = apps.valueAt(ia);
4618 if (app.removed) {
4619 procs.add(app);
4620 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4621 || app.processName.equals(name)
4622 || app.processName.startsWith(procNamePrefix)) {
4623 app.removed = true;
4624 procs.add(app);
4625 }
4626 }
4627 }
4628
4629 N = procs.size();
4630 for (i=0; i<N; i++) {
4631 removeProcessLocked(procs.get(i), callerWillRestart);
4632 }
4633
4634 for (i=mHistory.size()-1; i>=0; i--) {
4635 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4636 if (r.packageName.equals(name)) {
4637 if (Config.LOGD) Log.d(
4638 TAG, " Force finishing activity "
4639 + r.intent.getComponent().flattenToShortString());
4640 if (r.app != null) {
4641 r.app.removed = true;
4642 }
4643 r.app = null;
4644 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4645 }
4646 }
4647
4648 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4649 for (ServiceRecord service : mServices.values()) {
4650 if (service.packageName.equals(name)) {
4651 if (service.app != null) {
4652 service.app.removed = true;
4653 }
4654 service.app = null;
4655 services.add(service);
4656 }
4657 }
4658
4659 N = services.size();
4660 for (i=0; i<N; i++) {
4661 bringDownServiceLocked(services.get(i), true);
4662 }
4663
4664 resumeTopActivityLocked(null);
4665 }
4666
4667 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4668 final String name = app.processName;
4669 final int uid = app.info.uid;
4670 if (Config.LOGD) Log.d(
4671 TAG, "Force removing process " + app + " (" + name
4672 + "/" + uid + ")");
4673
4674 mProcessNames.remove(name, uid);
4675 boolean needRestart = false;
4676 if (app.pid > 0 && app.pid != MY_PID) {
4677 int pid = app.pid;
4678 synchronized (mPidsSelfLocked) {
4679 mPidsSelfLocked.remove(pid);
4680 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4681 }
4682 handleAppDiedLocked(app, true);
4683 mLRUProcesses.remove(app);
4684 Process.killProcess(pid);
4685
4686 if (app.persistent) {
4687 if (!callerWillRestart) {
4688 addAppLocked(app.info);
4689 } else {
4690 needRestart = true;
4691 }
4692 }
4693 } else {
4694 mRemovedProcesses.add(app);
4695 }
4696
4697 return needRestart;
4698 }
4699
4700 private final void processStartTimedOutLocked(ProcessRecord app) {
4701 final int pid = app.pid;
4702 boolean gone = false;
4703 synchronized (mPidsSelfLocked) {
4704 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4705 if (knownApp != null && knownApp.thread == null) {
4706 mPidsSelfLocked.remove(pid);
4707 gone = true;
4708 }
4709 }
4710
4711 if (gone) {
4712 Log.w(TAG, "Process " + app + " failed to attach");
4713 mProcessNames.remove(app.processName, app.info.uid);
4714 Process.killProcess(pid);
4715 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4716 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4717 mPendingBroadcast = null;
4718 scheduleBroadcastsLocked();
4719 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004720 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4721 Log.w(TAG, "Unattached app died before backup, skipping");
4722 try {
4723 IBackupManager bm = IBackupManager.Stub.asInterface(
4724 ServiceManager.getService(Context.BACKUP_SERVICE));
4725 bm.agentDisconnected(app.info.packageName);
4726 } catch (RemoteException e) {
4727 // Can't happen; the backup manager is local
4728 }
4729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004730 } else {
4731 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4732 }
4733 }
4734
4735 private final boolean attachApplicationLocked(IApplicationThread thread,
4736 int pid) {
4737
4738 // Find the application record that is being attached... either via
4739 // the pid if we are running in multiple processes, or just pull the
4740 // next app record if we are emulating process with anonymous threads.
4741 ProcessRecord app;
4742 if (pid != MY_PID && pid >= 0) {
4743 synchronized (mPidsSelfLocked) {
4744 app = mPidsSelfLocked.get(pid);
4745 }
4746 } else if (mStartingProcesses.size() > 0) {
4747 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004748 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004749 } else {
4750 app = null;
4751 }
4752
4753 if (app == null) {
4754 Log.w(TAG, "No pending application record for pid " + pid
4755 + " (IApplicationThread " + thread + "); dropping process");
4756 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4757 if (pid > 0 && pid != MY_PID) {
4758 Process.killProcess(pid);
4759 } else {
4760 try {
4761 thread.scheduleExit();
4762 } catch (Exception e) {
4763 // Ignore exceptions.
4764 }
4765 }
4766 return false;
4767 }
4768
4769 // If this application record is still attached to a previous
4770 // process, clean it up now.
4771 if (app.thread != null) {
4772 handleAppDiedLocked(app, true);
4773 }
4774
4775 // Tell the process all about itself.
4776
4777 if (localLOGV) Log.v(
4778 TAG, "Binding process pid " + pid + " to record " + app);
4779
4780 String processName = app.processName;
4781 try {
4782 thread.asBinder().linkToDeath(new AppDeathRecipient(
4783 app, pid, thread), 0);
4784 } catch (RemoteException e) {
4785 app.resetPackageList();
4786 startProcessLocked(app, "link fail", processName);
4787 return false;
4788 }
4789
4790 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4791
4792 app.thread = thread;
4793 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004794 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004795 app.forcingToForeground = null;
4796 app.foregroundServices = false;
4797 app.debugging = false;
4798
4799 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4800
4801 List providers = generateApplicationProvidersLocked(app);
4802
4803 if (localLOGV) Log.v(
4804 TAG, "New app record " + app
4805 + " thread=" + thread.asBinder() + " pid=" + pid);
4806 try {
4807 int testMode = IApplicationThread.DEBUG_OFF;
4808 if (mDebugApp != null && mDebugApp.equals(processName)) {
4809 testMode = mWaitForDebugger
4810 ? IApplicationThread.DEBUG_WAIT
4811 : IApplicationThread.DEBUG_ON;
4812 app.debugging = true;
4813 if (mDebugTransient) {
4814 mDebugApp = mOrigDebugApp;
4815 mWaitForDebugger = mOrigWaitForDebugger;
4816 }
4817 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004818 // If the app is being launched for restore or full backup, set it up specially
4819 boolean isRestrictedBackupMode = false;
4820 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4821 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4822 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4823 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004824 thread.bindApplication(processName, app.instrumentationInfo != null
4825 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004826 app.instrumentationClass, app.instrumentationProfileFile,
4827 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004828 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004829 updateLRUListLocked(app, false);
4830 app.lastRequestedGc = SystemClock.uptimeMillis();
4831 } catch (Exception e) {
4832 // todo: Yikes! What should we do? For now we will try to
4833 // start another process, but that could easily get us in
4834 // an infinite loop of restarting processes...
4835 Log.w(TAG, "Exception thrown during bind!", e);
4836
4837 app.resetPackageList();
4838 startProcessLocked(app, "bind fail", processName);
4839 return false;
4840 }
4841
4842 // Remove this record from the list of starting applications.
4843 mPersistentStartingProcesses.remove(app);
4844 mProcessesOnHold.remove(app);
4845
4846 boolean badApp = false;
4847 boolean didSomething = false;
4848
4849 // See if the top visible activity is waiting to run in this process...
4850 HistoryRecord hr = topRunningActivityLocked(null);
4851 if (hr != null) {
4852 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4853 && processName.equals(hr.processName)) {
4854 try {
4855 if (realStartActivityLocked(hr, app, true, true)) {
4856 didSomething = true;
4857 }
4858 } catch (Exception e) {
4859 Log.w(TAG, "Exception in new application when starting activity "
4860 + hr.intent.getComponent().flattenToShortString(), e);
4861 badApp = true;
4862 }
4863 } else {
4864 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4865 }
4866 }
4867
4868 // Find any services that should be running in this process...
4869 if (!badApp && mPendingServices.size() > 0) {
4870 ServiceRecord sr = null;
4871 try {
4872 for (int i=0; i<mPendingServices.size(); i++) {
4873 sr = mPendingServices.get(i);
4874 if (app.info.uid != sr.appInfo.uid
4875 || !processName.equals(sr.processName)) {
4876 continue;
4877 }
4878
4879 mPendingServices.remove(i);
4880 i--;
4881 realStartServiceLocked(sr, app);
4882 didSomething = true;
4883 }
4884 } catch (Exception e) {
4885 Log.w(TAG, "Exception in new application when starting service "
4886 + sr.shortName, e);
4887 badApp = true;
4888 }
4889 }
4890
4891 // Check if the next broadcast receiver is in this process...
4892 BroadcastRecord br = mPendingBroadcast;
4893 if (!badApp && br != null && br.curApp == app) {
4894 try {
4895 mPendingBroadcast = null;
4896 processCurBroadcastLocked(br, app);
4897 didSomething = true;
4898 } catch (Exception e) {
4899 Log.w(TAG, "Exception in new application when starting receiver "
4900 + br.curComponent.flattenToShortString(), e);
4901 badApp = true;
4902 logBroadcastReceiverDiscard(br);
4903 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4904 br.resultExtras, br.resultAbort, true);
4905 scheduleBroadcastsLocked();
4906 }
4907 }
4908
Christopher Tate181fafa2009-05-14 11:12:14 -07004909 // Check whether the next backup agent is in this process...
4910 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4911 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
4912 try {
4913 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4914 } catch (Exception e) {
4915 Log.w(TAG, "Exception scheduling backup agent creation: ");
4916 e.printStackTrace();
4917 }
4918 }
4919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004920 if (badApp) {
4921 // todo: Also need to kill application to deal with all
4922 // kinds of exceptions.
4923 handleAppDiedLocked(app, false);
4924 return false;
4925 }
4926
4927 if (!didSomething) {
4928 updateOomAdjLocked();
4929 }
4930
4931 return true;
4932 }
4933
4934 public final void attachApplication(IApplicationThread thread) {
4935 synchronized (this) {
4936 int callingPid = Binder.getCallingPid();
4937 final long origId = Binder.clearCallingIdentity();
4938 attachApplicationLocked(thread, callingPid);
4939 Binder.restoreCallingIdentity(origId);
4940 }
4941 }
4942
4943 public final void activityIdle(IBinder token) {
4944 final long origId = Binder.clearCallingIdentity();
4945 activityIdleInternal(token, false);
4946 Binder.restoreCallingIdentity(origId);
4947 }
4948
4949 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
4950 boolean remove) {
4951 int N = mStoppingActivities.size();
4952 if (N <= 0) return null;
4953
4954 ArrayList<HistoryRecord> stops = null;
4955
4956 final boolean nowVisible = mResumedActivity != null
4957 && mResumedActivity.nowVisible
4958 && !mResumedActivity.waitingVisible;
4959 for (int i=0; i<N; i++) {
4960 HistoryRecord s = mStoppingActivities.get(i);
4961 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
4962 + nowVisible + " waitingVisible=" + s.waitingVisible
4963 + " finishing=" + s.finishing);
4964 if (s.waitingVisible && nowVisible) {
4965 mWaitingVisibleActivities.remove(s);
4966 s.waitingVisible = false;
4967 if (s.finishing) {
4968 // If this activity is finishing, it is sitting on top of
4969 // everyone else but we now know it is no longer needed...
4970 // so get rid of it. Otherwise, we need to go through the
4971 // normal flow and hide it once we determine that it is
4972 // hidden by the activities in front of it.
4973 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
4974 mWindowManager.setAppVisibility(s, false);
4975 }
4976 }
4977 if (!s.waitingVisible && remove) {
4978 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
4979 if (stops == null) {
4980 stops = new ArrayList<HistoryRecord>();
4981 }
4982 stops.add(s);
4983 mStoppingActivities.remove(i);
4984 N--;
4985 i--;
4986 }
4987 }
4988
4989 return stops;
4990 }
4991
4992 void enableScreenAfterBoot() {
4993 mWindowManager.enableScreenAfterBoot();
4994 }
4995
4996 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
4997 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
4998
4999 ArrayList<HistoryRecord> stops = null;
5000 ArrayList<HistoryRecord> finishes = null;
5001 ArrayList<HistoryRecord> thumbnails = null;
5002 int NS = 0;
5003 int NF = 0;
5004 int NT = 0;
5005 IApplicationThread sendThumbnail = null;
5006 boolean booting = false;
5007 boolean enableScreen = false;
5008
5009 synchronized (this) {
5010 if (token != null) {
5011 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5012 }
5013
5014 // Get the activity record.
5015 int index = indexOfTokenLocked(token, false);
5016 if (index >= 0) {
5017 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5018
5019 // No longer need to keep the device awake.
5020 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5021 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5022 mLaunchingActivity.release();
5023 }
5024
5025 // We are now idle. If someone is waiting for a thumbnail from
5026 // us, we can now deliver.
5027 r.idle = true;
5028 scheduleAppGcsLocked();
5029 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5030 sendThumbnail = r.app.thread;
5031 r.thumbnailNeeded = false;
5032 }
5033
5034 // If this activity is fullscreen, set up to hide those under it.
5035
5036 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5037 ensureActivitiesVisibleLocked(null, 0);
5038
5039 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5040 if (!mBooted && !fromTimeout) {
5041 mBooted = true;
5042 enableScreen = true;
5043 }
5044 }
5045
5046 // Atomically retrieve all of the other things to do.
5047 stops = processStoppingActivitiesLocked(true);
5048 NS = stops != null ? stops.size() : 0;
5049 if ((NF=mFinishingActivities.size()) > 0) {
5050 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5051 mFinishingActivities.clear();
5052 }
5053 if ((NT=mCancelledThumbnails.size()) > 0) {
5054 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5055 mCancelledThumbnails.clear();
5056 }
5057
5058 booting = mBooting;
5059 mBooting = false;
5060 }
5061
5062 int i;
5063
5064 // Send thumbnail if requested.
5065 if (sendThumbnail != null) {
5066 try {
5067 sendThumbnail.requestThumbnail(token);
5068 } catch (Exception e) {
5069 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5070 sendPendingThumbnail(null, token, null, null, true);
5071 }
5072 }
5073
5074 // Stop any activities that are scheduled to do so but have been
5075 // waiting for the next one to start.
5076 for (i=0; i<NS; i++) {
5077 HistoryRecord r = (HistoryRecord)stops.get(i);
5078 synchronized (this) {
5079 if (r.finishing) {
5080 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5081 } else {
5082 stopActivityLocked(r);
5083 }
5084 }
5085 }
5086
5087 // Finish any activities that are scheduled to do so but have been
5088 // waiting for the next one to start.
5089 for (i=0; i<NF; i++) {
5090 HistoryRecord r = (HistoryRecord)finishes.get(i);
5091 synchronized (this) {
5092 destroyActivityLocked(r, true);
5093 }
5094 }
5095
5096 // Report back to any thumbnail receivers.
5097 for (i=0; i<NT; i++) {
5098 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5099 sendPendingThumbnail(r, null, null, null, true);
5100 }
5101
5102 if (booting) {
5103 // Ensure that any processes we had put on hold are now started
5104 // up.
5105 final int NP = mProcessesOnHold.size();
5106 if (NP > 0) {
5107 ArrayList<ProcessRecord> procs =
5108 new ArrayList<ProcessRecord>(mProcessesOnHold);
5109 for (int ip=0; ip<NP; ip++) {
5110 this.startProcessLocked(procs.get(ip), "on-hold", null);
5111 }
5112 }
5113 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5114 // Tell anyone interested that we are done booting!
5115 synchronized (this) {
5116 broadcastIntentLocked(null, null,
5117 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5118 null, null, 0, null, null,
5119 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5120 false, false, MY_PID, Process.SYSTEM_UID);
5121 }
5122 }
5123 }
5124
5125 trimApplications();
5126 //dump();
5127 //mWindowManager.dump();
5128
5129 if (enableScreen) {
5130 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5131 SystemClock.uptimeMillis());
5132 enableScreenAfterBoot();
5133 }
5134 }
5135
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005136 final void ensureScreenEnabled() {
5137 boolean enableScreen;
5138 synchronized (this) {
5139 enableScreen = !mBooted;
5140 mBooted = true;
5141 }
5142
5143 if (enableScreen) {
5144 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5145 SystemClock.uptimeMillis());
5146 enableScreenAfterBoot();
5147 }
5148 }
5149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005150 public final void activityPaused(IBinder token, Bundle icicle) {
5151 // Refuse possible leaked file descriptors
5152 if (icicle != null && icicle.hasFileDescriptors()) {
5153 throw new IllegalArgumentException("File descriptors passed in Bundle");
5154 }
5155
5156 final long origId = Binder.clearCallingIdentity();
5157 activityPaused(token, icicle, false);
5158 Binder.restoreCallingIdentity(origId);
5159 }
5160
5161 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5162 if (DEBUG_PAUSE) Log.v(
5163 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5164 + ", timeout=" + timeout);
5165
5166 HistoryRecord r = null;
5167
5168 synchronized (this) {
5169 int index = indexOfTokenLocked(token, false);
5170 if (index >= 0) {
5171 r = (HistoryRecord)mHistory.get(index);
5172 if (!timeout) {
5173 r.icicle = icicle;
5174 r.haveState = true;
5175 }
5176 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5177 if (mPausingActivity == r) {
5178 r.state = ActivityState.PAUSED;
5179 completePauseLocked();
5180 } else {
5181 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5182 System.identityHashCode(r), r.shortComponentName,
5183 mPausingActivity != null
5184 ? mPausingActivity.shortComponentName : "(none)");
5185 }
5186 }
5187 }
5188 }
5189
5190 public final void activityStopped(IBinder token, Bitmap thumbnail,
5191 CharSequence description) {
5192 if (localLOGV) Log.v(
5193 TAG, "Activity stopped: token=" + token);
5194
5195 HistoryRecord r = null;
5196
5197 final long origId = Binder.clearCallingIdentity();
5198
5199 synchronized (this) {
5200 int index = indexOfTokenLocked(token, false);
5201 if (index >= 0) {
5202 r = (HistoryRecord)mHistory.get(index);
5203 r.thumbnail = thumbnail;
5204 r.description = description;
5205 r.stopped = true;
5206 r.state = ActivityState.STOPPED;
5207 if (!r.finishing) {
5208 if (r.configDestroy) {
5209 destroyActivityLocked(r, true);
5210 resumeTopActivityLocked(null);
5211 }
5212 }
5213 }
5214 }
5215
5216 if (r != null) {
5217 sendPendingThumbnail(r, null, null, null, false);
5218 }
5219
5220 trimApplications();
5221
5222 Binder.restoreCallingIdentity(origId);
5223 }
5224
5225 public final void activityDestroyed(IBinder token) {
5226 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5227 synchronized (this) {
5228 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5229
5230 int index = indexOfTokenLocked(token, false);
5231 if (index >= 0) {
5232 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5233 if (r.state == ActivityState.DESTROYING) {
5234 final long origId = Binder.clearCallingIdentity();
5235 removeActivityFromHistoryLocked(r);
5236 Binder.restoreCallingIdentity(origId);
5237 }
5238 }
5239 }
5240 }
5241
5242 public String getCallingPackage(IBinder token) {
5243 synchronized (this) {
5244 HistoryRecord r = getCallingRecordLocked(token);
5245 return r != null && r.app != null ? r.app.processName : null;
5246 }
5247 }
5248
5249 public ComponentName getCallingActivity(IBinder token) {
5250 synchronized (this) {
5251 HistoryRecord r = getCallingRecordLocked(token);
5252 return r != null ? r.intent.getComponent() : null;
5253 }
5254 }
5255
5256 private HistoryRecord getCallingRecordLocked(IBinder token) {
5257 int index = indexOfTokenLocked(token, true);
5258 if (index >= 0) {
5259 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5260 if (r != null) {
5261 return r.resultTo;
5262 }
5263 }
5264 return null;
5265 }
5266
5267 public ComponentName getActivityClassForToken(IBinder token) {
5268 synchronized(this) {
5269 int index = indexOfTokenLocked(token, false);
5270 if (index >= 0) {
5271 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5272 return r.intent.getComponent();
5273 }
5274 return null;
5275 }
5276 }
5277
5278 public String getPackageForToken(IBinder token) {
5279 synchronized(this) {
5280 int index = indexOfTokenLocked(token, false);
5281 if (index >= 0) {
5282 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5283 return r.packageName;
5284 }
5285 return null;
5286 }
5287 }
5288
5289 public IIntentSender getIntentSender(int type,
5290 String packageName, IBinder token, String resultWho,
5291 int requestCode, Intent intent, String resolvedType, int flags) {
5292 // Refuse possible leaked file descriptors
5293 if (intent != null && intent.hasFileDescriptors() == true) {
5294 throw new IllegalArgumentException("File descriptors passed in Intent");
5295 }
5296
5297 synchronized(this) {
5298 int callingUid = Binder.getCallingUid();
5299 try {
5300 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5301 Process.supportsProcesses()) {
5302 int uid = ActivityThread.getPackageManager()
5303 .getPackageUid(packageName);
5304 if (uid != Binder.getCallingUid()) {
5305 String msg = "Permission Denial: getIntentSender() from pid="
5306 + Binder.getCallingPid()
5307 + ", uid=" + Binder.getCallingUid()
5308 + ", (need uid=" + uid + ")"
5309 + " is not allowed to send as package " + packageName;
5310 Log.w(TAG, msg);
5311 throw new SecurityException(msg);
5312 }
5313 }
5314 } catch (RemoteException e) {
5315 throw new SecurityException(e);
5316 }
5317 HistoryRecord activity = null;
5318 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5319 int index = indexOfTokenLocked(token, false);
5320 if (index < 0) {
5321 return null;
5322 }
5323 activity = (HistoryRecord)mHistory.get(index);
5324 if (activity.finishing) {
5325 return null;
5326 }
5327 }
5328
5329 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5330 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5331 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5332 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5333 |PendingIntent.FLAG_UPDATE_CURRENT);
5334
5335 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5336 type, packageName, activity, resultWho,
5337 requestCode, intent, resolvedType, flags);
5338 WeakReference<PendingIntentRecord> ref;
5339 ref = mIntentSenderRecords.get(key);
5340 PendingIntentRecord rec = ref != null ? ref.get() : null;
5341 if (rec != null) {
5342 if (!cancelCurrent) {
5343 if (updateCurrent) {
5344 rec.key.requestIntent.replaceExtras(intent);
5345 }
5346 return rec;
5347 }
5348 rec.canceled = true;
5349 mIntentSenderRecords.remove(key);
5350 }
5351 if (noCreate) {
5352 return rec;
5353 }
5354 rec = new PendingIntentRecord(this, key, callingUid);
5355 mIntentSenderRecords.put(key, rec.ref);
5356 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5357 if (activity.pendingResults == null) {
5358 activity.pendingResults
5359 = new HashSet<WeakReference<PendingIntentRecord>>();
5360 }
5361 activity.pendingResults.add(rec.ref);
5362 }
5363 return rec;
5364 }
5365 }
5366
5367 public void cancelIntentSender(IIntentSender sender) {
5368 if (!(sender instanceof PendingIntentRecord)) {
5369 return;
5370 }
5371 synchronized(this) {
5372 PendingIntentRecord rec = (PendingIntentRecord)sender;
5373 try {
5374 int uid = ActivityThread.getPackageManager()
5375 .getPackageUid(rec.key.packageName);
5376 if (uid != Binder.getCallingUid()) {
5377 String msg = "Permission Denial: cancelIntentSender() from pid="
5378 + Binder.getCallingPid()
5379 + ", uid=" + Binder.getCallingUid()
5380 + " is not allowed to cancel packges "
5381 + rec.key.packageName;
5382 Log.w(TAG, msg);
5383 throw new SecurityException(msg);
5384 }
5385 } catch (RemoteException e) {
5386 throw new SecurityException(e);
5387 }
5388 cancelIntentSenderLocked(rec, true);
5389 }
5390 }
5391
5392 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5393 rec.canceled = true;
5394 mIntentSenderRecords.remove(rec.key);
5395 if (cleanActivity && rec.key.activity != null) {
5396 rec.key.activity.pendingResults.remove(rec.ref);
5397 }
5398 }
5399
5400 public String getPackageForIntentSender(IIntentSender pendingResult) {
5401 if (!(pendingResult instanceof PendingIntentRecord)) {
5402 return null;
5403 }
5404 synchronized(this) {
5405 try {
5406 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5407 return res.key.packageName;
5408 } catch (ClassCastException e) {
5409 }
5410 }
5411 return null;
5412 }
5413
5414 public void setProcessLimit(int max) {
5415 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5416 "setProcessLimit()");
5417 mProcessLimit = max;
5418 }
5419
5420 public int getProcessLimit() {
5421 return mProcessLimit;
5422 }
5423
5424 void foregroundTokenDied(ForegroundToken token) {
5425 synchronized (ActivityManagerService.this) {
5426 synchronized (mPidsSelfLocked) {
5427 ForegroundToken cur
5428 = mForegroundProcesses.get(token.pid);
5429 if (cur != token) {
5430 return;
5431 }
5432 mForegroundProcesses.remove(token.pid);
5433 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5434 if (pr == null) {
5435 return;
5436 }
5437 pr.forcingToForeground = null;
5438 pr.foregroundServices = false;
5439 }
5440 updateOomAdjLocked();
5441 }
5442 }
5443
5444 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5445 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5446 "setProcessForeground()");
5447 synchronized(this) {
5448 boolean changed = false;
5449
5450 synchronized (mPidsSelfLocked) {
5451 ProcessRecord pr = mPidsSelfLocked.get(pid);
5452 if (pr == null) {
5453 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5454 return;
5455 }
5456 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5457 if (oldToken != null) {
5458 oldToken.token.unlinkToDeath(oldToken, 0);
5459 mForegroundProcesses.remove(pid);
5460 pr.forcingToForeground = null;
5461 changed = true;
5462 }
5463 if (isForeground && token != null) {
5464 ForegroundToken newToken = new ForegroundToken() {
5465 public void binderDied() {
5466 foregroundTokenDied(this);
5467 }
5468 };
5469 newToken.pid = pid;
5470 newToken.token = token;
5471 try {
5472 token.linkToDeath(newToken, 0);
5473 mForegroundProcesses.put(pid, newToken);
5474 pr.forcingToForeground = token;
5475 changed = true;
5476 } catch (RemoteException e) {
5477 // If the process died while doing this, we will later
5478 // do the cleanup with the process death link.
5479 }
5480 }
5481 }
5482
5483 if (changed) {
5484 updateOomAdjLocked();
5485 }
5486 }
5487 }
5488
5489 // =========================================================
5490 // PERMISSIONS
5491 // =========================================================
5492
5493 static class PermissionController extends IPermissionController.Stub {
5494 ActivityManagerService mActivityManagerService;
5495 PermissionController(ActivityManagerService activityManagerService) {
5496 mActivityManagerService = activityManagerService;
5497 }
5498
5499 public boolean checkPermission(String permission, int pid, int uid) {
5500 return mActivityManagerService.checkPermission(permission, pid,
5501 uid) == PackageManager.PERMISSION_GRANTED;
5502 }
5503 }
5504
5505 /**
5506 * This can be called with or without the global lock held.
5507 */
5508 int checkComponentPermission(String permission, int pid, int uid,
5509 int reqUid) {
5510 // We might be performing an operation on behalf of an indirect binder
5511 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5512 // client identity accordingly before proceeding.
5513 Identity tlsIdentity = sCallerIdentity.get();
5514 if (tlsIdentity != null) {
5515 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5516 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5517 uid = tlsIdentity.uid;
5518 pid = tlsIdentity.pid;
5519 }
5520
5521 // Root, system server and our own process get to do everything.
5522 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5523 !Process.supportsProcesses()) {
5524 return PackageManager.PERMISSION_GRANTED;
5525 }
5526 // If the target requires a specific UID, always fail for others.
5527 if (reqUid >= 0 && uid != reqUid) {
5528 return PackageManager.PERMISSION_DENIED;
5529 }
5530 if (permission == null) {
5531 return PackageManager.PERMISSION_GRANTED;
5532 }
5533 try {
5534 return ActivityThread.getPackageManager()
5535 .checkUidPermission(permission, uid);
5536 } catch (RemoteException e) {
5537 // Should never happen, but if it does... deny!
5538 Log.e(TAG, "PackageManager is dead?!?", e);
5539 }
5540 return PackageManager.PERMISSION_DENIED;
5541 }
5542
5543 /**
5544 * As the only public entry point for permissions checking, this method
5545 * can enforce the semantic that requesting a check on a null global
5546 * permission is automatically denied. (Internally a null permission
5547 * string is used when calling {@link #checkComponentPermission} in cases
5548 * when only uid-based security is needed.)
5549 *
5550 * This can be called with or without the global lock held.
5551 */
5552 public int checkPermission(String permission, int pid, int uid) {
5553 if (permission == null) {
5554 return PackageManager.PERMISSION_DENIED;
5555 }
5556 return checkComponentPermission(permission, pid, uid, -1);
5557 }
5558
5559 /**
5560 * Binder IPC calls go through the public entry point.
5561 * This can be called with or without the global lock held.
5562 */
5563 int checkCallingPermission(String permission) {
5564 return checkPermission(permission,
5565 Binder.getCallingPid(),
5566 Binder.getCallingUid());
5567 }
5568
5569 /**
5570 * This can be called with or without the global lock held.
5571 */
5572 void enforceCallingPermission(String permission, String func) {
5573 if (checkCallingPermission(permission)
5574 == PackageManager.PERMISSION_GRANTED) {
5575 return;
5576 }
5577
5578 String msg = "Permission Denial: " + func + " from pid="
5579 + Binder.getCallingPid()
5580 + ", uid=" + Binder.getCallingUid()
5581 + " requires " + permission;
5582 Log.w(TAG, msg);
5583 throw new SecurityException(msg);
5584 }
5585
5586 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5587 ProviderInfo pi, int uid, int modeFlags) {
5588 try {
5589 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5590 if ((pi.readPermission != null) &&
5591 (pm.checkUidPermission(pi.readPermission, uid)
5592 != PackageManager.PERMISSION_GRANTED)) {
5593 return false;
5594 }
5595 }
5596 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5597 if ((pi.writePermission != null) &&
5598 (pm.checkUidPermission(pi.writePermission, uid)
5599 != PackageManager.PERMISSION_GRANTED)) {
5600 return false;
5601 }
5602 }
5603 return true;
5604 } catch (RemoteException e) {
5605 return false;
5606 }
5607 }
5608
5609 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5610 int modeFlags) {
5611 // Root gets to do everything.
5612 if (uid == 0 || !Process.supportsProcesses()) {
5613 return true;
5614 }
5615 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5616 if (perms == null) return false;
5617 UriPermission perm = perms.get(uri);
5618 if (perm == null) return false;
5619 return (modeFlags&perm.modeFlags) == modeFlags;
5620 }
5621
5622 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5623 // Another redirected-binder-call permissions check as in
5624 // {@link checkComponentPermission}.
5625 Identity tlsIdentity = sCallerIdentity.get();
5626 if (tlsIdentity != null) {
5627 uid = tlsIdentity.uid;
5628 pid = tlsIdentity.pid;
5629 }
5630
5631 // Our own process gets to do everything.
5632 if (pid == MY_PID) {
5633 return PackageManager.PERMISSION_GRANTED;
5634 }
5635 synchronized(this) {
5636 return checkUriPermissionLocked(uri, uid, modeFlags)
5637 ? PackageManager.PERMISSION_GRANTED
5638 : PackageManager.PERMISSION_DENIED;
5639 }
5640 }
5641
5642 private void grantUriPermissionLocked(int callingUid,
5643 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5644 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5645 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5646 if (modeFlags == 0) {
5647 return;
5648 }
5649
5650 final IPackageManager pm = ActivityThread.getPackageManager();
5651
5652 // If this is not a content: uri, we can't do anything with it.
5653 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5654 return;
5655 }
5656
5657 String name = uri.getAuthority();
5658 ProviderInfo pi = null;
5659 ContentProviderRecord cpr
5660 = (ContentProviderRecord)mProvidersByName.get(name);
5661 if (cpr != null) {
5662 pi = cpr.info;
5663 } else {
5664 try {
5665 pi = pm.resolveContentProvider(name,
5666 PackageManager.GET_URI_PERMISSION_PATTERNS);
5667 } catch (RemoteException ex) {
5668 }
5669 }
5670 if (pi == null) {
5671 Log.w(TAG, "No content provider found for: " + name);
5672 return;
5673 }
5674
5675 int targetUid;
5676 try {
5677 targetUid = pm.getPackageUid(targetPkg);
5678 if (targetUid < 0) {
5679 return;
5680 }
5681 } catch (RemoteException ex) {
5682 return;
5683 }
5684
5685 // First... does the target actually need this permission?
5686 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5687 // No need to grant the target this permission.
5688 return;
5689 }
5690
5691 // Second... maybe someone else has already granted the
5692 // permission?
5693 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5694 // No need to grant the target this permission.
5695 return;
5696 }
5697
5698 // Third... is the provider allowing granting of URI permissions?
5699 if (!pi.grantUriPermissions) {
5700 throw new SecurityException("Provider " + pi.packageName
5701 + "/" + pi.name
5702 + " does not allow granting of Uri permissions (uri "
5703 + uri + ")");
5704 }
5705 if (pi.uriPermissionPatterns != null) {
5706 final int N = pi.uriPermissionPatterns.length;
5707 boolean allowed = false;
5708 for (int i=0; i<N; i++) {
5709 if (pi.uriPermissionPatterns[i] != null
5710 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5711 allowed = true;
5712 break;
5713 }
5714 }
5715 if (!allowed) {
5716 throw new SecurityException("Provider " + pi.packageName
5717 + "/" + pi.name
5718 + " does not allow granting of permission to path of Uri "
5719 + uri);
5720 }
5721 }
5722
5723 // Fourth... does the caller itself have permission to access
5724 // this uri?
5725 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5726 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5727 throw new SecurityException("Uid " + callingUid
5728 + " does not have permission to uri " + uri);
5729 }
5730 }
5731
5732 // Okay! So here we are: the caller has the assumed permission
5733 // to the uri, and the target doesn't. Let's now give this to
5734 // the target.
5735
5736 HashMap<Uri, UriPermission> targetUris
5737 = mGrantedUriPermissions.get(targetUid);
5738 if (targetUris == null) {
5739 targetUris = new HashMap<Uri, UriPermission>();
5740 mGrantedUriPermissions.put(targetUid, targetUris);
5741 }
5742
5743 UriPermission perm = targetUris.get(uri);
5744 if (perm == null) {
5745 perm = new UriPermission(targetUid, uri);
5746 targetUris.put(uri, perm);
5747
5748 }
5749 perm.modeFlags |= modeFlags;
5750 if (activity == null) {
5751 perm.globalModeFlags |= modeFlags;
5752 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5753 perm.readActivities.add(activity);
5754 if (activity.readUriPermissions == null) {
5755 activity.readUriPermissions = new HashSet<UriPermission>();
5756 }
5757 activity.readUriPermissions.add(perm);
5758 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5759 perm.writeActivities.add(activity);
5760 if (activity.writeUriPermissions == null) {
5761 activity.writeUriPermissions = new HashSet<UriPermission>();
5762 }
5763 activity.writeUriPermissions.add(perm);
5764 }
5765 }
5766
5767 private void grantUriPermissionFromIntentLocked(int callingUid,
5768 String targetPkg, Intent intent, HistoryRecord activity) {
5769 if (intent == null) {
5770 return;
5771 }
5772 Uri data = intent.getData();
5773 if (data == null) {
5774 return;
5775 }
5776 grantUriPermissionLocked(callingUid, targetPkg, data,
5777 intent.getFlags(), activity);
5778 }
5779
5780 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5781 Uri uri, int modeFlags) {
5782 synchronized(this) {
5783 final ProcessRecord r = getRecordForAppLocked(caller);
5784 if (r == null) {
5785 throw new SecurityException("Unable to find app for caller "
5786 + caller
5787 + " when granting permission to uri " + uri);
5788 }
5789 if (targetPkg == null) {
5790 Log.w(TAG, "grantUriPermission: null target");
5791 return;
5792 }
5793 if (uri == null) {
5794 Log.w(TAG, "grantUriPermission: null uri");
5795 return;
5796 }
5797
5798 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5799 null);
5800 }
5801 }
5802
5803 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5804 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5805 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5806 HashMap<Uri, UriPermission> perms
5807 = mGrantedUriPermissions.get(perm.uid);
5808 if (perms != null) {
5809 perms.remove(perm.uri);
5810 if (perms.size() == 0) {
5811 mGrantedUriPermissions.remove(perm.uid);
5812 }
5813 }
5814 }
5815 }
5816
5817 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5818 if (activity.readUriPermissions != null) {
5819 for (UriPermission perm : activity.readUriPermissions) {
5820 perm.readActivities.remove(activity);
5821 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5822 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5823 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5824 removeUriPermissionIfNeededLocked(perm);
5825 }
5826 }
5827 }
5828 if (activity.writeUriPermissions != null) {
5829 for (UriPermission perm : activity.writeUriPermissions) {
5830 perm.writeActivities.remove(activity);
5831 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5832 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5833 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5834 removeUriPermissionIfNeededLocked(perm);
5835 }
5836 }
5837 }
5838 }
5839
5840 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5841 int modeFlags) {
5842 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5843 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5844 if (modeFlags == 0) {
5845 return;
5846 }
5847
5848 final IPackageManager pm = ActivityThread.getPackageManager();
5849
5850 final String authority = uri.getAuthority();
5851 ProviderInfo pi = null;
5852 ContentProviderRecord cpr
5853 = (ContentProviderRecord)mProvidersByName.get(authority);
5854 if (cpr != null) {
5855 pi = cpr.info;
5856 } else {
5857 try {
5858 pi = pm.resolveContentProvider(authority,
5859 PackageManager.GET_URI_PERMISSION_PATTERNS);
5860 } catch (RemoteException ex) {
5861 }
5862 }
5863 if (pi == null) {
5864 Log.w(TAG, "No content provider found for: " + authority);
5865 return;
5866 }
5867
5868 // Does the caller have this permission on the URI?
5869 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5870 // Right now, if you are not the original owner of the permission,
5871 // you are not allowed to revoke it.
5872 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5873 throw new SecurityException("Uid " + callingUid
5874 + " does not have permission to uri " + uri);
5875 //}
5876 }
5877
5878 // Go through all of the permissions and remove any that match.
5879 final List<String> SEGMENTS = uri.getPathSegments();
5880 if (SEGMENTS != null) {
5881 final int NS = SEGMENTS.size();
5882 int N = mGrantedUriPermissions.size();
5883 for (int i=0; i<N; i++) {
5884 HashMap<Uri, UriPermission> perms
5885 = mGrantedUriPermissions.valueAt(i);
5886 Iterator<UriPermission> it = perms.values().iterator();
5887 toploop:
5888 while (it.hasNext()) {
5889 UriPermission perm = it.next();
5890 Uri targetUri = perm.uri;
5891 if (!authority.equals(targetUri.getAuthority())) {
5892 continue;
5893 }
5894 List<String> targetSegments = targetUri.getPathSegments();
5895 if (targetSegments == null) {
5896 continue;
5897 }
5898 if (targetSegments.size() < NS) {
5899 continue;
5900 }
5901 for (int j=0; j<NS; j++) {
5902 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5903 continue toploop;
5904 }
5905 }
5906 perm.clearModes(modeFlags);
5907 if (perm.modeFlags == 0) {
5908 it.remove();
5909 }
5910 }
5911 if (perms.size() == 0) {
5912 mGrantedUriPermissions.remove(
5913 mGrantedUriPermissions.keyAt(i));
5914 N--;
5915 i--;
5916 }
5917 }
5918 }
5919 }
5920
5921 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5922 int modeFlags) {
5923 synchronized(this) {
5924 final ProcessRecord r = getRecordForAppLocked(caller);
5925 if (r == null) {
5926 throw new SecurityException("Unable to find app for caller "
5927 + caller
5928 + " when revoking permission to uri " + uri);
5929 }
5930 if (uri == null) {
5931 Log.w(TAG, "revokeUriPermission: null uri");
5932 return;
5933 }
5934
5935 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5936 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5937 if (modeFlags == 0) {
5938 return;
5939 }
5940
5941 final IPackageManager pm = ActivityThread.getPackageManager();
5942
5943 final String authority = uri.getAuthority();
5944 ProviderInfo pi = null;
5945 ContentProviderRecord cpr
5946 = (ContentProviderRecord)mProvidersByName.get(authority);
5947 if (cpr != null) {
5948 pi = cpr.info;
5949 } else {
5950 try {
5951 pi = pm.resolveContentProvider(authority,
5952 PackageManager.GET_URI_PERMISSION_PATTERNS);
5953 } catch (RemoteException ex) {
5954 }
5955 }
5956 if (pi == null) {
5957 Log.w(TAG, "No content provider found for: " + authority);
5958 return;
5959 }
5960
5961 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
5962 }
5963 }
5964
5965 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
5966 synchronized (this) {
5967 ProcessRecord app =
5968 who != null ? getRecordForAppLocked(who) : null;
5969 if (app == null) return;
5970
5971 Message msg = Message.obtain();
5972 msg.what = WAIT_FOR_DEBUGGER_MSG;
5973 msg.obj = app;
5974 msg.arg1 = waiting ? 1 : 0;
5975 mHandler.sendMessage(msg);
5976 }
5977 }
5978
5979 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
5980 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08005981 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005982 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08005983 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005984 }
5985
5986 // =========================================================
5987 // TASK MANAGEMENT
5988 // =========================================================
5989
5990 public List getTasks(int maxNum, int flags,
5991 IThumbnailReceiver receiver) {
5992 ArrayList list = new ArrayList();
5993
5994 PendingThumbnailsRecord pending = null;
5995 IApplicationThread topThumbnail = null;
5996 HistoryRecord topRecord = null;
5997
5998 synchronized(this) {
5999 if (localLOGV) Log.v(
6000 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6001 + ", receiver=" + receiver);
6002
6003 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6004 != PackageManager.PERMISSION_GRANTED) {
6005 if (receiver != null) {
6006 // If the caller wants to wait for pending thumbnails,
6007 // it ain't gonna get them.
6008 try {
6009 receiver.finished();
6010 } catch (RemoteException ex) {
6011 }
6012 }
6013 String msg = "Permission Denial: getTasks() from pid="
6014 + Binder.getCallingPid()
6015 + ", uid=" + Binder.getCallingUid()
6016 + " requires " + android.Manifest.permission.GET_TASKS;
6017 Log.w(TAG, msg);
6018 throw new SecurityException(msg);
6019 }
6020
6021 int pos = mHistory.size()-1;
6022 HistoryRecord next =
6023 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6024 HistoryRecord top = null;
6025 CharSequence topDescription = null;
6026 TaskRecord curTask = null;
6027 int numActivities = 0;
6028 int numRunning = 0;
6029 while (pos >= 0 && maxNum > 0) {
6030 final HistoryRecord r = next;
6031 pos--;
6032 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6033
6034 // Initialize state for next task if needed.
6035 if (top == null ||
6036 (top.state == ActivityState.INITIALIZING
6037 && top.task == r.task)) {
6038 top = r;
6039 topDescription = r.description;
6040 curTask = r.task;
6041 numActivities = numRunning = 0;
6042 }
6043
6044 // Add 'r' into the current task.
6045 numActivities++;
6046 if (r.app != null && r.app.thread != null) {
6047 numRunning++;
6048 }
6049 if (topDescription == null) {
6050 topDescription = r.description;
6051 }
6052
6053 if (localLOGV) Log.v(
6054 TAG, r.intent.getComponent().flattenToShortString()
6055 + ": task=" + r.task);
6056
6057 // If the next one is a different task, generate a new
6058 // TaskInfo entry for what we have.
6059 if (next == null || next.task != curTask) {
6060 ActivityManager.RunningTaskInfo ci
6061 = new ActivityManager.RunningTaskInfo();
6062 ci.id = curTask.taskId;
6063 ci.baseActivity = r.intent.getComponent();
6064 ci.topActivity = top.intent.getComponent();
6065 ci.thumbnail = top.thumbnail;
6066 ci.description = topDescription;
6067 ci.numActivities = numActivities;
6068 ci.numRunning = numRunning;
6069 //System.out.println(
6070 // "#" + maxNum + ": " + " descr=" + ci.description);
6071 if (ci.thumbnail == null && receiver != null) {
6072 if (localLOGV) Log.v(
6073 TAG, "State=" + top.state + "Idle=" + top.idle
6074 + " app=" + top.app
6075 + " thr=" + (top.app != null ? top.app.thread : null));
6076 if (top.state == ActivityState.RESUMED
6077 || top.state == ActivityState.PAUSING) {
6078 if (top.idle && top.app != null
6079 && top.app.thread != null) {
6080 topRecord = top;
6081 topThumbnail = top.app.thread;
6082 } else {
6083 top.thumbnailNeeded = true;
6084 }
6085 }
6086 if (pending == null) {
6087 pending = new PendingThumbnailsRecord(receiver);
6088 }
6089 pending.pendingRecords.add(top);
6090 }
6091 list.add(ci);
6092 maxNum--;
6093 top = null;
6094 }
6095 }
6096
6097 if (pending != null) {
6098 mPendingThumbnails.add(pending);
6099 }
6100 }
6101
6102 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6103
6104 if (topThumbnail != null) {
6105 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6106 try {
6107 topThumbnail.requestThumbnail(topRecord);
6108 } catch (Exception e) {
6109 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6110 sendPendingThumbnail(null, topRecord, null, null, true);
6111 }
6112 }
6113
6114 if (pending == null && receiver != null) {
6115 // In this case all thumbnails were available and the client
6116 // is being asked to be told when the remaining ones come in...
6117 // which is unusually, since the top-most currently running
6118 // activity should never have a canned thumbnail! Oh well.
6119 try {
6120 receiver.finished();
6121 } catch (RemoteException ex) {
6122 }
6123 }
6124
6125 return list;
6126 }
6127
6128 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6129 int flags) {
6130 synchronized (this) {
6131 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6132 "getRecentTasks()");
6133
6134 final int N = mRecentTasks.size();
6135 ArrayList<ActivityManager.RecentTaskInfo> res
6136 = new ArrayList<ActivityManager.RecentTaskInfo>(
6137 maxNum < N ? maxNum : N);
6138 for (int i=0; i<N && maxNum > 0; i++) {
6139 TaskRecord tr = mRecentTasks.get(i);
6140 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6141 || (tr.intent == null)
6142 || ((tr.intent.getFlags()
6143 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6144 ActivityManager.RecentTaskInfo rti
6145 = new ActivityManager.RecentTaskInfo();
6146 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6147 rti.baseIntent = new Intent(
6148 tr.intent != null ? tr.intent : tr.affinityIntent);
6149 rti.origActivity = tr.origActivity;
6150 res.add(rti);
6151 maxNum--;
6152 }
6153 }
6154 return res;
6155 }
6156 }
6157
6158 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6159 int j;
6160 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6161 TaskRecord jt = startTask;
6162
6163 // First look backwards
6164 for (j=startIndex-1; j>=0; j--) {
6165 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6166 if (r.task != jt) {
6167 jt = r.task;
6168 if (affinity.equals(jt.affinity)) {
6169 return j;
6170 }
6171 }
6172 }
6173
6174 // Now look forwards
6175 final int N = mHistory.size();
6176 jt = startTask;
6177 for (j=startIndex+1; j<N; j++) {
6178 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6179 if (r.task != jt) {
6180 if (affinity.equals(jt.affinity)) {
6181 return j;
6182 }
6183 jt = r.task;
6184 }
6185 }
6186
6187 // Might it be at the top?
6188 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6189 return N-1;
6190 }
6191
6192 return -1;
6193 }
6194
6195 /**
6196 * Perform a reset of the given task, if needed as part of launching it.
6197 * Returns the new HistoryRecord at the top of the task.
6198 */
6199 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6200 HistoryRecord newActivity) {
6201 boolean forceReset = (newActivity.info.flags
6202 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6203 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6204 if ((newActivity.info.flags
6205 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6206 forceReset = true;
6207 }
6208 }
6209
6210 final TaskRecord task = taskTop.task;
6211
6212 // We are going to move through the history list so that we can look
6213 // at each activity 'target' with 'below' either the interesting
6214 // activity immediately below it in the stack or null.
6215 HistoryRecord target = null;
6216 int targetI = 0;
6217 int taskTopI = -1;
6218 int replyChainEnd = -1;
6219 int lastReparentPos = -1;
6220 for (int i=mHistory.size()-1; i>=-1; i--) {
6221 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6222
6223 if (below != null && below.finishing) {
6224 continue;
6225 }
6226 if (target == null) {
6227 target = below;
6228 targetI = i;
6229 // If we were in the middle of a reply chain before this
6230 // task, it doesn't appear like the root of the chain wants
6231 // anything interesting, so drop it.
6232 replyChainEnd = -1;
6233 continue;
6234 }
6235
6236 final int flags = target.info.flags;
6237
6238 final boolean finishOnTaskLaunch =
6239 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6240 final boolean allowTaskReparenting =
6241 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6242
6243 if (target.task == task) {
6244 // We are inside of the task being reset... we'll either
6245 // finish this activity, push it out for another task,
6246 // or leave it as-is. We only do this
6247 // for activities that are not the root of the task (since
6248 // if we finish the root, we may no longer have the task!).
6249 if (taskTopI < 0) {
6250 taskTopI = targetI;
6251 }
6252 if (below != null && below.task == task) {
6253 final boolean clearWhenTaskReset =
6254 (target.intent.getFlags()
6255 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006256 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006257 // If this activity is sending a reply to a previous
6258 // activity, we can't do anything with it now until
6259 // we reach the start of the reply chain.
6260 // XXX note that we are assuming the result is always
6261 // to the previous activity, which is almost always
6262 // the case but we really shouldn't count on.
6263 if (replyChainEnd < 0) {
6264 replyChainEnd = targetI;
6265 }
Ed Heyl73798232009-03-24 21:32:21 -07006266 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006267 && target.taskAffinity != null
6268 && !target.taskAffinity.equals(task.affinity)) {
6269 // If this activity has an affinity for another
6270 // task, then we need to move it out of here. We will
6271 // move it as far out of the way as possible, to the
6272 // bottom of the activity stack. This also keeps it
6273 // correctly ordered with any activities we previously
6274 // moved.
6275 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6276 if (target.taskAffinity != null
6277 && target.taskAffinity.equals(p.task.affinity)) {
6278 // If the activity currently at the bottom has the
6279 // same task affinity as the one we are moving,
6280 // then merge it into the same task.
6281 target.task = p.task;
6282 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6283 + " out to bottom task " + p.task);
6284 } else {
6285 mCurTask++;
6286 if (mCurTask <= 0) {
6287 mCurTask = 1;
6288 }
6289 target.task = new TaskRecord(mCurTask, target.info, null,
6290 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6291 target.task.affinityIntent = target.intent;
6292 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6293 + " out to new task " + target.task);
6294 }
6295 mWindowManager.setAppGroupId(target, task.taskId);
6296 if (replyChainEnd < 0) {
6297 replyChainEnd = targetI;
6298 }
6299 int dstPos = 0;
6300 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6301 p = (HistoryRecord)mHistory.get(srcPos);
6302 if (p.finishing) {
6303 continue;
6304 }
6305 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6306 + " out to target's task " + target.task);
6307 task.numActivities--;
6308 p.task = target.task;
6309 target.task.numActivities++;
6310 mHistory.remove(srcPos);
6311 mHistory.add(dstPos, p);
6312 mWindowManager.moveAppToken(dstPos, p);
6313 mWindowManager.setAppGroupId(p, p.task.taskId);
6314 dstPos++;
6315 if (VALIDATE_TOKENS) {
6316 mWindowManager.validateAppTokens(mHistory);
6317 }
6318 i++;
6319 }
6320 if (taskTop == p) {
6321 taskTop = below;
6322 }
6323 if (taskTopI == replyChainEnd) {
6324 taskTopI = -1;
6325 }
6326 replyChainEnd = -1;
6327 addRecentTask(target.task);
6328 } else if (forceReset || finishOnTaskLaunch
6329 || clearWhenTaskReset) {
6330 // If the activity should just be removed -- either
6331 // because it asks for it, or the task should be
6332 // cleared -- then finish it and anything that is
6333 // part of its reply chain.
6334 if (clearWhenTaskReset) {
6335 // In this case, we want to finish this activity
6336 // and everything above it, so be sneaky and pretend
6337 // like these are all in the reply chain.
6338 replyChainEnd = targetI+1;
6339 while (replyChainEnd < mHistory.size() &&
6340 ((HistoryRecord)mHistory.get(
6341 replyChainEnd)).task == task) {
6342 replyChainEnd++;
6343 }
6344 replyChainEnd--;
6345 } else if (replyChainEnd < 0) {
6346 replyChainEnd = targetI;
6347 }
6348 HistoryRecord p = null;
6349 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6350 p = (HistoryRecord)mHistory.get(srcPos);
6351 if (p.finishing) {
6352 continue;
6353 }
6354 if (finishActivityLocked(p, srcPos,
6355 Activity.RESULT_CANCELED, null, "reset")) {
6356 replyChainEnd--;
6357 srcPos--;
6358 }
6359 }
6360 if (taskTop == p) {
6361 taskTop = below;
6362 }
6363 if (taskTopI == replyChainEnd) {
6364 taskTopI = -1;
6365 }
6366 replyChainEnd = -1;
6367 } else {
6368 // If we were in the middle of a chain, well the
6369 // activity that started it all doesn't want anything
6370 // special, so leave it all as-is.
6371 replyChainEnd = -1;
6372 }
6373 } else {
6374 // Reached the bottom of the task -- any reply chain
6375 // should be left as-is.
6376 replyChainEnd = -1;
6377 }
6378
6379 } else if (target.resultTo != null) {
6380 // If this activity is sending a reply to a previous
6381 // activity, we can't do anything with it now until
6382 // we reach the start of the reply chain.
6383 // XXX note that we are assuming the result is always
6384 // to the previous activity, which is almost always
6385 // the case but we really shouldn't count on.
6386 if (replyChainEnd < 0) {
6387 replyChainEnd = targetI;
6388 }
6389
6390 } else if (taskTopI >= 0 && allowTaskReparenting
6391 && task.affinity != null
6392 && task.affinity.equals(target.taskAffinity)) {
6393 // We are inside of another task... if this activity has
6394 // an affinity for our task, then either remove it if we are
6395 // clearing or move it over to our task. Note that
6396 // we currently punt on the case where we are resetting a
6397 // task that is not at the top but who has activities above
6398 // with an affinity to it... this is really not a normal
6399 // case, and we will need to later pull that task to the front
6400 // and usually at that point we will do the reset and pick
6401 // up those remaining activities. (This only happens if
6402 // someone starts an activity in a new task from an activity
6403 // in a task that is not currently on top.)
6404 if (forceReset || finishOnTaskLaunch) {
6405 if (replyChainEnd < 0) {
6406 replyChainEnd = targetI;
6407 }
6408 HistoryRecord p = null;
6409 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6410 p = (HistoryRecord)mHistory.get(srcPos);
6411 if (p.finishing) {
6412 continue;
6413 }
6414 if (finishActivityLocked(p, srcPos,
6415 Activity.RESULT_CANCELED, null, "reset")) {
6416 taskTopI--;
6417 lastReparentPos--;
6418 replyChainEnd--;
6419 srcPos--;
6420 }
6421 }
6422 replyChainEnd = -1;
6423 } else {
6424 if (replyChainEnd < 0) {
6425 replyChainEnd = targetI;
6426 }
6427 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6428 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6429 if (p.finishing) {
6430 continue;
6431 }
6432 if (lastReparentPos < 0) {
6433 lastReparentPos = taskTopI;
6434 taskTop = p;
6435 } else {
6436 lastReparentPos--;
6437 }
6438 mHistory.remove(srcPos);
6439 p.task.numActivities--;
6440 p.task = task;
6441 mHistory.add(lastReparentPos, p);
6442 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6443 + " in to resetting task " + task);
6444 task.numActivities++;
6445 mWindowManager.moveAppToken(lastReparentPos, p);
6446 mWindowManager.setAppGroupId(p, p.task.taskId);
6447 if (VALIDATE_TOKENS) {
6448 mWindowManager.validateAppTokens(mHistory);
6449 }
6450 }
6451 replyChainEnd = -1;
6452
6453 // Now we've moved it in to place... but what if this is
6454 // a singleTop activity and we have put it on top of another
6455 // instance of the same activity? Then we drop the instance
6456 // below so it remains singleTop.
6457 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6458 for (int j=lastReparentPos-1; j>=0; j--) {
6459 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6460 if (p.finishing) {
6461 continue;
6462 }
6463 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6464 if (finishActivityLocked(p, j,
6465 Activity.RESULT_CANCELED, null, "replace")) {
6466 taskTopI--;
6467 lastReparentPos--;
6468 }
6469 }
6470 }
6471 }
6472 }
6473 }
6474
6475 target = below;
6476 targetI = i;
6477 }
6478
6479 return taskTop;
6480 }
6481
6482 /**
6483 * TODO: Add mWatcher hook
6484 */
6485 public void moveTaskToFront(int task) {
6486 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6487 "moveTaskToFront()");
6488
6489 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006490 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6491 Binder.getCallingUid(), "Task to front")) {
6492 return;
6493 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006494 final long origId = Binder.clearCallingIdentity();
6495 try {
6496 int N = mRecentTasks.size();
6497 for (int i=0; i<N; i++) {
6498 TaskRecord tr = mRecentTasks.get(i);
6499 if (tr.taskId == task) {
6500 moveTaskToFrontLocked(tr);
6501 return;
6502 }
6503 }
6504 for (int i=mHistory.size()-1; i>=0; i--) {
6505 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6506 if (hr.task.taskId == task) {
6507 moveTaskToFrontLocked(hr.task);
6508 return;
6509 }
6510 }
6511 } finally {
6512 Binder.restoreCallingIdentity(origId);
6513 }
6514 }
6515 }
6516
6517 private final void moveTaskToFrontLocked(TaskRecord tr) {
6518 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6519
6520 final int task = tr.taskId;
6521 int top = mHistory.size()-1;
6522
6523 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6524 // nothing to do!
6525 return;
6526 }
6527
6528 if (DEBUG_TRANSITION) Log.v(TAG,
6529 "Prepare to front transition: task=" + tr);
6530 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6531
6532 ArrayList moved = new ArrayList();
6533
6534 // Applying the affinities may have removed entries from the history,
6535 // so get the size again.
6536 top = mHistory.size()-1;
6537 int pos = top;
6538
6539 // Shift all activities with this task up to the top
6540 // of the stack, keeping them in the same internal order.
6541 while (pos >= 0) {
6542 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6543 if (localLOGV) Log.v(
6544 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6545 boolean first = true;
6546 if (r.task.taskId == task) {
6547 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6548 mHistory.remove(pos);
6549 mHistory.add(top, r);
6550 moved.add(0, r);
6551 top--;
6552 if (first) {
6553 addRecentTask(r.task);
6554 first = false;
6555 }
6556 }
6557 pos--;
6558 }
6559
6560 mWindowManager.moveAppTokensToTop(moved);
6561 if (VALIDATE_TOKENS) {
6562 mWindowManager.validateAppTokens(mHistory);
6563 }
6564
6565 finishTaskMove(task);
6566 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6567 }
6568
6569 private final void finishTaskMove(int task) {
6570 resumeTopActivityLocked(null);
6571 }
6572
6573 public void moveTaskToBack(int task) {
6574 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6575 "moveTaskToBack()");
6576
6577 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006578 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6579 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6580 Binder.getCallingUid(), "Task to back")) {
6581 return;
6582 }
6583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006584 final long origId = Binder.clearCallingIdentity();
6585 moveTaskToBackLocked(task);
6586 Binder.restoreCallingIdentity(origId);
6587 }
6588 }
6589
6590 /**
6591 * Moves an activity, and all of the other activities within the same task, to the bottom
6592 * of the history stack. The activity's order within the task is unchanged.
6593 *
6594 * @param token A reference to the activity we wish to move
6595 * @param nonRoot If false then this only works if the activity is the root
6596 * of a task; if true it will work for any activity in a task.
6597 * @return Returns true if the move completed, false if not.
6598 */
6599 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6600 synchronized(this) {
6601 final long origId = Binder.clearCallingIdentity();
6602 int taskId = getTaskForActivityLocked(token, !nonRoot);
6603 if (taskId >= 0) {
6604 return moveTaskToBackLocked(taskId);
6605 }
6606 Binder.restoreCallingIdentity(origId);
6607 }
6608 return false;
6609 }
6610
6611 /**
6612 * Worker method for rearranging history stack. Implements the function of moving all
6613 * activities for a specific task (gathering them if disjoint) into a single group at the
6614 * bottom of the stack.
6615 *
6616 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6617 * to premeptively cancel the move.
6618 *
6619 * @param task The taskId to collect and move to the bottom.
6620 * @return Returns true if the move completed, false if not.
6621 */
6622 private final boolean moveTaskToBackLocked(int task) {
6623 Log.i(TAG, "moveTaskToBack: " + task);
6624
6625 // If we have a watcher, preflight the move before committing to it. First check
6626 // for *other* available tasks, but if none are available, then try again allowing the
6627 // current task to be selected.
6628 if (mWatcher != null) {
6629 HistoryRecord next = topRunningActivityLocked(null, task);
6630 if (next == null) {
6631 next = topRunningActivityLocked(null, 0);
6632 }
6633 if (next != null) {
6634 // ask watcher if this is allowed
6635 boolean moveOK = true;
6636 try {
6637 moveOK = mWatcher.activityResuming(next.packageName);
6638 } catch (RemoteException e) {
6639 mWatcher = null;
6640 }
6641 if (!moveOK) {
6642 return false;
6643 }
6644 }
6645 }
6646
6647 ArrayList moved = new ArrayList();
6648
6649 if (DEBUG_TRANSITION) Log.v(TAG,
6650 "Prepare to back transition: task=" + task);
6651 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6652
6653 final int N = mHistory.size();
6654 int bottom = 0;
6655 int pos = 0;
6656
6657 // Shift all activities with this task down to the bottom
6658 // of the stack, keeping them in the same internal order.
6659 while (pos < N) {
6660 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6661 if (localLOGV) Log.v(
6662 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6663 if (r.task.taskId == task) {
6664 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6665 mHistory.remove(pos);
6666 mHistory.add(bottom, r);
6667 moved.add(r);
6668 bottom++;
6669 }
6670 pos++;
6671 }
6672
6673 mWindowManager.moveAppTokensToBottom(moved);
6674 if (VALIDATE_TOKENS) {
6675 mWindowManager.validateAppTokens(mHistory);
6676 }
6677
6678 finishTaskMove(task);
6679 return true;
6680 }
6681
6682 public void moveTaskBackwards(int task) {
6683 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6684 "moveTaskBackwards()");
6685
6686 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006687 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6688 Binder.getCallingUid(), "Task backwards")) {
6689 return;
6690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006691 final long origId = Binder.clearCallingIdentity();
6692 moveTaskBackwardsLocked(task);
6693 Binder.restoreCallingIdentity(origId);
6694 }
6695 }
6696
6697 private final void moveTaskBackwardsLocked(int task) {
6698 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6699 }
6700
6701 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6702 synchronized(this) {
6703 return getTaskForActivityLocked(token, onlyRoot);
6704 }
6705 }
6706
6707 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6708 final int N = mHistory.size();
6709 TaskRecord lastTask = null;
6710 for (int i=0; i<N; i++) {
6711 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6712 if (r == token) {
6713 if (!onlyRoot || lastTask != r.task) {
6714 return r.task.taskId;
6715 }
6716 return -1;
6717 }
6718 lastTask = r.task;
6719 }
6720
6721 return -1;
6722 }
6723
6724 /**
6725 * Returns the top activity in any existing task matching the given
6726 * Intent. Returns null if no such task is found.
6727 */
6728 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6729 ComponentName cls = intent.getComponent();
6730 if (info.targetActivity != null) {
6731 cls = new ComponentName(info.packageName, info.targetActivity);
6732 }
6733
6734 TaskRecord cp = null;
6735
6736 final int N = mHistory.size();
6737 for (int i=(N-1); i>=0; i--) {
6738 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6739 if (!r.finishing && r.task != cp
6740 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6741 cp = r.task;
6742 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6743 // + "/aff=" + r.task.affinity + " to new cls="
6744 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6745 if (r.task.affinity != null) {
6746 if (r.task.affinity.equals(info.taskAffinity)) {
6747 //Log.i(TAG, "Found matching affinity!");
6748 return r;
6749 }
6750 } else if (r.task.intent != null
6751 && r.task.intent.getComponent().equals(cls)) {
6752 //Log.i(TAG, "Found matching class!");
6753 //dump();
6754 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6755 return r;
6756 } else if (r.task.affinityIntent != null
6757 && r.task.affinityIntent.getComponent().equals(cls)) {
6758 //Log.i(TAG, "Found matching class!");
6759 //dump();
6760 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6761 return r;
6762 }
6763 }
6764 }
6765
6766 return null;
6767 }
6768
6769 /**
6770 * Returns the first activity (starting from the top of the stack) that
6771 * is the same as the given activity. Returns null if no such activity
6772 * is found.
6773 */
6774 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6775 ComponentName cls = intent.getComponent();
6776 if (info.targetActivity != null) {
6777 cls = new ComponentName(info.packageName, info.targetActivity);
6778 }
6779
6780 final int N = mHistory.size();
6781 for (int i=(N-1); i>=0; i--) {
6782 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6783 if (!r.finishing) {
6784 if (r.intent.getComponent().equals(cls)) {
6785 //Log.i(TAG, "Found matching class!");
6786 //dump();
6787 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6788 return r;
6789 }
6790 }
6791 }
6792
6793 return null;
6794 }
6795
6796 public void finishOtherInstances(IBinder token, ComponentName className) {
6797 synchronized(this) {
6798 final long origId = Binder.clearCallingIdentity();
6799
6800 int N = mHistory.size();
6801 TaskRecord lastTask = null;
6802 for (int i=0; i<N; i++) {
6803 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6804 if (r.realActivity.equals(className)
6805 && r != token && lastTask != r.task) {
6806 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6807 null, "others")) {
6808 i--;
6809 N--;
6810 }
6811 }
6812 lastTask = r.task;
6813 }
6814
6815 Binder.restoreCallingIdentity(origId);
6816 }
6817 }
6818
6819 // =========================================================
6820 // THUMBNAILS
6821 // =========================================================
6822
6823 public void reportThumbnail(IBinder token,
6824 Bitmap thumbnail, CharSequence description) {
6825 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6826 final long origId = Binder.clearCallingIdentity();
6827 sendPendingThumbnail(null, token, thumbnail, description, true);
6828 Binder.restoreCallingIdentity(origId);
6829 }
6830
6831 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6832 Bitmap thumbnail, CharSequence description, boolean always) {
6833 TaskRecord task = null;
6834 ArrayList receivers = null;
6835
6836 //System.out.println("Send pending thumbnail: " + r);
6837
6838 synchronized(this) {
6839 if (r == null) {
6840 int index = indexOfTokenLocked(token, false);
6841 if (index < 0) {
6842 return;
6843 }
6844 r = (HistoryRecord)mHistory.get(index);
6845 }
6846 if (thumbnail == null) {
6847 thumbnail = r.thumbnail;
6848 description = r.description;
6849 }
6850 if (thumbnail == null && !always) {
6851 // If there is no thumbnail, and this entry is not actually
6852 // going away, then abort for now and pick up the next
6853 // thumbnail we get.
6854 return;
6855 }
6856 task = r.task;
6857
6858 int N = mPendingThumbnails.size();
6859 int i=0;
6860 while (i<N) {
6861 PendingThumbnailsRecord pr =
6862 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6863 //System.out.println("Looking in " + pr.pendingRecords);
6864 if (pr.pendingRecords.remove(r)) {
6865 if (receivers == null) {
6866 receivers = new ArrayList();
6867 }
6868 receivers.add(pr);
6869 if (pr.pendingRecords.size() == 0) {
6870 pr.finished = true;
6871 mPendingThumbnails.remove(i);
6872 N--;
6873 continue;
6874 }
6875 }
6876 i++;
6877 }
6878 }
6879
6880 if (receivers != null) {
6881 final int N = receivers.size();
6882 for (int i=0; i<N; i++) {
6883 try {
6884 PendingThumbnailsRecord pr =
6885 (PendingThumbnailsRecord)receivers.get(i);
6886 pr.receiver.newThumbnail(
6887 task != null ? task.taskId : -1, thumbnail, description);
6888 if (pr.finished) {
6889 pr.receiver.finished();
6890 }
6891 } catch (Exception e) {
6892 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6893 }
6894 }
6895 }
6896 }
6897
6898 // =========================================================
6899 // CONTENT PROVIDERS
6900 // =========================================================
6901
6902 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6903 List providers = null;
6904 try {
6905 providers = ActivityThread.getPackageManager().
6906 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006907 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006908 } catch (RemoteException ex) {
6909 }
6910 if (providers != null) {
6911 final int N = providers.size();
6912 for (int i=0; i<N; i++) {
6913 ProviderInfo cpi =
6914 (ProviderInfo)providers.get(i);
6915 ContentProviderRecord cpr =
6916 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6917 if (cpr == null) {
6918 cpr = new ContentProviderRecord(cpi, app.info);
6919 mProvidersByClass.put(cpi.name, cpr);
6920 }
6921 app.pubProviders.put(cpi.name, cpr);
6922 app.addPackage(cpi.applicationInfo.packageName);
6923 }
6924 }
6925 return providers;
6926 }
6927
6928 private final String checkContentProviderPermissionLocked(
6929 ProviderInfo cpi, ProcessRecord r, int mode) {
6930 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6931 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6932 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6933 cpi.exported ? -1 : cpi.applicationInfo.uid)
6934 == PackageManager.PERMISSION_GRANTED
6935 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6936 return null;
6937 }
6938 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6939 cpi.exported ? -1 : cpi.applicationInfo.uid)
6940 == PackageManager.PERMISSION_GRANTED) {
6941 return null;
6942 }
6943 String msg = "Permission Denial: opening provider " + cpi.name
6944 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
6945 + ", uid=" + callingUid + ") requires "
6946 + cpi.readPermission + " or " + cpi.writePermission;
6947 Log.w(TAG, msg);
6948 return msg;
6949 }
6950
6951 private final ContentProviderHolder getContentProviderImpl(
6952 IApplicationThread caller, String name) {
6953 ContentProviderRecord cpr;
6954 ProviderInfo cpi = null;
6955
6956 synchronized(this) {
6957 ProcessRecord r = null;
6958 if (caller != null) {
6959 r = getRecordForAppLocked(caller);
6960 if (r == null) {
6961 throw new SecurityException(
6962 "Unable to find app for caller " + caller
6963 + " (pid=" + Binder.getCallingPid()
6964 + ") when getting content provider " + name);
6965 }
6966 }
6967
6968 // First check if this content provider has been published...
6969 cpr = (ContentProviderRecord)mProvidersByName.get(name);
6970 if (cpr != null) {
6971 cpi = cpr.info;
6972 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6973 return new ContentProviderHolder(cpi,
6974 cpi.readPermission != null
6975 ? cpi.readPermission : cpi.writePermission);
6976 }
6977
6978 if (r != null && cpr.canRunHere(r)) {
6979 // This provider has been published or is in the process
6980 // of being published... but it is also allowed to run
6981 // in the caller's process, so don't make a connection
6982 // and just let the caller instantiate its own instance.
6983 if (cpr.provider != null) {
6984 // don't give caller the provider object, it needs
6985 // to make its own.
6986 cpr = new ContentProviderRecord(cpr);
6987 }
6988 return cpr;
6989 }
6990
6991 final long origId = Binder.clearCallingIdentity();
6992
6993 // In this case the provider is a single instance, so we can
6994 // return it right away.
6995 if (r != null) {
6996 r.conProviders.add(cpr);
6997 cpr.clients.add(r);
6998 } else {
6999 cpr.externals++;
7000 }
7001
7002 if (cpr.app != null) {
7003 updateOomAdjLocked(cpr.app);
7004 }
7005
7006 Binder.restoreCallingIdentity(origId);
7007
7008 } else {
7009 try {
7010 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007011 resolveContentProvider(name,
7012 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007013 } catch (RemoteException ex) {
7014 }
7015 if (cpi == null) {
7016 return null;
7017 }
7018
7019 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7020 return new ContentProviderHolder(cpi,
7021 cpi.readPermission != null
7022 ? cpi.readPermission : cpi.writePermission);
7023 }
7024
7025 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7026 final boolean firstClass = cpr == null;
7027 if (firstClass) {
7028 try {
7029 ApplicationInfo ai =
7030 ActivityThread.getPackageManager().
7031 getApplicationInfo(
7032 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007033 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007034 if (ai == null) {
7035 Log.w(TAG, "No package info for content provider "
7036 + cpi.name);
7037 return null;
7038 }
7039 cpr = new ContentProviderRecord(cpi, ai);
7040 } catch (RemoteException ex) {
7041 // pm is in same process, this will never happen.
7042 }
7043 }
7044
7045 if (r != null && cpr.canRunHere(r)) {
7046 // If this is a multiprocess provider, then just return its
7047 // info and allow the caller to instantiate it. Only do
7048 // this if the provider is the same user as the caller's
7049 // process, or can run as root (so can be in any process).
7050 return cpr;
7051 }
7052
7053 if (false) {
7054 RuntimeException e = new RuntimeException("foo");
7055 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7056 // + " pruid " + ai.uid + "): " + cpi.className, e);
7057 }
7058
7059 // This is single process, and our app is now connecting to it.
7060 // See if we are already in the process of launching this
7061 // provider.
7062 final int N = mLaunchingProviders.size();
7063 int i;
7064 for (i=0; i<N; i++) {
7065 if (mLaunchingProviders.get(i) == cpr) {
7066 break;
7067 }
7068 if (false) {
7069 final ContentProviderRecord rec =
7070 (ContentProviderRecord)mLaunchingProviders.get(i);
7071 if (rec.info.name.equals(cpr.info.name)) {
7072 cpr = rec;
7073 break;
7074 }
7075 }
7076 }
7077
7078 // If the provider is not already being launched, then get it
7079 // started.
7080 if (i >= N) {
7081 final long origId = Binder.clearCallingIdentity();
7082 ProcessRecord proc = startProcessLocked(cpi.processName,
7083 cpr.appInfo, false, 0, "content provider",
7084 new ComponentName(cpi.applicationInfo.packageName,
7085 cpi.name));
7086 if (proc == null) {
7087 Log.w(TAG, "Unable to launch app "
7088 + cpi.applicationInfo.packageName + "/"
7089 + cpi.applicationInfo.uid + " for provider "
7090 + name + ": process is bad");
7091 return null;
7092 }
7093 cpr.launchingApp = proc;
7094 mLaunchingProviders.add(cpr);
7095 Binder.restoreCallingIdentity(origId);
7096 }
7097
7098 // Make sure the provider is published (the same provider class
7099 // may be published under multiple names).
7100 if (firstClass) {
7101 mProvidersByClass.put(cpi.name, cpr);
7102 }
7103 mProvidersByName.put(name, cpr);
7104
7105 if (r != null) {
7106 r.conProviders.add(cpr);
7107 cpr.clients.add(r);
7108 } else {
7109 cpr.externals++;
7110 }
7111 }
7112 }
7113
7114 // Wait for the provider to be published...
7115 synchronized (cpr) {
7116 while (cpr.provider == null) {
7117 if (cpr.launchingApp == null) {
7118 Log.w(TAG, "Unable to launch app "
7119 + cpi.applicationInfo.packageName + "/"
7120 + cpi.applicationInfo.uid + " for provider "
7121 + name + ": launching app became null");
7122 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7123 cpi.applicationInfo.packageName,
7124 cpi.applicationInfo.uid, name);
7125 return null;
7126 }
7127 try {
7128 cpr.wait();
7129 } catch (InterruptedException ex) {
7130 }
7131 }
7132 }
7133 return cpr;
7134 }
7135
7136 public final ContentProviderHolder getContentProvider(
7137 IApplicationThread caller, String name) {
7138 if (caller == null) {
7139 String msg = "null IApplicationThread when getting content provider "
7140 + name;
7141 Log.w(TAG, msg);
7142 throw new SecurityException(msg);
7143 }
7144
7145 return getContentProviderImpl(caller, name);
7146 }
7147
7148 private ContentProviderHolder getContentProviderExternal(String name) {
7149 return getContentProviderImpl(null, name);
7150 }
7151
7152 /**
7153 * Drop a content provider from a ProcessRecord's bookkeeping
7154 * @param cpr
7155 */
7156 public void removeContentProvider(IApplicationThread caller, String name) {
7157 synchronized (this) {
7158 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7159 if(cpr == null) {
7160 //remove from mProvidersByClass
7161 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7162 return;
7163 }
7164 final ProcessRecord r = getRecordForAppLocked(caller);
7165 if (r == null) {
7166 throw new SecurityException(
7167 "Unable to find app for caller " + caller +
7168 " when removing content provider " + name);
7169 }
7170 //update content provider record entry info
7171 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7172 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7173 r.info.processName+" from process "+localCpr.appInfo.processName);
7174 if(localCpr.appInfo.processName == r.info.processName) {
7175 //should not happen. taken care of as a local provider
7176 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7177 return;
7178 } else {
7179 localCpr.clients.remove(r);
7180 r.conProviders.remove(localCpr);
7181 }
7182 updateOomAdjLocked();
7183 }
7184 }
7185
7186 private void removeContentProviderExternal(String name) {
7187 synchronized (this) {
7188 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7189 if(cpr == null) {
7190 //remove from mProvidersByClass
7191 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7192 return;
7193 }
7194
7195 //update content provider record entry info
7196 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7197 localCpr.externals--;
7198 if (localCpr.externals < 0) {
7199 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7200 }
7201 updateOomAdjLocked();
7202 }
7203 }
7204
7205 public final void publishContentProviders(IApplicationThread caller,
7206 List<ContentProviderHolder> providers) {
7207 if (providers == null) {
7208 return;
7209 }
7210
7211 synchronized(this) {
7212 final ProcessRecord r = getRecordForAppLocked(caller);
7213 if (r == null) {
7214 throw new SecurityException(
7215 "Unable to find app for caller " + caller
7216 + " (pid=" + Binder.getCallingPid()
7217 + ") when publishing content providers");
7218 }
7219
7220 final long origId = Binder.clearCallingIdentity();
7221
7222 final int N = providers.size();
7223 for (int i=0; i<N; i++) {
7224 ContentProviderHolder src = providers.get(i);
7225 if (src == null || src.info == null || src.provider == null) {
7226 continue;
7227 }
7228 ContentProviderRecord dst =
7229 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7230 if (dst != null) {
7231 mProvidersByClass.put(dst.info.name, dst);
7232 String names[] = dst.info.authority.split(";");
7233 for (int j = 0; j < names.length; j++) {
7234 mProvidersByName.put(names[j], dst);
7235 }
7236
7237 int NL = mLaunchingProviders.size();
7238 int j;
7239 for (j=0; j<NL; j++) {
7240 if (mLaunchingProviders.get(j) == dst) {
7241 mLaunchingProviders.remove(j);
7242 j--;
7243 NL--;
7244 }
7245 }
7246 synchronized (dst) {
7247 dst.provider = src.provider;
7248 dst.app = r;
7249 dst.notifyAll();
7250 }
7251 updateOomAdjLocked(r);
7252 }
7253 }
7254
7255 Binder.restoreCallingIdentity(origId);
7256 }
7257 }
7258
7259 public static final void installSystemProviders() {
7260 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7261 List providers = mSelf.generateApplicationProvidersLocked(app);
7262 mSystemThread.installSystemProviders(providers);
7263 }
7264
7265 // =========================================================
7266 // GLOBAL MANAGEMENT
7267 // =========================================================
7268
7269 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7270 ApplicationInfo info, String customProcess) {
7271 String proc = customProcess != null ? customProcess : info.processName;
7272 BatteryStatsImpl.Uid.Proc ps = null;
7273 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7274 synchronized (stats) {
7275 ps = stats.getProcessStatsLocked(info.uid, proc);
7276 }
7277 return new ProcessRecord(ps, thread, info, proc);
7278 }
7279
7280 final ProcessRecord addAppLocked(ApplicationInfo info) {
7281 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7282
7283 if (app == null) {
7284 app = newProcessRecordLocked(null, info, null);
7285 mProcessNames.put(info.processName, info.uid, app);
7286 updateLRUListLocked(app, true);
7287 }
7288
7289 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7290 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7291 app.persistent = true;
7292 app.maxAdj = CORE_SERVER_ADJ;
7293 }
7294 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7295 mPersistentStartingProcesses.add(app);
7296 startProcessLocked(app, "added application", app.processName);
7297 }
7298
7299 return app;
7300 }
7301
7302 public void unhandledBack() {
7303 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7304 "unhandledBack()");
7305
7306 synchronized(this) {
7307 int count = mHistory.size();
7308 if (Config.LOGD) Log.d(
7309 TAG, "Performing unhandledBack(): stack size = " + count);
7310 if (count > 1) {
7311 final long origId = Binder.clearCallingIdentity();
7312 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7313 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7314 Binder.restoreCallingIdentity(origId);
7315 }
7316 }
7317 }
7318
7319 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7320 String name = uri.getAuthority();
7321 ContentProviderHolder cph = getContentProviderExternal(name);
7322 ParcelFileDescriptor pfd = null;
7323 if (cph != null) {
7324 // We record the binder invoker's uid in thread-local storage before
7325 // going to the content provider to open the file. Later, in the code
7326 // that handles all permissions checks, we look for this uid and use
7327 // that rather than the Activity Manager's own uid. The effect is that
7328 // we do the check against the caller's permissions even though it looks
7329 // to the content provider like the Activity Manager itself is making
7330 // the request.
7331 sCallerIdentity.set(new Identity(
7332 Binder.getCallingPid(), Binder.getCallingUid()));
7333 try {
7334 pfd = cph.provider.openFile(uri, "r");
7335 } catch (FileNotFoundException e) {
7336 // do nothing; pfd will be returned null
7337 } finally {
7338 // Ensure that whatever happens, we clean up the identity state
7339 sCallerIdentity.remove();
7340 }
7341
7342 // We've got the fd now, so we're done with the provider.
7343 removeContentProviderExternal(name);
7344 } else {
7345 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7346 }
7347 return pfd;
7348 }
7349
7350 public void goingToSleep() {
7351 synchronized(this) {
7352 mSleeping = true;
7353 mWindowManager.setEventDispatching(false);
7354
7355 if (mResumedActivity != null) {
7356 pauseIfSleepingLocked();
7357 } else {
7358 Log.w(TAG, "goingToSleep with no resumed activity!");
7359 }
7360 }
7361 }
7362
Dianne Hackborn55280a92009-05-07 15:53:46 -07007363 public boolean shutdown(int timeout) {
7364 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7365 != PackageManager.PERMISSION_GRANTED) {
7366 throw new SecurityException("Requires permission "
7367 + android.Manifest.permission.SHUTDOWN);
7368 }
7369
7370 boolean timedout = false;
7371
7372 synchronized(this) {
7373 mShuttingDown = true;
7374 mWindowManager.setEventDispatching(false);
7375
7376 if (mResumedActivity != null) {
7377 pauseIfSleepingLocked();
7378 final long endTime = System.currentTimeMillis() + timeout;
7379 while (mResumedActivity != null || mPausingActivity != null) {
7380 long delay = endTime - System.currentTimeMillis();
7381 if (delay <= 0) {
7382 Log.w(TAG, "Activity manager shutdown timed out");
7383 timedout = true;
7384 break;
7385 }
7386 try {
7387 this.wait();
7388 } catch (InterruptedException e) {
7389 }
7390 }
7391 }
7392 }
7393
7394 mUsageStatsService.shutdown();
7395 mBatteryStatsService.shutdown();
7396
7397 return timedout;
7398 }
7399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007400 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007401 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007402 if (!mGoingToSleep.isHeld()) {
7403 mGoingToSleep.acquire();
7404 if (mLaunchingActivity.isHeld()) {
7405 mLaunchingActivity.release();
7406 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7407 }
7408 }
7409
7410 // If we are not currently pausing an activity, get the current
7411 // one to pause. If we are pausing one, we will just let that stuff
7412 // run and release the wake lock when all done.
7413 if (mPausingActivity == null) {
7414 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7415 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7416 startPausingLocked(false, true);
7417 }
7418 }
7419 }
7420
7421 public void wakingUp() {
7422 synchronized(this) {
7423 if (mGoingToSleep.isHeld()) {
7424 mGoingToSleep.release();
7425 }
7426 mWindowManager.setEventDispatching(true);
7427 mSleeping = false;
7428 resumeTopActivityLocked(null);
7429 }
7430 }
7431
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007432 public void stopAppSwitches() {
7433 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7434 != PackageManager.PERMISSION_GRANTED) {
7435 throw new SecurityException("Requires permission "
7436 + android.Manifest.permission.STOP_APP_SWITCHES);
7437 }
7438
7439 synchronized(this) {
7440 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7441 + APP_SWITCH_DELAY_TIME;
7442 mDidAppSwitch = false;
7443 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7444 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7445 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7446 }
7447 }
7448
7449 public void resumeAppSwitches() {
7450 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7451 != PackageManager.PERMISSION_GRANTED) {
7452 throw new SecurityException("Requires permission "
7453 + android.Manifest.permission.STOP_APP_SWITCHES);
7454 }
7455
7456 synchronized(this) {
7457 // Note that we don't execute any pending app switches... we will
7458 // let those wait until either the timeout, or the next start
7459 // activity request.
7460 mAppSwitchesAllowedTime = 0;
7461 }
7462 }
7463
7464 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7465 String name) {
7466 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7467 return true;
7468 }
7469
7470 final int perm = checkComponentPermission(
7471 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7472 callingUid, -1);
7473 if (perm == PackageManager.PERMISSION_GRANTED) {
7474 return true;
7475 }
7476
7477 Log.w(TAG, name + " request from " + callingUid + " stopped");
7478 return false;
7479 }
7480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007481 public void setDebugApp(String packageName, boolean waitForDebugger,
7482 boolean persistent) {
7483 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7484 "setDebugApp()");
7485
7486 // Note that this is not really thread safe if there are multiple
7487 // callers into it at the same time, but that's not a situation we
7488 // care about.
7489 if (persistent) {
7490 final ContentResolver resolver = mContext.getContentResolver();
7491 Settings.System.putString(
7492 resolver, Settings.System.DEBUG_APP,
7493 packageName);
7494 Settings.System.putInt(
7495 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7496 waitForDebugger ? 1 : 0);
7497 }
7498
7499 synchronized (this) {
7500 if (!persistent) {
7501 mOrigDebugApp = mDebugApp;
7502 mOrigWaitForDebugger = mWaitForDebugger;
7503 }
7504 mDebugApp = packageName;
7505 mWaitForDebugger = waitForDebugger;
7506 mDebugTransient = !persistent;
7507 if (packageName != null) {
7508 final long origId = Binder.clearCallingIdentity();
7509 uninstallPackageLocked(packageName, -1, false);
7510 Binder.restoreCallingIdentity(origId);
7511 }
7512 }
7513 }
7514
7515 public void setAlwaysFinish(boolean enabled) {
7516 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7517 "setAlwaysFinish()");
7518
7519 Settings.System.putInt(
7520 mContext.getContentResolver(),
7521 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7522
7523 synchronized (this) {
7524 mAlwaysFinishActivities = enabled;
7525 }
7526 }
7527
7528 public void setActivityWatcher(IActivityWatcher watcher) {
7529 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7530 "setActivityWatcher()");
7531 synchronized (this) {
7532 mWatcher = watcher;
7533 }
7534 }
7535
7536 public final void enterSafeMode() {
7537 synchronized(this) {
7538 // It only makes sense to do this before the system is ready
7539 // and started launching other packages.
7540 if (!mSystemReady) {
7541 try {
7542 ActivityThread.getPackageManager().enterSafeMode();
7543 } catch (RemoteException e) {
7544 }
7545
7546 View v = LayoutInflater.from(mContext).inflate(
7547 com.android.internal.R.layout.safe_mode, null);
7548 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7549 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7550 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7551 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7552 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7553 lp.format = v.getBackground().getOpacity();
7554 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7555 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7556 ((WindowManager)mContext.getSystemService(
7557 Context.WINDOW_SERVICE)).addView(v, lp);
7558 }
7559 }
7560 }
7561
7562 public void noteWakeupAlarm(IIntentSender sender) {
7563 if (!(sender instanceof PendingIntentRecord)) {
7564 return;
7565 }
7566 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7567 synchronized (stats) {
7568 if (mBatteryStatsService.isOnBattery()) {
7569 mBatteryStatsService.enforceCallingPermission();
7570 PendingIntentRecord rec = (PendingIntentRecord)sender;
7571 int MY_UID = Binder.getCallingUid();
7572 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7573 BatteryStatsImpl.Uid.Pkg pkg =
7574 stats.getPackageStatsLocked(uid, rec.key.packageName);
7575 pkg.incWakeupsLocked();
7576 }
7577 }
7578 }
7579
7580 public boolean killPidsForMemory(int[] pids) {
7581 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7582 throw new SecurityException("killPidsForMemory only available to the system");
7583 }
7584
7585 // XXX Note: don't acquire main activity lock here, because the window
7586 // manager calls in with its locks held.
7587
7588 boolean killed = false;
7589 synchronized (mPidsSelfLocked) {
7590 int[] types = new int[pids.length];
7591 int worstType = 0;
7592 for (int i=0; i<pids.length; i++) {
7593 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7594 if (proc != null) {
7595 int type = proc.setAdj;
7596 types[i] = type;
7597 if (type > worstType) {
7598 worstType = type;
7599 }
7600 }
7601 }
7602
7603 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7604 // then constrain it so we will kill all hidden procs.
7605 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7606 worstType = HIDDEN_APP_MIN_ADJ;
7607 }
7608 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7609 for (int i=0; i<pids.length; i++) {
7610 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7611 if (proc == null) {
7612 continue;
7613 }
7614 int adj = proc.setAdj;
7615 if (adj >= worstType) {
7616 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7617 + adj + ")");
7618 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7619 proc.processName, adj);
7620 killed = true;
7621 Process.killProcess(pids[i]);
7622 }
7623 }
7624 }
7625 return killed;
7626 }
7627
7628 public void reportPss(IApplicationThread caller, int pss) {
7629 Watchdog.PssRequestor req;
7630 String name;
7631 ProcessRecord callerApp;
7632 synchronized (this) {
7633 if (caller == null) {
7634 return;
7635 }
7636 callerApp = getRecordForAppLocked(caller);
7637 if (callerApp == null) {
7638 return;
7639 }
7640 callerApp.lastPss = pss;
7641 req = callerApp;
7642 name = callerApp.processName;
7643 }
7644 Watchdog.getInstance().reportPss(req, name, pss);
7645 if (!callerApp.persistent) {
7646 removeRequestedPss(callerApp);
7647 }
7648 }
7649
7650 public void requestPss(Runnable completeCallback) {
7651 ArrayList<ProcessRecord> procs;
7652 synchronized (this) {
7653 mRequestPssCallback = completeCallback;
7654 mRequestPssList.clear();
7655 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7656 ProcessRecord proc = mLRUProcesses.get(i);
7657 if (!proc.persistent) {
7658 mRequestPssList.add(proc);
7659 }
7660 }
7661 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7662 }
7663
7664 int oldPri = Process.getThreadPriority(Process.myTid());
7665 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7666 for (int i=procs.size()-1; i>=0; i--) {
7667 ProcessRecord proc = procs.get(i);
7668 proc.lastPss = 0;
7669 proc.requestPss();
7670 }
7671 Process.setThreadPriority(oldPri);
7672 }
7673
7674 void removeRequestedPss(ProcessRecord proc) {
7675 Runnable callback = null;
7676 synchronized (this) {
7677 if (mRequestPssList.remove(proc)) {
7678 if (mRequestPssList.size() == 0) {
7679 callback = mRequestPssCallback;
7680 mRequestPssCallback = null;
7681 }
7682 }
7683 }
7684
7685 if (callback != null) {
7686 callback.run();
7687 }
7688 }
7689
7690 public void collectPss(Watchdog.PssStats stats) {
7691 stats.mEmptyPss = 0;
7692 stats.mEmptyCount = 0;
7693 stats.mBackgroundPss = 0;
7694 stats.mBackgroundCount = 0;
7695 stats.mServicePss = 0;
7696 stats.mServiceCount = 0;
7697 stats.mVisiblePss = 0;
7698 stats.mVisibleCount = 0;
7699 stats.mForegroundPss = 0;
7700 stats.mForegroundCount = 0;
7701 stats.mNoPssCount = 0;
7702 synchronized (this) {
7703 int i;
7704 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7705 ? mProcDeaths.length : stats.mProcDeaths.length;
7706 int aggr = 0;
7707 for (i=0; i<NPD; i++) {
7708 aggr += mProcDeaths[i];
7709 stats.mProcDeaths[i] = aggr;
7710 }
7711 while (i<stats.mProcDeaths.length) {
7712 stats.mProcDeaths[i] = 0;
7713 i++;
7714 }
7715
7716 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7717 ProcessRecord proc = mLRUProcesses.get(i);
7718 if (proc.persistent) {
7719 continue;
7720 }
7721 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7722 if (proc.lastPss == 0) {
7723 stats.mNoPssCount++;
7724 continue;
7725 }
7726 if (proc.setAdj == EMPTY_APP_ADJ) {
7727 stats.mEmptyPss += proc.lastPss;
7728 stats.mEmptyCount++;
7729 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7730 stats.mEmptyPss += proc.lastPss;
7731 stats.mEmptyCount++;
7732 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7733 stats.mBackgroundPss += proc.lastPss;
7734 stats.mBackgroundCount++;
7735 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7736 stats.mVisiblePss += proc.lastPss;
7737 stats.mVisibleCount++;
7738 } else {
7739 stats.mForegroundPss += proc.lastPss;
7740 stats.mForegroundCount++;
7741 }
7742 }
7743 }
7744 }
7745
7746 public final void startRunning(String pkg, String cls, String action,
7747 String data) {
7748 synchronized(this) {
7749 if (mStartRunning) {
7750 return;
7751 }
7752 mStartRunning = true;
7753 mTopComponent = pkg != null && cls != null
7754 ? new ComponentName(pkg, cls) : null;
7755 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7756 mTopData = data;
7757 if (!mSystemReady) {
7758 return;
7759 }
7760 }
7761
7762 systemReady();
7763 }
7764
7765 private void retrieveSettings() {
7766 final ContentResolver resolver = mContext.getContentResolver();
7767 String debugApp = Settings.System.getString(
7768 resolver, Settings.System.DEBUG_APP);
7769 boolean waitForDebugger = Settings.System.getInt(
7770 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7771 boolean alwaysFinishActivities = Settings.System.getInt(
7772 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7773
7774 Configuration configuration = new Configuration();
7775 Settings.System.getConfiguration(resolver, configuration);
7776
7777 synchronized (this) {
7778 mDebugApp = mOrigDebugApp = debugApp;
7779 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7780 mAlwaysFinishActivities = alwaysFinishActivities;
7781 // This happens before any activities are started, so we can
7782 // change mConfiguration in-place.
7783 mConfiguration.updateFrom(configuration);
7784 }
7785 }
7786
7787 public boolean testIsSystemReady() {
7788 // no need to synchronize(this) just to read & return the value
7789 return mSystemReady;
7790 }
7791
7792 public void systemReady() {
7793 // In the simulator, startRunning will never have been called, which
7794 // normally sets a few crucial variables. Do it here instead.
7795 if (!Process.supportsProcesses()) {
7796 mStartRunning = true;
7797 mTopAction = Intent.ACTION_MAIN;
7798 }
7799
7800 synchronized(this) {
7801 if (mSystemReady) {
7802 return;
7803 }
7804 mSystemReady = true;
7805 if (!mStartRunning) {
7806 return;
7807 }
7808 }
7809
7810 if (Config.LOGD) Log.d(TAG, "Start running!");
7811 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7812 SystemClock.uptimeMillis());
7813
7814 synchronized(this) {
7815 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7816 ResolveInfo ri = mContext.getPackageManager()
7817 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007818 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007819 CharSequence errorMsg = null;
7820 if (ri != null) {
7821 ActivityInfo ai = ri.activityInfo;
7822 ApplicationInfo app = ai.applicationInfo;
7823 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7824 mTopAction = Intent.ACTION_FACTORY_TEST;
7825 mTopData = null;
7826 mTopComponent = new ComponentName(app.packageName,
7827 ai.name);
7828 } else {
7829 errorMsg = mContext.getResources().getText(
7830 com.android.internal.R.string.factorytest_not_system);
7831 }
7832 } else {
7833 errorMsg = mContext.getResources().getText(
7834 com.android.internal.R.string.factorytest_no_action);
7835 }
7836 if (errorMsg != null) {
7837 mTopAction = null;
7838 mTopData = null;
7839 mTopComponent = null;
7840 Message msg = Message.obtain();
7841 msg.what = SHOW_FACTORY_ERROR_MSG;
7842 msg.getData().putCharSequence("msg", errorMsg);
7843 mHandler.sendMessage(msg);
7844 }
7845 }
7846 }
7847
7848 retrieveSettings();
7849
7850 synchronized (this) {
7851 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7852 try {
7853 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007854 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007855 if (apps != null) {
7856 int N = apps.size();
7857 int i;
7858 for (i=0; i<N; i++) {
7859 ApplicationInfo info
7860 = (ApplicationInfo)apps.get(i);
7861 if (info != null &&
7862 !info.packageName.equals("android")) {
7863 addAppLocked(info);
7864 }
7865 }
7866 }
7867 } catch (RemoteException ex) {
7868 // pm is in same process, this will never happen.
7869 }
7870 }
7871
7872 try {
7873 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7874 Message msg = Message.obtain();
7875 msg.what = SHOW_UID_ERROR_MSG;
7876 mHandler.sendMessage(msg);
7877 }
7878 } catch (RemoteException e) {
7879 }
7880
7881 // Start up initial activity.
7882 mBooting = true;
7883 resumeTopActivityLocked(null);
7884 }
7885 }
7886
7887 boolean makeAppCrashingLocked(ProcessRecord app,
7888 String tag, String shortMsg, String longMsg, byte[] crashData) {
7889 app.crashing = true;
7890 app.crashingReport = generateProcessError(app,
7891 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7892 startAppProblemLocked(app);
7893 app.stopFreezingAllLocked();
7894 return handleAppCrashLocked(app);
7895 }
7896
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007897 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7898 IPackageManager pm = ActivityThread.getPackageManager();
7899 try {
7900 // was an installer package name specified when this app was
7901 // installed?
7902 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7903 if (installerPackageName == null) {
7904 return null;
7905 }
7906
7907 // is there an Activity in this package that handles ACTION_APP_ERROR?
7908 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
7909 ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
7910 if (info == null || info.activityInfo == null) {
7911 return null;
7912 }
7913
7914 return new ComponentName(installerPackageName, info.activityInfo.name);
7915 } catch (RemoteException e) {
7916 // will return null and no error report will be delivered
7917 }
7918 return null;
7919 }
7920
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007921 void makeAppNotRespondingLocked(ProcessRecord app,
7922 String tag, String shortMsg, String longMsg, byte[] crashData) {
7923 app.notResponding = true;
7924 app.notRespondingReport = generateProcessError(app,
7925 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7926 crashData);
7927 startAppProblemLocked(app);
7928 app.stopFreezingAllLocked();
7929 }
7930
7931 /**
7932 * Generate a process error record, suitable for attachment to a ProcessRecord.
7933 *
7934 * @param app The ProcessRecord in which the error occurred.
7935 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7936 * ActivityManager.AppErrorStateInfo
7937 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7938 * @param shortMsg Short message describing the crash.
7939 * @param longMsg Long message describing the crash.
7940 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7941 *
7942 * @return Returns a fully-formed AppErrorStateInfo record.
7943 */
7944 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
7945 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
7946 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
7947
7948 report.condition = condition;
7949 report.processName = app.processName;
7950 report.pid = app.pid;
7951 report.uid = app.info.uid;
7952 report.tag = tag;
7953 report.shortMsg = shortMsg;
7954 report.longMsg = longMsg;
7955 report.crashData = crashData;
7956
7957 return report;
7958 }
7959
7960 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
7961 boolean crashed) {
7962 synchronized (this) {
7963 app.crashing = false;
7964 app.crashingReport = null;
7965 app.notResponding = false;
7966 app.notRespondingReport = null;
7967 if (app.anrDialog == fromDialog) {
7968 app.anrDialog = null;
7969 }
7970 if (app.waitDialog == fromDialog) {
7971 app.waitDialog = null;
7972 }
7973 if (app.pid > 0 && app.pid != MY_PID) {
7974 if (crashed) {
7975 handleAppCrashLocked(app);
7976 }
7977 Log.i(ActivityManagerService.TAG, "Killing process "
7978 + app.processName
7979 + " (pid=" + app.pid + ") at user's request");
7980 Process.killProcess(app.pid);
7981 }
7982
7983 }
7984 }
7985
7986 boolean handleAppCrashLocked(ProcessRecord app) {
7987 long now = SystemClock.uptimeMillis();
7988
7989 Long crashTime = mProcessCrashTimes.get(app.info.processName,
7990 app.info.uid);
7991 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
7992 // This process loses!
7993 Log.w(TAG, "Process " + app.info.processName
7994 + " has crashed too many times: killing!");
7995 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
7996 app.info.processName, app.info.uid);
7997 killServicesLocked(app, false);
7998 for (int i=mHistory.size()-1; i>=0; i--) {
7999 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8000 if (r.app == app) {
8001 if (Config.LOGD) Log.d(
8002 TAG, " Force finishing activity "
8003 + r.intent.getComponent().flattenToShortString());
8004 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8005 }
8006 }
8007 if (!app.persistent) {
8008 // We don't want to start this process again until the user
8009 // explicitly does so... but for persistent process, we really
8010 // need to keep it running. If a persistent process is actually
8011 // repeatedly crashing, then badness for everyone.
8012 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8013 app.info.processName);
8014 mBadProcesses.put(app.info.processName, app.info.uid, now);
8015 app.bad = true;
8016 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8017 app.removed = true;
8018 removeProcessLocked(app, false);
8019 return false;
8020 }
8021 }
8022
8023 // Bump up the crash count of any services currently running in the proc.
8024 if (app.services.size() != 0) {
8025 // Any services running in the application need to be placed
8026 // back in the pending list.
8027 Iterator it = app.services.iterator();
8028 while (it.hasNext()) {
8029 ServiceRecord sr = (ServiceRecord)it.next();
8030 sr.crashCount++;
8031 }
8032 }
8033
8034 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8035 return true;
8036 }
8037
8038 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008039 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008040 skipCurrentReceiverLocked(app);
8041 }
8042
8043 void skipCurrentReceiverLocked(ProcessRecord app) {
8044 boolean reschedule = false;
8045 BroadcastRecord r = app.curReceiver;
8046 if (r != null) {
8047 // The current broadcast is waiting for this app's receiver
8048 // to be finished. Looks like that's not going to happen, so
8049 // let the broadcast continue.
8050 logBroadcastReceiverDiscard(r);
8051 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8052 r.resultExtras, r.resultAbort, true);
8053 reschedule = true;
8054 }
8055 r = mPendingBroadcast;
8056 if (r != null && r.curApp == app) {
8057 if (DEBUG_BROADCAST) Log.v(TAG,
8058 "skip & discard pending app " + r);
8059 logBroadcastReceiverDiscard(r);
8060 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8061 r.resultExtras, r.resultAbort, true);
8062 reschedule = true;
8063 }
8064 if (reschedule) {
8065 scheduleBroadcastsLocked();
8066 }
8067 }
8068
8069 public int handleApplicationError(IBinder app, int flags,
8070 String tag, String shortMsg, String longMsg, byte[] crashData) {
8071 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008072 ProcessRecord r = null;
8073 synchronized (this) {
8074 if (app != null) {
8075 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8076 final int NA = apps.size();
8077 for (int ia=0; ia<NA; ia++) {
8078 ProcessRecord p = apps.valueAt(ia);
8079 if (p.thread != null && p.thread.asBinder() == app) {
8080 r = p;
8081 break;
8082 }
8083 }
8084 }
8085 }
8086
8087 if (r != null) {
8088 // The application has crashed. Send the SIGQUIT to the process so
8089 // that it can dump its state.
8090 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8091 //Log.i(TAG, "Current system threads:");
8092 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8093 }
8094
8095 if (mWatcher != null) {
8096 try {
8097 String name = r != null ? r.processName : null;
8098 int pid = r != null ? r.pid : Binder.getCallingPid();
8099 if (!mWatcher.appCrashed(name, pid,
8100 shortMsg, longMsg, crashData)) {
8101 Log.w(TAG, "Force-killing crashed app " + name
8102 + " at watcher's request");
8103 Process.killProcess(pid);
8104 return 0;
8105 }
8106 } catch (RemoteException e) {
8107 mWatcher = null;
8108 }
8109 }
8110
8111 final long origId = Binder.clearCallingIdentity();
8112
8113 // If this process is running instrumentation, finish it.
8114 if (r != null && r.instrumentationClass != null) {
8115 Log.w(TAG, "Error in app " + r.processName
8116 + " running instrumentation " + r.instrumentationClass + ":");
8117 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8118 if (longMsg != null) Log.w(TAG, " " + longMsg);
8119 Bundle info = new Bundle();
8120 info.putString("shortMsg", shortMsg);
8121 info.putString("longMsg", longMsg);
8122 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8123 Binder.restoreCallingIdentity(origId);
8124 return 0;
8125 }
8126
8127 if (r != null) {
8128 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8129 return 0;
8130 }
8131 } else {
8132 Log.w(TAG, "Some application object " + app + " tag " + tag
8133 + " has crashed, but I don't know who it is.");
8134 Log.w(TAG, "ShortMsg:" + shortMsg);
8135 Log.w(TAG, "LongMsg:" + longMsg);
8136 Binder.restoreCallingIdentity(origId);
8137 return 0;
8138 }
8139
8140 Message msg = Message.obtain();
8141 msg.what = SHOW_ERROR_MSG;
8142 HashMap data = new HashMap();
8143 data.put("result", result);
8144 data.put("app", r);
8145 data.put("flags", flags);
8146 data.put("shortMsg", shortMsg);
8147 data.put("longMsg", longMsg);
8148 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8149 // For system processes, submit crash data to the server.
8150 data.put("crashData", crashData);
8151 }
8152 msg.obj = data;
8153 mHandler.sendMessage(msg);
8154
8155 Binder.restoreCallingIdentity(origId);
8156 }
8157
8158 int res = result.get();
8159
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008160 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008161 synchronized (this) {
8162 if (r != null) {
8163 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8164 SystemClock.uptimeMillis());
8165 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008166 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8167 appErrorIntent = createAppErrorIntentLocked(r);
8168 res = AppErrorDialog.FORCE_QUIT;
8169 }
8170 }
8171
8172 if (appErrorIntent != null) {
8173 try {
8174 mContext.startActivity(appErrorIntent);
8175 } catch (ActivityNotFoundException e) {
8176 Log.w(TAG, "bug report receiver dissappeared", e);
8177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008178 }
8179
8180 return res;
8181 }
8182
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008183 Intent createAppErrorIntentLocked(ProcessRecord r) {
8184 ApplicationErrorReport report = createAppErrorReportLocked(r);
8185 if (report == null) {
8186 return null;
8187 }
8188 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8189 result.setComponent(r.errorReportReceiver);
8190 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8191 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8192 return result;
8193 }
8194
8195 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8196 if (r.errorReportReceiver == null) {
8197 return null;
8198 }
8199
8200 if (!r.crashing && !r.notResponding) {
8201 return null;
8202 }
8203
8204 try {
8205 ApplicationErrorReport report = new ApplicationErrorReport();
8206 report.packageName = r.info.packageName;
8207 report.installerPackageName = r.errorReportReceiver.getPackageName();
8208 report.processName = r.processName;
8209
8210 if (r.crashing) {
8211 report.type = ApplicationErrorReport.TYPE_CRASH;
8212 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8213
8214 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8215 r.crashingReport.crashData);
8216 DataInputStream dataStream = new DataInputStream(byteStream);
8217 CrashData crashData = new CrashData(dataStream);
8218 ThrowableData throwData = crashData.getThrowableData();
8219
8220 report.time = crashData.getTime();
8221 report.crashInfo.stackTrace = throwData.toString();
8222
8223 // extract the source of the exception, useful for report
8224 // clustering
8225 while (throwData.getCause() != null) {
8226 throwData = throwData.getCause();
8227 }
8228 StackTraceElementData trace = throwData.getStackTrace()[0];
8229 report.crashInfo.exceptionClassName = throwData.getType();
8230 report.crashInfo.throwFileName = trace.getFileName();
8231 report.crashInfo.throwClassName = trace.getClassName();
8232 report.crashInfo.throwMethodName = trace.getMethodName();
8233 } else if (r.notResponding) {
8234 report.type = ApplicationErrorReport.TYPE_ANR;
8235 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8236
8237 report.anrInfo.activity = r.notRespondingReport.tag;
8238 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8239 report.anrInfo.info = r.notRespondingReport.longMsg;
8240 }
8241
8242 return report;
8243 } catch (IOException e) {
8244 // we don't send it
8245 }
8246
8247 return null;
8248 }
8249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008250 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8251 // assume our apps are happy - lazy create the list
8252 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8253
8254 synchronized (this) {
8255
8256 // iterate across all processes
8257 final int N = mLRUProcesses.size();
8258 for (int i = 0; i < N; i++) {
8259 ProcessRecord app = mLRUProcesses.get(i);
8260 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8261 // This one's in trouble, so we'll generate a report for it
8262 // crashes are higher priority (in case there's a crash *and* an anr)
8263 ActivityManager.ProcessErrorStateInfo report = null;
8264 if (app.crashing) {
8265 report = app.crashingReport;
8266 } else if (app.notResponding) {
8267 report = app.notRespondingReport;
8268 }
8269
8270 if (report != null) {
8271 if (errList == null) {
8272 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8273 }
8274 errList.add(report);
8275 } else {
8276 Log.w(TAG, "Missing app error report, app = " + app.processName +
8277 " crashing = " + app.crashing +
8278 " notResponding = " + app.notResponding);
8279 }
8280 }
8281 }
8282 }
8283
8284 return errList;
8285 }
8286
8287 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8288 // Lazy instantiation of list
8289 List<ActivityManager.RunningAppProcessInfo> runList = null;
8290 synchronized (this) {
8291 // Iterate across all processes
8292 final int N = mLRUProcesses.size();
8293 for (int i = 0; i < N; i++) {
8294 ProcessRecord app = mLRUProcesses.get(i);
8295 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8296 // Generate process state info for running application
8297 ActivityManager.RunningAppProcessInfo currApp =
8298 new ActivityManager.RunningAppProcessInfo(app.processName,
8299 app.pid, app.getPackageList());
8300 int adj = app.curAdj;
8301 if (adj >= CONTENT_PROVIDER_ADJ) {
8302 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8303 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8304 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008305 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8306 } else if (adj >= HOME_APP_ADJ) {
8307 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8308 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008309 } else if (adj >= SECONDARY_SERVER_ADJ) {
8310 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8311 } else if (adj >= VISIBLE_APP_ADJ) {
8312 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8313 } else {
8314 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8315 }
8316 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8317 // + " lru=" + currApp.lru);
8318 if (runList == null) {
8319 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8320 }
8321 runList.add(currApp);
8322 }
8323 }
8324 }
8325 return runList;
8326 }
8327
8328 @Override
8329 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8330 synchronized (this) {
8331 if (checkCallingPermission(android.Manifest.permission.DUMP)
8332 != PackageManager.PERMISSION_GRANTED) {
8333 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8334 + Binder.getCallingPid()
8335 + ", uid=" + Binder.getCallingUid()
8336 + " without permission "
8337 + android.Manifest.permission.DUMP);
8338 return;
8339 }
8340 if (args.length != 0 && "service".equals(args[0])) {
8341 dumpService(fd, pw, args);
8342 return;
8343 }
8344 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008345 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008346 pw.println(" ");
8347 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008348 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008349 if (mWaitingVisibleActivities.size() > 0) {
8350 pw.println(" ");
8351 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008352 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008353 }
8354 if (mStoppingActivities.size() > 0) {
8355 pw.println(" ");
8356 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008357 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008358 }
8359 if (mFinishingActivities.size() > 0) {
8360 pw.println(" ");
8361 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008362 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008363 }
8364
8365 pw.println(" ");
8366 pw.println(" mPausingActivity: " + mPausingActivity);
8367 pw.println(" mResumedActivity: " + mResumedActivity);
8368 pw.println(" mFocusedActivity: " + mFocusedActivity);
8369 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8370
8371 if (mRecentTasks.size() > 0) {
8372 pw.println(" ");
8373 pw.println("Recent tasks in Current Activity Manager State:");
8374
8375 final int N = mRecentTasks.size();
8376 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008377 TaskRecord tr = mRecentTasks.get(i);
8378 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8379 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008380 mRecentTasks.get(i).dump(pw, " ");
8381 }
8382 }
8383
8384 pw.println(" ");
8385 pw.println(" mCurTask: " + mCurTask);
8386
8387 pw.println(" ");
8388 pw.println("Processes in Current Activity Manager State:");
8389
8390 boolean needSep = false;
8391 int numPers = 0;
8392
8393 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8394 final int NA = procs.size();
8395 for (int ia=0; ia<NA; ia++) {
8396 if (!needSep) {
8397 pw.println(" All known processes:");
8398 needSep = true;
8399 }
8400 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008401 pw.print(r.persistent ? " *PERS*" : " *APP*");
8402 pw.print(" UID "); pw.print(procs.keyAt(ia));
8403 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008404 r.dump(pw, " ");
8405 if (r.persistent) {
8406 numPers++;
8407 }
8408 }
8409 }
8410
8411 if (mLRUProcesses.size() > 0) {
8412 if (needSep) pw.println(" ");
8413 needSep = true;
8414 pw.println(" Running processes (most recent first):");
8415 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008416 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008417 needSep = true;
8418 }
8419
8420 synchronized (mPidsSelfLocked) {
8421 if (mPidsSelfLocked.size() > 0) {
8422 if (needSep) pw.println(" ");
8423 needSep = true;
8424 pw.println(" PID mappings:");
8425 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008426 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8427 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008428 }
8429 }
8430 }
8431
8432 if (mForegroundProcesses.size() > 0) {
8433 if (needSep) pw.println(" ");
8434 needSep = true;
8435 pw.println(" Foreground Processes:");
8436 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008437 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8438 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008439 }
8440 }
8441
8442 if (mPersistentStartingProcesses.size() > 0) {
8443 if (needSep) pw.println(" ");
8444 needSep = true;
8445 pw.println(" Persisent processes that are starting:");
8446 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008447 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008448 }
8449
8450 if (mStartingProcesses.size() > 0) {
8451 if (needSep) pw.println(" ");
8452 needSep = true;
8453 pw.println(" Processes that are starting:");
8454 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008455 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008456 }
8457
8458 if (mRemovedProcesses.size() > 0) {
8459 if (needSep) pw.println(" ");
8460 needSep = true;
8461 pw.println(" Processes that are being removed:");
8462 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008463 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008464 }
8465
8466 if (mProcessesOnHold.size() > 0) {
8467 if (needSep) pw.println(" ");
8468 needSep = true;
8469 pw.println(" Processes that are on old until the system is ready:");
8470 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008471 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008472 }
8473
8474 if (mProcessCrashTimes.getMap().size() > 0) {
8475 if (needSep) pw.println(" ");
8476 needSep = true;
8477 pw.println(" Time since processes crashed:");
8478 long now = SystemClock.uptimeMillis();
8479 for (Map.Entry<String, SparseArray<Long>> procs
8480 : mProcessCrashTimes.getMap().entrySet()) {
8481 SparseArray<Long> uids = procs.getValue();
8482 final int N = uids.size();
8483 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008484 pw.print(" Process "); pw.print(procs.getKey());
8485 pw.print(" uid "); pw.print(uids.keyAt(i));
8486 pw.print(": last crashed ");
8487 pw.print((now-uids.valueAt(i)));
8488 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008489 }
8490 }
8491 }
8492
8493 if (mBadProcesses.getMap().size() > 0) {
8494 if (needSep) pw.println(" ");
8495 needSep = true;
8496 pw.println(" Bad processes:");
8497 for (Map.Entry<String, SparseArray<Long>> procs
8498 : mBadProcesses.getMap().entrySet()) {
8499 SparseArray<Long> uids = procs.getValue();
8500 final int N = uids.size();
8501 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008502 pw.print(" Bad process "); pw.print(procs.getKey());
8503 pw.print(" uid "); pw.print(uids.keyAt(i));
8504 pw.print(": crashed at time ");
8505 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008506 }
8507 }
8508 }
8509
8510 pw.println(" ");
8511 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008512 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008513 pw.println(" mConfiguration: " + mConfiguration);
8514 pw.println(" mStartRunning=" + mStartRunning
8515 + " mSystemReady=" + mSystemReady
8516 + " mBooting=" + mBooting
8517 + " mBooted=" + mBooted
8518 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008519 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 pw.println(" mGoingToSleep=" + mGoingToSleep);
8521 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8522 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8523 + " mDebugTransient=" + mDebugTransient
8524 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8525 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8526 + " mWatcher=" + mWatcher);
8527 }
8528 }
8529
8530 /**
8531 * There are three ways to call this:
8532 * - no service specified: dump all the services
8533 * - a flattened component name that matched an existing service was specified as the
8534 * first arg: dump that one service
8535 * - the first arg isn't the flattened component name of an existing service:
8536 * dump all services whose component contains the first arg as a substring
8537 */
8538 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8539 String[] newArgs;
8540 String componentNameString;
8541 ServiceRecord r;
8542 if (args.length == 1) {
8543 componentNameString = null;
8544 newArgs = EMPTY_STRING_ARRAY;
8545 r = null;
8546 } else {
8547 componentNameString = args[1];
8548 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8549 r = componentName != null ? mServices.get(componentName) : null;
8550 newArgs = new String[args.length - 2];
8551 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8552 }
8553
8554 if (r != null) {
8555 dumpService(fd, pw, r, newArgs);
8556 } else {
8557 for (ServiceRecord r1 : mServices.values()) {
8558 if (componentNameString == null
8559 || r1.name.flattenToString().contains(componentNameString)) {
8560 dumpService(fd, pw, r1, newArgs);
8561 }
8562 }
8563 }
8564 }
8565
8566 /**
8567 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8568 * there is a thread associated with the service.
8569 */
8570 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8571 pw.println(" Service " + r.name.flattenToString());
8572 if (r.app != null && r.app.thread != null) {
8573 try {
8574 // flush anything that is already in the PrintWriter since the thread is going
8575 // to write to the file descriptor directly
8576 pw.flush();
8577 r.app.thread.dumpService(fd, r, args);
8578 pw.print("\n");
8579 } catch (RemoteException e) {
8580 pw.println("got a RemoteException while dumping the service");
8581 }
8582 }
8583 }
8584
8585 void dumpBroadcasts(PrintWriter pw) {
8586 synchronized (this) {
8587 if (checkCallingPermission(android.Manifest.permission.DUMP)
8588 != PackageManager.PERMISSION_GRANTED) {
8589 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8590 + Binder.getCallingPid()
8591 + ", uid=" + Binder.getCallingUid()
8592 + " without permission "
8593 + android.Manifest.permission.DUMP);
8594 return;
8595 }
8596 pw.println("Broadcasts in Current Activity Manager State:");
8597
8598 if (mRegisteredReceivers.size() > 0) {
8599 pw.println(" ");
8600 pw.println(" Registered Receivers:");
8601 Iterator it = mRegisteredReceivers.values().iterator();
8602 while (it.hasNext()) {
8603 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008604 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008605 r.dump(pw, " ");
8606 }
8607 }
8608
8609 pw.println(" ");
8610 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008611 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008612
8613 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8614 || mPendingBroadcast != null) {
8615 if (mParallelBroadcasts.size() > 0) {
8616 pw.println(" ");
8617 pw.println(" Active broadcasts:");
8618 }
8619 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8620 pw.println(" Broadcast #" + i + ":");
8621 mParallelBroadcasts.get(i).dump(pw, " ");
8622 }
8623 if (mOrderedBroadcasts.size() > 0) {
8624 pw.println(" ");
8625 pw.println(" Active serialized broadcasts:");
8626 }
8627 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8628 pw.println(" Serialized Broadcast #" + i + ":");
8629 mOrderedBroadcasts.get(i).dump(pw, " ");
8630 }
8631 pw.println(" ");
8632 pw.println(" Pending broadcast:");
8633 if (mPendingBroadcast != null) {
8634 mPendingBroadcast.dump(pw, " ");
8635 } else {
8636 pw.println(" (null)");
8637 }
8638 }
8639
8640 pw.println(" ");
8641 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8642 if (mStickyBroadcasts != null) {
8643 pw.println(" ");
8644 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008645 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008646 for (Map.Entry<String, ArrayList<Intent>> ent
8647 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008648 pw.print(" * Sticky action "); pw.print(ent.getKey());
8649 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008650 ArrayList<Intent> intents = ent.getValue();
8651 final int N = intents.size();
8652 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008653 sb.setLength(0);
8654 sb.append(" Intent: ");
8655 intents.get(i).toShortString(sb, true, false);
8656 pw.println(sb.toString());
8657 Bundle bundle = intents.get(i).getExtras();
8658 if (bundle != null) {
8659 pw.print(" ");
8660 pw.println(bundle.toString());
8661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008662 }
8663 }
8664 }
8665
8666 pw.println(" ");
8667 pw.println(" mHandler:");
8668 mHandler.dump(new PrintWriterPrinter(pw), " ");
8669 }
8670 }
8671
8672 void dumpServices(PrintWriter pw) {
8673 synchronized (this) {
8674 if (checkCallingPermission(android.Manifest.permission.DUMP)
8675 != PackageManager.PERMISSION_GRANTED) {
8676 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8677 + Binder.getCallingPid()
8678 + ", uid=" + Binder.getCallingUid()
8679 + " without permission "
8680 + android.Manifest.permission.DUMP);
8681 return;
8682 }
8683 pw.println("Services in Current Activity Manager State:");
8684
8685 boolean needSep = false;
8686
8687 if (mServices.size() > 0) {
8688 pw.println(" Active services:");
8689 Iterator<ServiceRecord> it = mServices.values().iterator();
8690 while (it.hasNext()) {
8691 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008692 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008693 r.dump(pw, " ");
8694 }
8695 needSep = true;
8696 }
8697
8698 if (mPendingServices.size() > 0) {
8699 if (needSep) pw.println(" ");
8700 pw.println(" Pending services:");
8701 for (int i=0; i<mPendingServices.size(); i++) {
8702 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008703 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008704 r.dump(pw, " ");
8705 }
8706 needSep = true;
8707 }
8708
8709 if (mRestartingServices.size() > 0) {
8710 if (needSep) pw.println(" ");
8711 pw.println(" Restarting services:");
8712 for (int i=0; i<mRestartingServices.size(); i++) {
8713 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008714 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008715 r.dump(pw, " ");
8716 }
8717 needSep = true;
8718 }
8719
8720 if (mStoppingServices.size() > 0) {
8721 if (needSep) pw.println(" ");
8722 pw.println(" Stopping services:");
8723 for (int i=0; i<mStoppingServices.size(); i++) {
8724 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008725 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008726 r.dump(pw, " ");
8727 }
8728 needSep = true;
8729 }
8730
8731 if (mServiceConnections.size() > 0) {
8732 if (needSep) pw.println(" ");
8733 pw.println(" Connection bindings to services:");
8734 Iterator<ConnectionRecord> it
8735 = mServiceConnections.values().iterator();
8736 while (it.hasNext()) {
8737 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008738 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008739 r.dump(pw, " ");
8740 }
8741 }
8742 }
8743 }
8744
8745 void dumpProviders(PrintWriter pw) {
8746 synchronized (this) {
8747 if (checkCallingPermission(android.Manifest.permission.DUMP)
8748 != PackageManager.PERMISSION_GRANTED) {
8749 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8750 + Binder.getCallingPid()
8751 + ", uid=" + Binder.getCallingUid()
8752 + " without permission "
8753 + android.Manifest.permission.DUMP);
8754 return;
8755 }
8756
8757 pw.println("Content Providers in Current Activity Manager State:");
8758
8759 boolean needSep = false;
8760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008761 if (mProvidersByClass.size() > 0) {
8762 if (needSep) pw.println(" ");
8763 pw.println(" Published content providers (by class):");
8764 Iterator it = mProvidersByClass.entrySet().iterator();
8765 while (it.hasNext()) {
8766 Map.Entry e = (Map.Entry)it.next();
8767 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008768 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008769 r.dump(pw, " ");
8770 }
8771 needSep = true;
8772 }
8773
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008774 if (mProvidersByName.size() > 0) {
8775 pw.println(" ");
8776 pw.println(" Authority to provider mappings:");
8777 Iterator it = mProvidersByName.entrySet().iterator();
8778 while (it.hasNext()) {
8779 Map.Entry e = (Map.Entry)it.next();
8780 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8781 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8782 pw.println(r);
8783 }
8784 needSep = true;
8785 }
8786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008787 if (mLaunchingProviders.size() > 0) {
8788 if (needSep) pw.println(" ");
8789 pw.println(" Launching content providers:");
8790 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008791 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8792 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008793 }
8794 needSep = true;
8795 }
8796
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008797 if (mGrantedUriPermissions.size() > 0) {
8798 pw.println();
8799 pw.println("Granted Uri Permissions:");
8800 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8801 int uid = mGrantedUriPermissions.keyAt(i);
8802 HashMap<Uri, UriPermission> perms
8803 = mGrantedUriPermissions.valueAt(i);
8804 pw.print(" * UID "); pw.print(uid);
8805 pw.println(" holds:");
8806 for (UriPermission perm : perms.values()) {
8807 pw.print(" "); pw.println(perm);
8808 perm.dump(pw, " ");
8809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008810 }
8811 }
8812 }
8813 }
8814
8815 void dumpSenders(PrintWriter pw) {
8816 synchronized (this) {
8817 if (checkCallingPermission(android.Manifest.permission.DUMP)
8818 != PackageManager.PERMISSION_GRANTED) {
8819 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8820 + Binder.getCallingPid()
8821 + ", uid=" + Binder.getCallingUid()
8822 + " without permission "
8823 + android.Manifest.permission.DUMP);
8824 return;
8825 }
8826
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008827 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008828
8829 if (this.mIntentSenderRecords.size() > 0) {
8830 Iterator<WeakReference<PendingIntentRecord>> it
8831 = mIntentSenderRecords.values().iterator();
8832 while (it.hasNext()) {
8833 WeakReference<PendingIntentRecord> ref = it.next();
8834 PendingIntentRecord rec = ref != null ? ref.get(): null;
8835 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008836 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008837 rec.dump(pw, " ");
8838 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008839 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008840 }
8841 }
8842 }
8843 }
8844 }
8845
8846 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008847 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008848 TaskRecord lastTask = null;
8849 for (int i=list.size()-1; i>=0; i--) {
8850 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008851 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008852 if (lastTask != r.task) {
8853 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008854 pw.print(prefix);
8855 pw.print(full ? "* " : " ");
8856 pw.println(lastTask);
8857 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008858 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008859 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008860 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008861 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8862 pw.print(" #"); pw.print(i); pw.print(": ");
8863 pw.println(r);
8864 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008865 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008867 }
8868 }
8869
8870 private static final int dumpProcessList(PrintWriter pw, List list,
8871 String prefix, String normalLabel, String persistentLabel,
8872 boolean inclOomAdj) {
8873 int numPers = 0;
8874 for (int i=list.size()-1; i>=0; i--) {
8875 ProcessRecord r = (ProcessRecord)list.get(i);
8876 if (false) {
8877 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8878 + " #" + i + ":");
8879 r.dump(pw, prefix + " ");
8880 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008881 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008882 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008883 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008884 } else {
8885 pw.println(String.format("%s%s #%2d: %s",
8886 prefix, (r.persistent ? persistentLabel : normalLabel),
8887 i, r.toString()));
8888 }
8889 if (r.persistent) {
8890 numPers++;
8891 }
8892 }
8893 return numPers;
8894 }
8895
8896 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8897 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008898 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008899 long uptime = SystemClock.uptimeMillis();
8900 long realtime = SystemClock.elapsedRealtime();
8901
8902 if (isCheckinRequest) {
8903 // short checkin version
8904 pw.println(uptime + "," + realtime);
8905 pw.flush();
8906 } else {
8907 pw.println("Applications Memory Usage (kB):");
8908 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8909 }
8910 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8911 ProcessRecord r = (ProcessRecord)list.get(i);
8912 if (r.thread != null) {
8913 if (!isCheckinRequest) {
8914 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8915 pw.flush();
8916 }
8917 try {
8918 r.thread.asBinder().dump(fd, args);
8919 } catch (RemoteException e) {
8920 if (!isCheckinRequest) {
8921 pw.println("Got RemoteException!");
8922 pw.flush();
8923 }
8924 }
8925 }
8926 }
8927 }
8928
8929 /**
8930 * Searches array of arguments for the specified string
8931 * @param args array of argument strings
8932 * @param value value to search for
8933 * @return true if the value is contained in the array
8934 */
8935 private static boolean scanArgs(String[] args, String value) {
8936 if (args != null) {
8937 for (String arg : args) {
8938 if (value.equals(arg)) {
8939 return true;
8940 }
8941 }
8942 }
8943 return false;
8944 }
8945
8946 private final int indexOfTokenLocked(IBinder token, boolean required) {
8947 int count = mHistory.size();
8948
8949 // convert the token to an entry in the history.
8950 HistoryRecord r = null;
8951 int index = -1;
8952 for (int i=count-1; i>=0; i--) {
8953 Object o = mHistory.get(i);
8954 if (o == token) {
8955 r = (HistoryRecord)o;
8956 index = i;
8957 break;
8958 }
8959 }
8960 if (index < 0 && required) {
8961 RuntimeInit.crash(TAG, new InvalidTokenException(token));
8962 }
8963
8964 return index;
8965 }
8966
8967 static class InvalidTokenException extends Exception {
8968 InvalidTokenException(IBinder token) {
8969 super("Bad activity token: " + token);
8970 }
8971 }
8972
8973 private final void killServicesLocked(ProcessRecord app,
8974 boolean allowRestart) {
8975 // Report disconnected services.
8976 if (false) {
8977 // XXX we are letting the client link to the service for
8978 // death notifications.
8979 if (app.services.size() > 0) {
8980 Iterator it = app.services.iterator();
8981 while (it.hasNext()) {
8982 ServiceRecord r = (ServiceRecord)it.next();
8983 if (r.connections.size() > 0) {
8984 Iterator<ConnectionRecord> jt
8985 = r.connections.values().iterator();
8986 while (jt.hasNext()) {
8987 ConnectionRecord c = jt.next();
8988 if (c.binding.client != app) {
8989 try {
8990 //c.conn.connected(r.className, null);
8991 } catch (Exception e) {
8992 // todo: this should be asynchronous!
8993 Log.w(TAG, "Exception thrown disconnected servce "
8994 + r.shortName
8995 + " from app " + app.processName, e);
8996 }
8997 }
8998 }
8999 }
9000 }
9001 }
9002 }
9003
9004 // Clean up any connections this application has to other services.
9005 if (app.connections.size() > 0) {
9006 Iterator<ConnectionRecord> it = app.connections.iterator();
9007 while (it.hasNext()) {
9008 ConnectionRecord r = it.next();
9009 removeConnectionLocked(r, app, null);
9010 }
9011 }
9012 app.connections.clear();
9013
9014 if (app.services.size() != 0) {
9015 // Any services running in the application need to be placed
9016 // back in the pending list.
9017 Iterator it = app.services.iterator();
9018 while (it.hasNext()) {
9019 ServiceRecord sr = (ServiceRecord)it.next();
9020 synchronized (sr.stats.getBatteryStats()) {
9021 sr.stats.stopLaunchedLocked();
9022 }
9023 sr.app = null;
9024 sr.executeNesting = 0;
9025 mStoppingServices.remove(sr);
9026 if (sr.bindings.size() > 0) {
9027 Iterator<IntentBindRecord> bindings
9028 = sr.bindings.values().iterator();
9029 while (bindings.hasNext()) {
9030 IntentBindRecord b = bindings.next();
9031 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9032 + ": shouldUnbind=" + b.hasBound);
9033 b.binder = null;
9034 b.requested = b.received = b.hasBound = false;
9035 }
9036 }
9037
9038 if (sr.crashCount >= 2) {
9039 Log.w(TAG, "Service crashed " + sr.crashCount
9040 + " times, stopping: " + sr);
9041 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9042 sr.crashCount, sr.shortName, app.pid);
9043 bringDownServiceLocked(sr, true);
9044 } else if (!allowRestart) {
9045 bringDownServiceLocked(sr, true);
9046 } else {
9047 scheduleServiceRestartLocked(sr);
9048 }
9049 }
9050
9051 if (!allowRestart) {
9052 app.services.clear();
9053 }
9054 }
9055
9056 app.executingServices.clear();
9057 }
9058
9059 private final void removeDyingProviderLocked(ProcessRecord proc,
9060 ContentProviderRecord cpr) {
9061 synchronized (cpr) {
9062 cpr.launchingApp = null;
9063 cpr.notifyAll();
9064 }
9065
9066 mProvidersByClass.remove(cpr.info.name);
9067 String names[] = cpr.info.authority.split(";");
9068 for (int j = 0; j < names.length; j++) {
9069 mProvidersByName.remove(names[j]);
9070 }
9071
9072 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9073 while (cit.hasNext()) {
9074 ProcessRecord capp = cit.next();
9075 if (!capp.persistent && capp.thread != null
9076 && capp.pid != 0
9077 && capp.pid != MY_PID) {
9078 Log.i(TAG, "Killing app " + capp.processName
9079 + " (pid " + capp.pid
9080 + ") because provider " + cpr.info.name
9081 + " is in dying process " + proc.processName);
9082 Process.killProcess(capp.pid);
9083 }
9084 }
9085
9086 mLaunchingProviders.remove(cpr);
9087 }
9088
9089 /**
9090 * Main code for cleaning up a process when it has gone away. This is
9091 * called both as a result of the process dying, or directly when stopping
9092 * a process when running in single process mode.
9093 */
9094 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9095 boolean restarting, int index) {
9096 if (index >= 0) {
9097 mLRUProcesses.remove(index);
9098 }
9099
9100 // Dismiss any open dialogs.
9101 if (app.crashDialog != null) {
9102 app.crashDialog.dismiss();
9103 app.crashDialog = null;
9104 }
9105 if (app.anrDialog != null) {
9106 app.anrDialog.dismiss();
9107 app.anrDialog = null;
9108 }
9109 if (app.waitDialog != null) {
9110 app.waitDialog.dismiss();
9111 app.waitDialog = null;
9112 }
9113
9114 app.crashing = false;
9115 app.notResponding = false;
9116
9117 app.resetPackageList();
9118 app.thread = null;
9119 app.forcingToForeground = null;
9120 app.foregroundServices = false;
9121
9122 killServicesLocked(app, true);
9123
9124 boolean restart = false;
9125
9126 int NL = mLaunchingProviders.size();
9127
9128 // Remove published content providers.
9129 if (!app.pubProviders.isEmpty()) {
9130 Iterator it = app.pubProviders.values().iterator();
9131 while (it.hasNext()) {
9132 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9133 cpr.provider = null;
9134 cpr.app = null;
9135
9136 // See if someone is waiting for this provider... in which
9137 // case we don't remove it, but just let it restart.
9138 int i = 0;
9139 if (!app.bad) {
9140 for (; i<NL; i++) {
9141 if (mLaunchingProviders.get(i) == cpr) {
9142 restart = true;
9143 break;
9144 }
9145 }
9146 } else {
9147 i = NL;
9148 }
9149
9150 if (i >= NL) {
9151 removeDyingProviderLocked(app, cpr);
9152 NL = mLaunchingProviders.size();
9153 }
9154 }
9155 app.pubProviders.clear();
9156 }
9157
9158 // Look through the content providers we are waiting to have launched,
9159 // and if any run in this process then either schedule a restart of
9160 // the process or kill the client waiting for it if this process has
9161 // gone bad.
9162 for (int i=0; i<NL; i++) {
9163 ContentProviderRecord cpr = (ContentProviderRecord)
9164 mLaunchingProviders.get(i);
9165 if (cpr.launchingApp == app) {
9166 if (!app.bad) {
9167 restart = true;
9168 } else {
9169 removeDyingProviderLocked(app, cpr);
9170 NL = mLaunchingProviders.size();
9171 }
9172 }
9173 }
9174
9175 // Unregister from connected content providers.
9176 if (!app.conProviders.isEmpty()) {
9177 Iterator it = app.conProviders.iterator();
9178 while (it.hasNext()) {
9179 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9180 cpr.clients.remove(app);
9181 }
9182 app.conProviders.clear();
9183 }
9184
9185 skipCurrentReceiverLocked(app);
9186
9187 // Unregister any receivers.
9188 if (app.receivers.size() > 0) {
9189 Iterator<ReceiverList> it = app.receivers.iterator();
9190 while (it.hasNext()) {
9191 removeReceiverLocked(it.next());
9192 }
9193 app.receivers.clear();
9194 }
9195
Christopher Tate181fafa2009-05-14 11:12:14 -07009196 // If the app is undergoing backup, tell the backup manager about it
9197 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9198 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9199 try {
9200 IBackupManager bm = IBackupManager.Stub.asInterface(
9201 ServiceManager.getService(Context.BACKUP_SERVICE));
9202 bm.agentDisconnected(app.info.packageName);
9203 } catch (RemoteException e) {
9204 // can't happen; backup manager is local
9205 }
9206 }
9207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009208 // If the caller is restarting this app, then leave it in its
9209 // current lists and let the caller take care of it.
9210 if (restarting) {
9211 return;
9212 }
9213
9214 if (!app.persistent) {
9215 if (DEBUG_PROCESSES) Log.v(TAG,
9216 "Removing non-persistent process during cleanup: " + app);
9217 mProcessNames.remove(app.processName, app.info.uid);
9218 } else if (!app.removed) {
9219 // This app is persistent, so we need to keep its record around.
9220 // If it is not already on the pending app list, add it there
9221 // and start a new process for it.
9222 app.thread = null;
9223 app.forcingToForeground = null;
9224 app.foregroundServices = false;
9225 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9226 mPersistentStartingProcesses.add(app);
9227 restart = true;
9228 }
9229 }
9230 mProcessesOnHold.remove(app);
9231
The Android Open Source Project4df24232009-03-05 14:34:35 -08009232 if (app == mHomeProcess) {
9233 mHomeProcess = null;
9234 }
9235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009236 if (restart) {
9237 // We have components that still need to be running in the
9238 // process, so re-launch it.
9239 mProcessNames.put(app.processName, app.info.uid, app);
9240 startProcessLocked(app, "restart", app.processName);
9241 } else if (app.pid > 0 && app.pid != MY_PID) {
9242 // Goodbye!
9243 synchronized (mPidsSelfLocked) {
9244 mPidsSelfLocked.remove(app.pid);
9245 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9246 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009247 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009248 }
9249 }
9250
9251 // =========================================================
9252 // SERVICES
9253 // =========================================================
9254
9255 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9256 ActivityManager.RunningServiceInfo info =
9257 new ActivityManager.RunningServiceInfo();
9258 info.service = r.name;
9259 if (r.app != null) {
9260 info.pid = r.app.pid;
9261 }
9262 info.process = r.processName;
9263 info.foreground = r.isForeground;
9264 info.activeSince = r.createTime;
9265 info.started = r.startRequested;
9266 info.clientCount = r.connections.size();
9267 info.crashCount = r.crashCount;
9268 info.lastActivityTime = r.lastActivity;
9269 return info;
9270 }
9271
9272 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9273 int flags) {
9274 synchronized (this) {
9275 ArrayList<ActivityManager.RunningServiceInfo> res
9276 = new ArrayList<ActivityManager.RunningServiceInfo>();
9277
9278 if (mServices.size() > 0) {
9279 Iterator<ServiceRecord> it = mServices.values().iterator();
9280 while (it.hasNext() && res.size() < maxNum) {
9281 res.add(makeRunningServiceInfoLocked(it.next()));
9282 }
9283 }
9284
9285 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9286 ServiceRecord r = mRestartingServices.get(i);
9287 ActivityManager.RunningServiceInfo info =
9288 makeRunningServiceInfoLocked(r);
9289 info.restarting = r.nextRestartTime;
9290 res.add(info);
9291 }
9292
9293 return res;
9294 }
9295 }
9296
9297 private final ServiceRecord findServiceLocked(ComponentName name,
9298 IBinder token) {
9299 ServiceRecord r = mServices.get(name);
9300 return r == token ? r : null;
9301 }
9302
9303 private final class ServiceLookupResult {
9304 final ServiceRecord record;
9305 final String permission;
9306
9307 ServiceLookupResult(ServiceRecord _record, String _permission) {
9308 record = _record;
9309 permission = _permission;
9310 }
9311 };
9312
9313 private ServiceLookupResult findServiceLocked(Intent service,
9314 String resolvedType) {
9315 ServiceRecord r = null;
9316 if (service.getComponent() != null) {
9317 r = mServices.get(service.getComponent());
9318 }
9319 if (r == null) {
9320 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9321 r = mServicesByIntent.get(filter);
9322 }
9323
9324 if (r == null) {
9325 try {
9326 ResolveInfo rInfo =
9327 ActivityThread.getPackageManager().resolveService(
9328 service, resolvedType, 0);
9329 ServiceInfo sInfo =
9330 rInfo != null ? rInfo.serviceInfo : null;
9331 if (sInfo == null) {
9332 return null;
9333 }
9334
9335 ComponentName name = new ComponentName(
9336 sInfo.applicationInfo.packageName, sInfo.name);
9337 r = mServices.get(name);
9338 } catch (RemoteException ex) {
9339 // pm is in same process, this will never happen.
9340 }
9341 }
9342 if (r != null) {
9343 int callingPid = Binder.getCallingPid();
9344 int callingUid = Binder.getCallingUid();
9345 if (checkComponentPermission(r.permission,
9346 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9347 != PackageManager.PERMISSION_GRANTED) {
9348 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9349 + " from pid=" + callingPid
9350 + ", uid=" + callingUid
9351 + " requires " + r.permission);
9352 return new ServiceLookupResult(null, r.permission);
9353 }
9354 return new ServiceLookupResult(r, null);
9355 }
9356 return null;
9357 }
9358
9359 private class ServiceRestarter implements Runnable {
9360 private ServiceRecord mService;
9361
9362 void setService(ServiceRecord service) {
9363 mService = service;
9364 }
9365
9366 public void run() {
9367 synchronized(ActivityManagerService.this) {
9368 performServiceRestartLocked(mService);
9369 }
9370 }
9371 }
9372
9373 private ServiceLookupResult retrieveServiceLocked(Intent service,
9374 String resolvedType, int callingPid, int callingUid) {
9375 ServiceRecord r = null;
9376 if (service.getComponent() != null) {
9377 r = mServices.get(service.getComponent());
9378 }
9379 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9380 r = mServicesByIntent.get(filter);
9381 if (r == null) {
9382 try {
9383 ResolveInfo rInfo =
9384 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009385 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009386 ServiceInfo sInfo =
9387 rInfo != null ? rInfo.serviceInfo : null;
9388 if (sInfo == null) {
9389 Log.w(TAG, "Unable to start service " + service +
9390 ": not found");
9391 return null;
9392 }
9393
9394 ComponentName name = new ComponentName(
9395 sInfo.applicationInfo.packageName, sInfo.name);
9396 r = mServices.get(name);
9397 if (r == null) {
9398 filter = new Intent.FilterComparison(service.cloneFilter());
9399 ServiceRestarter res = new ServiceRestarter();
9400 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9401 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9402 synchronized (stats) {
9403 ss = stats.getServiceStatsLocked(
9404 sInfo.applicationInfo.uid, sInfo.packageName,
9405 sInfo.name);
9406 }
9407 r = new ServiceRecord(ss, name, filter, sInfo, res);
9408 res.setService(r);
9409 mServices.put(name, r);
9410 mServicesByIntent.put(filter, r);
9411
9412 // Make sure this component isn't in the pending list.
9413 int N = mPendingServices.size();
9414 for (int i=0; i<N; i++) {
9415 ServiceRecord pr = mPendingServices.get(i);
9416 if (pr.name.equals(name)) {
9417 mPendingServices.remove(i);
9418 i--;
9419 N--;
9420 }
9421 }
9422 }
9423 } catch (RemoteException ex) {
9424 // pm is in same process, this will never happen.
9425 }
9426 }
9427 if (r != null) {
9428 if (checkComponentPermission(r.permission,
9429 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9430 != PackageManager.PERMISSION_GRANTED) {
9431 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9432 + " from pid=" + Binder.getCallingPid()
9433 + ", uid=" + Binder.getCallingUid()
9434 + " requires " + r.permission);
9435 return new ServiceLookupResult(null, r.permission);
9436 }
9437 return new ServiceLookupResult(r, null);
9438 }
9439 return null;
9440 }
9441
9442 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9443 long now = SystemClock.uptimeMillis();
9444 if (r.executeNesting == 0 && r.app != null) {
9445 if (r.app.executingServices.size() == 0) {
9446 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9447 msg.obj = r.app;
9448 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9449 }
9450 r.app.executingServices.add(r);
9451 }
9452 r.executeNesting++;
9453 r.executingStart = now;
9454 }
9455
9456 private final void sendServiceArgsLocked(ServiceRecord r,
9457 boolean oomAdjusted) {
9458 final int N = r.startArgs.size();
9459 if (N == 0) {
9460 return;
9461 }
9462
9463 final int BASEID = r.lastStartId - N + 1;
9464 int i = 0;
9465 while (i < N) {
9466 try {
9467 Intent args = r.startArgs.get(i);
9468 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9469 + r.name + " " + r.intent + " args=" + args);
9470 bumpServiceExecutingLocked(r);
9471 if (!oomAdjusted) {
9472 oomAdjusted = true;
9473 updateOomAdjLocked(r.app);
9474 }
9475 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9476 i++;
9477 } catch (Exception e) {
9478 break;
9479 }
9480 }
9481 if (i == N) {
9482 r.startArgs.clear();
9483 } else {
9484 while (i > 0) {
9485 r.startArgs.remove(0);
9486 i--;
9487 }
9488 }
9489 }
9490
9491 private final boolean requestServiceBindingLocked(ServiceRecord r,
9492 IntentBindRecord i, boolean rebind) {
9493 if (r.app == null || r.app.thread == null) {
9494 // If service is not currently running, can't yet bind.
9495 return false;
9496 }
9497 if ((!i.requested || rebind) && i.apps.size() > 0) {
9498 try {
9499 bumpServiceExecutingLocked(r);
9500 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9501 + ": shouldUnbind=" + i.hasBound);
9502 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9503 if (!rebind) {
9504 i.requested = true;
9505 }
9506 i.hasBound = true;
9507 i.doRebind = false;
9508 } catch (RemoteException e) {
9509 return false;
9510 }
9511 }
9512 return true;
9513 }
9514
9515 private final void requestServiceBindingsLocked(ServiceRecord r) {
9516 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9517 while (bindings.hasNext()) {
9518 IntentBindRecord i = bindings.next();
9519 if (!requestServiceBindingLocked(r, i, false)) {
9520 break;
9521 }
9522 }
9523 }
9524
9525 private final void realStartServiceLocked(ServiceRecord r,
9526 ProcessRecord app) throws RemoteException {
9527 if (app.thread == null) {
9528 throw new RemoteException();
9529 }
9530
9531 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009532 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009533
9534 app.services.add(r);
9535 bumpServiceExecutingLocked(r);
9536 updateLRUListLocked(app, true);
9537
9538 boolean created = false;
9539 try {
9540 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9541 + r.name + " " + r.intent);
9542 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9543 System.identityHashCode(r), r.shortName,
9544 r.intent.getIntent().toString(), r.app.pid);
9545 synchronized (r.stats.getBatteryStats()) {
9546 r.stats.startLaunchedLocked();
9547 }
9548 app.thread.scheduleCreateService(r, r.serviceInfo);
9549 created = true;
9550 } finally {
9551 if (!created) {
9552 app.services.remove(r);
9553 scheduleServiceRestartLocked(r);
9554 }
9555 }
9556
9557 requestServiceBindingsLocked(r);
9558 sendServiceArgsLocked(r, true);
9559 }
9560
9561 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9562 r.totalRestartCount++;
9563 if (r.restartDelay == 0) {
9564 r.restartCount++;
9565 r.restartDelay = SERVICE_RESTART_DURATION;
9566 } else {
9567 // If it has been a "reasonably long time" since the service
9568 // was started, then reset our restart duration back to
9569 // the beginning, so we don't infinitely increase the duration
9570 // on a service that just occasionally gets killed (which is
9571 // a normal case, due to process being killed to reclaim memory).
9572 long now = SystemClock.uptimeMillis();
9573 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9574 r.restartCount = 1;
9575 r.restartDelay = SERVICE_RESTART_DURATION;
9576 } else {
9577 r.restartDelay *= 2;
9578 }
9579 }
9580 if (!mRestartingServices.contains(r)) {
9581 mRestartingServices.add(r);
9582 }
9583 mHandler.removeCallbacks(r.restarter);
9584 mHandler.postDelayed(r.restarter, r.restartDelay);
9585 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9586 Log.w(TAG, "Scheduling restart of crashed service "
9587 + r.shortName + " in " + r.restartDelay + "ms");
9588 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9589 r.shortName, r.restartDelay);
9590
9591 Message msg = Message.obtain();
9592 msg.what = SERVICE_ERROR_MSG;
9593 msg.obj = r;
9594 mHandler.sendMessage(msg);
9595 }
9596
9597 final void performServiceRestartLocked(ServiceRecord r) {
9598 if (!mRestartingServices.contains(r)) {
9599 return;
9600 }
9601 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9602 }
9603
9604 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9605 if (r.restartDelay == 0) {
9606 return false;
9607 }
9608 r.resetRestartCounter();
9609 mRestartingServices.remove(r);
9610 mHandler.removeCallbacks(r.restarter);
9611 return true;
9612 }
9613
9614 private final boolean bringUpServiceLocked(ServiceRecord r,
9615 int intentFlags, boolean whileRestarting) {
9616 //Log.i(TAG, "Bring up service:");
9617 //r.dump(" ");
9618
9619 if (r.app != null) {
9620 sendServiceArgsLocked(r, false);
9621 return true;
9622 }
9623
9624 if (!whileRestarting && r.restartDelay > 0) {
9625 // If waiting for a restart, then do nothing.
9626 return true;
9627 }
9628
9629 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9630 + " " + r.intent);
9631
9632 final String appName = r.processName;
9633 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9634 if (app != null && app.thread != null) {
9635 try {
9636 realStartServiceLocked(r, app);
9637 return true;
9638 } catch (RemoteException e) {
9639 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9640 }
9641
9642 // If a dead object exception was thrown -- fall through to
9643 // restart the application.
9644 }
9645
9646 if (!mPendingServices.contains(r)) {
9647 // Not running -- get it started, and enqueue this service record
9648 // to be executed when the app comes up.
9649 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9650 "service", r.name) == null) {
9651 Log.w(TAG, "Unable to launch app "
9652 + r.appInfo.packageName + "/"
9653 + r.appInfo.uid + " for service "
9654 + r.intent.getIntent() + ": process is bad");
9655 bringDownServiceLocked(r, true);
9656 return false;
9657 }
9658 mPendingServices.add(r);
9659 }
9660 return true;
9661 }
9662
9663 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9664 //Log.i(TAG, "Bring down service:");
9665 //r.dump(" ");
9666
9667 // Does it still need to run?
9668 if (!force && r.startRequested) {
9669 return;
9670 }
9671 if (r.connections.size() > 0) {
9672 if (!force) {
9673 // XXX should probably keep a count of the number of auto-create
9674 // connections directly in the service.
9675 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9676 while (it.hasNext()) {
9677 ConnectionRecord cr = it.next();
9678 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9679 return;
9680 }
9681 }
9682 }
9683
9684 // Report to all of the connections that the service is no longer
9685 // available.
9686 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9687 while (it.hasNext()) {
9688 ConnectionRecord c = it.next();
9689 try {
9690 // todo: shouldn't be a synchronous call!
9691 c.conn.connected(r.name, null);
9692 } catch (Exception e) {
9693 Log.w(TAG, "Failure disconnecting service " + r.name +
9694 " to connection " + c.conn.asBinder() +
9695 " (in " + c.binding.client.processName + ")", e);
9696 }
9697 }
9698 }
9699
9700 // Tell the service that it has been unbound.
9701 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9702 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9703 while (it.hasNext()) {
9704 IntentBindRecord ibr = it.next();
9705 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9706 + ": hasBound=" + ibr.hasBound);
9707 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9708 try {
9709 bumpServiceExecutingLocked(r);
9710 updateOomAdjLocked(r.app);
9711 ibr.hasBound = false;
9712 r.app.thread.scheduleUnbindService(r,
9713 ibr.intent.getIntent());
9714 } catch (Exception e) {
9715 Log.w(TAG, "Exception when unbinding service "
9716 + r.shortName, e);
9717 serviceDoneExecutingLocked(r, true);
9718 }
9719 }
9720 }
9721 }
9722
9723 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9724 + " " + r.intent);
9725 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9726 System.identityHashCode(r), r.shortName,
9727 (r.app != null) ? r.app.pid : -1);
9728
9729 mServices.remove(r.name);
9730 mServicesByIntent.remove(r.intent);
9731 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9732 r.totalRestartCount = 0;
9733 unscheduleServiceRestartLocked(r);
9734
9735 // Also make sure it is not on the pending list.
9736 int N = mPendingServices.size();
9737 for (int i=0; i<N; i++) {
9738 if (mPendingServices.get(i) == r) {
9739 mPendingServices.remove(i);
9740 if (DEBUG_SERVICE) Log.v(
9741 TAG, "Removed pending service: " + r.shortName);
9742 i--;
9743 N--;
9744 }
9745 }
9746
9747 if (r.app != null) {
9748 synchronized (r.stats.getBatteryStats()) {
9749 r.stats.stopLaunchedLocked();
9750 }
9751 r.app.services.remove(r);
9752 if (r.app.thread != null) {
9753 updateServiceForegroundLocked(r.app, false);
9754 try {
9755 Log.i(TAG, "Stopping service: " + r.shortName);
9756 bumpServiceExecutingLocked(r);
9757 mStoppingServices.add(r);
9758 updateOomAdjLocked(r.app);
9759 r.app.thread.scheduleStopService(r);
9760 } catch (Exception e) {
9761 Log.w(TAG, "Exception when stopping service "
9762 + r.shortName, e);
9763 serviceDoneExecutingLocked(r, true);
9764 }
9765 } else {
9766 if (DEBUG_SERVICE) Log.v(
9767 TAG, "Removed service that has no process: " + r.shortName);
9768 }
9769 } else {
9770 if (DEBUG_SERVICE) Log.v(
9771 TAG, "Removed service that is not running: " + r.shortName);
9772 }
9773 }
9774
9775 ComponentName startServiceLocked(IApplicationThread caller,
9776 Intent service, String resolvedType,
9777 int callingPid, int callingUid) {
9778 synchronized(this) {
9779 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9780 + " type=" + resolvedType + " args=" + service.getExtras());
9781
9782 if (caller != null) {
9783 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9784 if (callerApp == null) {
9785 throw new SecurityException(
9786 "Unable to find app for caller " + caller
9787 + " (pid=" + Binder.getCallingPid()
9788 + ") when starting service " + service);
9789 }
9790 }
9791
9792 ServiceLookupResult res =
9793 retrieveServiceLocked(service, resolvedType,
9794 callingPid, callingUid);
9795 if (res == null) {
9796 return null;
9797 }
9798 if (res.record == null) {
9799 return new ComponentName("!", res.permission != null
9800 ? res.permission : "private to package");
9801 }
9802 ServiceRecord r = res.record;
9803 if (unscheduleServiceRestartLocked(r)) {
9804 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9805 + r.shortName);
9806 }
9807 r.startRequested = true;
9808 r.startArgs.add(service);
9809 r.lastStartId++;
9810 if (r.lastStartId < 1) {
9811 r.lastStartId = 1;
9812 }
9813 r.lastActivity = SystemClock.uptimeMillis();
9814 synchronized (r.stats.getBatteryStats()) {
9815 r.stats.startRunningLocked();
9816 }
9817 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9818 return new ComponentName("!", "Service process is bad");
9819 }
9820 return r.name;
9821 }
9822 }
9823
9824 public ComponentName startService(IApplicationThread caller, Intent service,
9825 String resolvedType) {
9826 // Refuse possible leaked file descriptors
9827 if (service != null && service.hasFileDescriptors() == true) {
9828 throw new IllegalArgumentException("File descriptors passed in Intent");
9829 }
9830
9831 synchronized(this) {
9832 final int callingPid = Binder.getCallingPid();
9833 final int callingUid = Binder.getCallingUid();
9834 final long origId = Binder.clearCallingIdentity();
9835 ComponentName res = startServiceLocked(caller, service,
9836 resolvedType, callingPid, callingUid);
9837 Binder.restoreCallingIdentity(origId);
9838 return res;
9839 }
9840 }
9841
9842 ComponentName startServiceInPackage(int uid,
9843 Intent service, String resolvedType) {
9844 synchronized(this) {
9845 final long origId = Binder.clearCallingIdentity();
9846 ComponentName res = startServiceLocked(null, service,
9847 resolvedType, -1, uid);
9848 Binder.restoreCallingIdentity(origId);
9849 return res;
9850 }
9851 }
9852
9853 public int stopService(IApplicationThread caller, Intent service,
9854 String resolvedType) {
9855 // Refuse possible leaked file descriptors
9856 if (service != null && service.hasFileDescriptors() == true) {
9857 throw new IllegalArgumentException("File descriptors passed in Intent");
9858 }
9859
9860 synchronized(this) {
9861 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9862 + " type=" + resolvedType);
9863
9864 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9865 if (caller != null && callerApp == null) {
9866 throw new SecurityException(
9867 "Unable to find app for caller " + caller
9868 + " (pid=" + Binder.getCallingPid()
9869 + ") when stopping service " + service);
9870 }
9871
9872 // If this service is active, make sure it is stopped.
9873 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9874 if (r != null) {
9875 if (r.record != null) {
9876 synchronized (r.record.stats.getBatteryStats()) {
9877 r.record.stats.stopRunningLocked();
9878 }
9879 r.record.startRequested = false;
9880 final long origId = Binder.clearCallingIdentity();
9881 bringDownServiceLocked(r.record, false);
9882 Binder.restoreCallingIdentity(origId);
9883 return 1;
9884 }
9885 return -1;
9886 }
9887 }
9888
9889 return 0;
9890 }
9891
9892 public IBinder peekService(Intent service, String resolvedType) {
9893 // Refuse possible leaked file descriptors
9894 if (service != null && service.hasFileDescriptors() == true) {
9895 throw new IllegalArgumentException("File descriptors passed in Intent");
9896 }
9897
9898 IBinder ret = null;
9899
9900 synchronized(this) {
9901 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9902
9903 if (r != null) {
9904 // r.record is null if findServiceLocked() failed the caller permission check
9905 if (r.record == null) {
9906 throw new SecurityException(
9907 "Permission Denial: Accessing service " + r.record.name
9908 + " from pid=" + Binder.getCallingPid()
9909 + ", uid=" + Binder.getCallingUid()
9910 + " requires " + r.permission);
9911 }
9912 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9913 if (ib != null) {
9914 ret = ib.binder;
9915 }
9916 }
9917 }
9918
9919 return ret;
9920 }
9921
9922 public boolean stopServiceToken(ComponentName className, IBinder token,
9923 int startId) {
9924 synchronized(this) {
9925 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9926 + " " + token + " startId=" + startId);
9927 ServiceRecord r = findServiceLocked(className, token);
9928 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9929 synchronized (r.stats.getBatteryStats()) {
9930 r.stats.stopRunningLocked();
9931 r.startRequested = false;
9932 }
9933 final long origId = Binder.clearCallingIdentity();
9934 bringDownServiceLocked(r, false);
9935 Binder.restoreCallingIdentity(origId);
9936 return true;
9937 }
9938 }
9939 return false;
9940 }
9941
9942 public void setServiceForeground(ComponentName className, IBinder token,
9943 boolean isForeground) {
9944 synchronized(this) {
9945 ServiceRecord r = findServiceLocked(className, token);
9946 if (r != null) {
9947 if (r.isForeground != isForeground) {
9948 final long origId = Binder.clearCallingIdentity();
9949 r.isForeground = isForeground;
9950 if (r.app != null) {
9951 updateServiceForegroundLocked(r.app, true);
9952 }
9953 Binder.restoreCallingIdentity(origId);
9954 }
9955 }
9956 }
9957 }
9958
9959 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
9960 boolean anyForeground = false;
9961 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
9962 if (sr.isForeground) {
9963 anyForeground = true;
9964 break;
9965 }
9966 }
9967 if (anyForeground != proc.foregroundServices) {
9968 proc.foregroundServices = anyForeground;
9969 if (oomAdj) {
9970 updateOomAdjLocked();
9971 }
9972 }
9973 }
9974
9975 public int bindService(IApplicationThread caller, IBinder token,
9976 Intent service, String resolvedType,
9977 IServiceConnection connection, int flags) {
9978 // Refuse possible leaked file descriptors
9979 if (service != null && service.hasFileDescriptors() == true) {
9980 throw new IllegalArgumentException("File descriptors passed in Intent");
9981 }
9982
9983 synchronized(this) {
9984 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
9985 + " type=" + resolvedType + " conn=" + connection.asBinder()
9986 + " flags=0x" + Integer.toHexString(flags));
9987 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9988 if (callerApp == null) {
9989 throw new SecurityException(
9990 "Unable to find app for caller " + caller
9991 + " (pid=" + Binder.getCallingPid()
9992 + ") when binding service " + service);
9993 }
9994
9995 HistoryRecord activity = null;
9996 if (token != null) {
9997 int aindex = indexOfTokenLocked(token, false);
9998 if (aindex < 0) {
9999 Log.w(TAG, "Binding with unknown activity: " + token);
10000 return 0;
10001 }
10002 activity = (HistoryRecord)mHistory.get(aindex);
10003 }
10004
10005 ServiceLookupResult res =
10006 retrieveServiceLocked(service, resolvedType,
10007 Binder.getCallingPid(), Binder.getCallingUid());
10008 if (res == null) {
10009 return 0;
10010 }
10011 if (res.record == null) {
10012 return -1;
10013 }
10014 ServiceRecord s = res.record;
10015
10016 final long origId = Binder.clearCallingIdentity();
10017
10018 if (unscheduleServiceRestartLocked(s)) {
10019 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10020 + s.shortName);
10021 }
10022
10023 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10024 ConnectionRecord c = new ConnectionRecord(b, activity,
10025 connection, flags);
10026
10027 IBinder binder = connection.asBinder();
10028 s.connections.put(binder, c);
10029 b.connections.add(c);
10030 if (activity != null) {
10031 if (activity.connections == null) {
10032 activity.connections = new HashSet<ConnectionRecord>();
10033 }
10034 activity.connections.add(c);
10035 }
10036 b.client.connections.add(c);
10037 mServiceConnections.put(binder, c);
10038
10039 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10040 s.lastActivity = SystemClock.uptimeMillis();
10041 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10042 return 0;
10043 }
10044 }
10045
10046 if (s.app != null) {
10047 // This could have made the service more important.
10048 updateOomAdjLocked(s.app);
10049 }
10050
10051 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10052 + ": received=" + b.intent.received
10053 + " apps=" + b.intent.apps.size()
10054 + " doRebind=" + b.intent.doRebind);
10055
10056 if (s.app != null && b.intent.received) {
10057 // Service is already running, so we can immediately
10058 // publish the connection.
10059 try {
10060 c.conn.connected(s.name, b.intent.binder);
10061 } catch (Exception e) {
10062 Log.w(TAG, "Failure sending service " + s.shortName
10063 + " to connection " + c.conn.asBinder()
10064 + " (in " + c.binding.client.processName + ")", e);
10065 }
10066
10067 // If this is the first app connected back to this binding,
10068 // and the service had previously asked to be told when
10069 // rebound, then do so.
10070 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10071 requestServiceBindingLocked(s, b.intent, true);
10072 }
10073 } else if (!b.intent.requested) {
10074 requestServiceBindingLocked(s, b.intent, false);
10075 }
10076
10077 Binder.restoreCallingIdentity(origId);
10078 }
10079
10080 return 1;
10081 }
10082
10083 private void removeConnectionLocked(
10084 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10085 IBinder binder = c.conn.asBinder();
10086 AppBindRecord b = c.binding;
10087 ServiceRecord s = b.service;
10088 s.connections.remove(binder);
10089 b.connections.remove(c);
10090 if (c.activity != null && c.activity != skipAct) {
10091 if (c.activity.connections != null) {
10092 c.activity.connections.remove(c);
10093 }
10094 }
10095 if (b.client != skipApp) {
10096 b.client.connections.remove(c);
10097 }
10098 mServiceConnections.remove(binder);
10099
10100 if (b.connections.size() == 0) {
10101 b.intent.apps.remove(b.client);
10102 }
10103
10104 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10105 + ": shouldUnbind=" + b.intent.hasBound);
10106 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10107 && b.intent.hasBound) {
10108 try {
10109 bumpServiceExecutingLocked(s);
10110 updateOomAdjLocked(s.app);
10111 b.intent.hasBound = false;
10112 // Assume the client doesn't want to know about a rebind;
10113 // we will deal with that later if it asks for one.
10114 b.intent.doRebind = false;
10115 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10116 } catch (Exception e) {
10117 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10118 serviceDoneExecutingLocked(s, true);
10119 }
10120 }
10121
10122 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10123 bringDownServiceLocked(s, false);
10124 }
10125 }
10126
10127 public boolean unbindService(IServiceConnection connection) {
10128 synchronized (this) {
10129 IBinder binder = connection.asBinder();
10130 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10131 ConnectionRecord r = mServiceConnections.get(binder);
10132 if (r == null) {
10133 Log.w(TAG, "Unbind failed: could not find connection for "
10134 + connection.asBinder());
10135 return false;
10136 }
10137
10138 final long origId = Binder.clearCallingIdentity();
10139
10140 removeConnectionLocked(r, null, null);
10141
10142 if (r.binding.service.app != null) {
10143 // This could have made the service less important.
10144 updateOomAdjLocked(r.binding.service.app);
10145 }
10146
10147 Binder.restoreCallingIdentity(origId);
10148 }
10149
10150 return true;
10151 }
10152
10153 public void publishService(IBinder token, Intent intent, IBinder service) {
10154 // Refuse possible leaked file descriptors
10155 if (intent != null && intent.hasFileDescriptors() == true) {
10156 throw new IllegalArgumentException("File descriptors passed in Intent");
10157 }
10158
10159 synchronized(this) {
10160 if (!(token instanceof ServiceRecord)) {
10161 throw new IllegalArgumentException("Invalid service token");
10162 }
10163 ServiceRecord r = (ServiceRecord)token;
10164
10165 final long origId = Binder.clearCallingIdentity();
10166
10167 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10168 + " " + intent + ": " + service);
10169 if (r != null) {
10170 Intent.FilterComparison filter
10171 = new Intent.FilterComparison(intent);
10172 IntentBindRecord b = r.bindings.get(filter);
10173 if (b != null && !b.received) {
10174 b.binder = service;
10175 b.requested = true;
10176 b.received = true;
10177 if (r.connections.size() > 0) {
10178 Iterator<ConnectionRecord> it
10179 = r.connections.values().iterator();
10180 while (it.hasNext()) {
10181 ConnectionRecord c = it.next();
10182 if (!filter.equals(c.binding.intent.intent)) {
10183 if (DEBUG_SERVICE) Log.v(
10184 TAG, "Not publishing to: " + c);
10185 if (DEBUG_SERVICE) Log.v(
10186 TAG, "Bound intent: " + c.binding.intent.intent);
10187 if (DEBUG_SERVICE) Log.v(
10188 TAG, "Published intent: " + intent);
10189 continue;
10190 }
10191 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10192 try {
10193 c.conn.connected(r.name, service);
10194 } catch (Exception e) {
10195 Log.w(TAG, "Failure sending service " + r.name +
10196 " to connection " + c.conn.asBinder() +
10197 " (in " + c.binding.client.processName + ")", e);
10198 }
10199 }
10200 }
10201 }
10202
10203 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10204
10205 Binder.restoreCallingIdentity(origId);
10206 }
10207 }
10208 }
10209
10210 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10211 // Refuse possible leaked file descriptors
10212 if (intent != null && intent.hasFileDescriptors() == true) {
10213 throw new IllegalArgumentException("File descriptors passed in Intent");
10214 }
10215
10216 synchronized(this) {
10217 if (!(token instanceof ServiceRecord)) {
10218 throw new IllegalArgumentException("Invalid service token");
10219 }
10220 ServiceRecord r = (ServiceRecord)token;
10221
10222 final long origId = Binder.clearCallingIdentity();
10223
10224 if (r != null) {
10225 Intent.FilterComparison filter
10226 = new Intent.FilterComparison(intent);
10227 IntentBindRecord b = r.bindings.get(filter);
10228 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10229 + " at " + b + ": apps="
10230 + (b != null ? b.apps.size() : 0));
10231 if (b != null) {
10232 if (b.apps.size() > 0) {
10233 // Applications have already bound since the last
10234 // unbind, so just rebind right here.
10235 requestServiceBindingLocked(r, b, true);
10236 } else {
10237 // Note to tell the service the next time there is
10238 // a new client.
10239 b.doRebind = true;
10240 }
10241 }
10242
10243 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10244
10245 Binder.restoreCallingIdentity(origId);
10246 }
10247 }
10248 }
10249
10250 public void serviceDoneExecuting(IBinder token) {
10251 synchronized(this) {
10252 if (!(token instanceof ServiceRecord)) {
10253 throw new IllegalArgumentException("Invalid service token");
10254 }
10255 ServiceRecord r = (ServiceRecord)token;
10256 boolean inStopping = mStoppingServices.contains(token);
10257 if (r != null) {
10258 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10259 + ": nesting=" + r.executeNesting
10260 + ", inStopping=" + inStopping);
10261 if (r != token) {
10262 Log.w(TAG, "Done executing service " + r.name
10263 + " with incorrect token: given " + token
10264 + ", expected " + r);
10265 return;
10266 }
10267
10268 final long origId = Binder.clearCallingIdentity();
10269 serviceDoneExecutingLocked(r, inStopping);
10270 Binder.restoreCallingIdentity(origId);
10271 } else {
10272 Log.w(TAG, "Done executing unknown service " + r.name
10273 + " with token " + token);
10274 }
10275 }
10276 }
10277
10278 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10279 r.executeNesting--;
10280 if (r.executeNesting <= 0 && r.app != null) {
10281 r.app.executingServices.remove(r);
10282 if (r.app.executingServices.size() == 0) {
10283 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10284 }
10285 if (inStopping) {
10286 mStoppingServices.remove(r);
10287 }
10288 updateOomAdjLocked(r.app);
10289 }
10290 }
10291
10292 void serviceTimeout(ProcessRecord proc) {
10293 synchronized(this) {
10294 if (proc.executingServices.size() == 0 || proc.thread == null) {
10295 return;
10296 }
10297 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10298 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10299 ServiceRecord timeout = null;
10300 long nextTime = 0;
10301 while (it.hasNext()) {
10302 ServiceRecord sr = it.next();
10303 if (sr.executingStart < maxTime) {
10304 timeout = sr;
10305 break;
10306 }
10307 if (sr.executingStart > nextTime) {
10308 nextTime = sr.executingStart;
10309 }
10310 }
10311 if (timeout != null && mLRUProcesses.contains(proc)) {
10312 Log.w(TAG, "Timeout executing service: " + timeout);
10313 appNotRespondingLocked(proc, null, "Executing service "
10314 + timeout.name);
10315 } else {
10316 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10317 msg.obj = proc;
10318 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10319 }
10320 }
10321 }
10322
10323 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010324 // BACKUP AND RESTORE
10325 // =========================================================
10326
10327 // Cause the target app to be launched if necessary and its backup agent
10328 // instantiated. The backup agent will invoke backupAgentCreated() on the
10329 // activity manager to announce its creation.
10330 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10331 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10332 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10333
10334 synchronized(this) {
10335 // !!! TODO: currently no check here that we're already bound
10336 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10337 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10338 synchronized (stats) {
10339 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10340 }
10341
10342 BackupRecord r = new BackupRecord(ss, app, backupMode);
10343 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10344 // startProcessLocked() returns existing proc's record if it's already running
10345 ProcessRecord proc = startProcessLocked(app.processName, app,
10346 false, 0, "backup", hostingName);
10347 if (proc == null) {
10348 Log.e(TAG, "Unable to start backup agent process " + r);
10349 return false;
10350 }
10351
10352 r.app = proc;
10353 mBackupTarget = r;
10354 mBackupAppName = app.packageName;
10355
Christopher Tate6fa95972009-06-05 18:43:55 -070010356 // Try not to kill the process during backup
10357 updateOomAdjLocked(proc);
10358
Christopher Tate181fafa2009-05-14 11:12:14 -070010359 // If the process is already attached, schedule the creation of the backup agent now.
10360 // If it is not yet live, this will be done when it attaches to the framework.
10361 if (proc.thread != null) {
10362 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10363 try {
10364 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10365 } catch (RemoteException e) {
10366 // !!! TODO: notify the backup manager that we crashed, or rely on
10367 // death notices, or...?
10368 }
10369 } else {
10370 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10371 }
10372 // Invariants: at this point, the target app process exists and the application
10373 // is either already running or in the process of coming up. mBackupTarget and
10374 // mBackupAppName describe the app, so that when it binds back to the AM we
10375 // know that it's scheduled for a backup-agent operation.
10376 }
10377
10378 return true;
10379 }
10380
10381 // A backup agent has just come up
10382 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10383 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10384 + " = " + agent);
10385
10386 synchronized(this) {
10387 if (!agentPackageName.equals(mBackupAppName)) {
10388 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10389 return;
10390 }
10391
Christopher Tate043dadc2009-06-02 16:11:00 -070010392 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010393 try {
10394 IBackupManager bm = IBackupManager.Stub.asInterface(
10395 ServiceManager.getService(Context.BACKUP_SERVICE));
10396 bm.agentConnected(agentPackageName, agent);
10397 } catch (RemoteException e) {
10398 // can't happen; the backup manager service is local
10399 } catch (Exception e) {
10400 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10401 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010402 } finally {
10403 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010404 }
10405 }
10406 }
10407
10408 // done with this agent
10409 public void unbindBackupAgent(ApplicationInfo appInfo) {
10410 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
10411
10412 synchronized(this) {
10413 if (!mBackupAppName.equals(appInfo.packageName)) {
10414 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10415 return;
10416 }
10417
Christopher Tate6fa95972009-06-05 18:43:55 -070010418 ProcessRecord proc = mBackupTarget.app;
10419 mBackupTarget = null;
10420 mBackupAppName = null;
10421
10422 // Not backing this app up any more; reset its OOM adjustment
10423 updateOomAdjLocked(proc);
10424
Christopher Tate181fafa2009-05-14 11:12:14 -070010425 try {
Christopher Tate6fa95972009-06-05 18:43:55 -070010426 proc.thread.scheduleDestroyBackupAgent(appInfo);
Christopher Tate181fafa2009-05-14 11:12:14 -070010427 } catch (Exception e) {
10428 Log.e(TAG, "Exception when unbinding backup agent:");
10429 e.printStackTrace();
10430 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010431 }
10432 }
10433 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010434 // BROADCASTS
10435 // =========================================================
10436
10437 private final List getStickies(String action, IntentFilter filter,
10438 List cur) {
10439 final ContentResolver resolver = mContext.getContentResolver();
10440 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10441 if (list == null) {
10442 return cur;
10443 }
10444 int N = list.size();
10445 for (int i=0; i<N; i++) {
10446 Intent intent = list.get(i);
10447 if (filter.match(resolver, intent, true, TAG) >= 0) {
10448 if (cur == null) {
10449 cur = new ArrayList<Intent>();
10450 }
10451 cur.add(intent);
10452 }
10453 }
10454 return cur;
10455 }
10456
10457 private final void scheduleBroadcastsLocked() {
10458 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10459 + mBroadcastsScheduled);
10460
10461 if (mBroadcastsScheduled) {
10462 return;
10463 }
10464 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10465 mBroadcastsScheduled = true;
10466 }
10467
10468 public Intent registerReceiver(IApplicationThread caller,
10469 IIntentReceiver receiver, IntentFilter filter, String permission) {
10470 synchronized(this) {
10471 ProcessRecord callerApp = null;
10472 if (caller != null) {
10473 callerApp = getRecordForAppLocked(caller);
10474 if (callerApp == null) {
10475 throw new SecurityException(
10476 "Unable to find app for caller " + caller
10477 + " (pid=" + Binder.getCallingPid()
10478 + ") when registering receiver " + receiver);
10479 }
10480 }
10481
10482 List allSticky = null;
10483
10484 // Look for any matching sticky broadcasts...
10485 Iterator actions = filter.actionsIterator();
10486 if (actions != null) {
10487 while (actions.hasNext()) {
10488 String action = (String)actions.next();
10489 allSticky = getStickies(action, filter, allSticky);
10490 }
10491 } else {
10492 allSticky = getStickies(null, filter, allSticky);
10493 }
10494
10495 // The first sticky in the list is returned directly back to
10496 // the client.
10497 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10498
10499 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10500 + ": " + sticky);
10501
10502 if (receiver == null) {
10503 return sticky;
10504 }
10505
10506 ReceiverList rl
10507 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10508 if (rl == null) {
10509 rl = new ReceiverList(this, callerApp,
10510 Binder.getCallingPid(),
10511 Binder.getCallingUid(), receiver);
10512 if (rl.app != null) {
10513 rl.app.receivers.add(rl);
10514 } else {
10515 try {
10516 receiver.asBinder().linkToDeath(rl, 0);
10517 } catch (RemoteException e) {
10518 return sticky;
10519 }
10520 rl.linkedToDeath = true;
10521 }
10522 mRegisteredReceivers.put(receiver.asBinder(), rl);
10523 }
10524 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10525 rl.add(bf);
10526 if (!bf.debugCheck()) {
10527 Log.w(TAG, "==> For Dynamic broadast");
10528 }
10529 mReceiverResolver.addFilter(bf);
10530
10531 // Enqueue broadcasts for all existing stickies that match
10532 // this filter.
10533 if (allSticky != null) {
10534 ArrayList receivers = new ArrayList();
10535 receivers.add(bf);
10536
10537 int N = allSticky.size();
10538 for (int i=0; i<N; i++) {
10539 Intent intent = (Intent)allSticky.get(i);
10540 BroadcastRecord r = new BroadcastRecord(intent, null,
10541 null, -1, -1, null, receivers, null, 0, null, null,
10542 false);
10543 if (mParallelBroadcasts.size() == 0) {
10544 scheduleBroadcastsLocked();
10545 }
10546 mParallelBroadcasts.add(r);
10547 }
10548 }
10549
10550 return sticky;
10551 }
10552 }
10553
10554 public void unregisterReceiver(IIntentReceiver receiver) {
10555 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10556
10557 boolean doNext = false;
10558
10559 synchronized(this) {
10560 ReceiverList rl
10561 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10562 if (rl != null) {
10563 if (rl.curBroadcast != null) {
10564 BroadcastRecord r = rl.curBroadcast;
10565 doNext = finishReceiverLocked(
10566 receiver.asBinder(), r.resultCode, r.resultData,
10567 r.resultExtras, r.resultAbort, true);
10568 }
10569
10570 if (rl.app != null) {
10571 rl.app.receivers.remove(rl);
10572 }
10573 removeReceiverLocked(rl);
10574 if (rl.linkedToDeath) {
10575 rl.linkedToDeath = false;
10576 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10577 }
10578 }
10579 }
10580
10581 if (!doNext) {
10582 return;
10583 }
10584
10585 final long origId = Binder.clearCallingIdentity();
10586 processNextBroadcast(false);
10587 trimApplications();
10588 Binder.restoreCallingIdentity(origId);
10589 }
10590
10591 void removeReceiverLocked(ReceiverList rl) {
10592 mRegisteredReceivers.remove(rl.receiver.asBinder());
10593 int N = rl.size();
10594 for (int i=0; i<N; i++) {
10595 mReceiverResolver.removeFilter(rl.get(i));
10596 }
10597 }
10598
10599 private final int broadcastIntentLocked(ProcessRecord callerApp,
10600 String callerPackage, Intent intent, String resolvedType,
10601 IIntentReceiver resultTo, int resultCode, String resultData,
10602 Bundle map, String requiredPermission,
10603 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10604 intent = new Intent(intent);
10605
10606 if (DEBUG_BROADCAST) Log.v(
10607 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10608 + " ordered=" + ordered);
10609 if ((resultTo != null) && !ordered) {
10610 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10611 }
10612
10613 // Handle special intents: if this broadcast is from the package
10614 // manager about a package being removed, we need to remove all of
10615 // its activities from the history stack.
10616 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10617 intent.getAction());
10618 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10619 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10620 || uidRemoved) {
10621 if (checkComponentPermission(
10622 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10623 callingPid, callingUid, -1)
10624 == PackageManager.PERMISSION_GRANTED) {
10625 if (uidRemoved) {
10626 final Bundle intentExtras = intent.getExtras();
10627 final int uid = intentExtras != null
10628 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10629 if (uid >= 0) {
10630 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10631 synchronized (bs) {
10632 bs.removeUidStatsLocked(uid);
10633 }
10634 }
10635 } else {
10636 Uri data = intent.getData();
10637 String ssp;
10638 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10639 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10640 uninstallPackageLocked(ssp,
10641 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10642 }
10643 }
10644 }
10645 } else {
10646 String msg = "Permission Denial: " + intent.getAction()
10647 + " broadcast from " + callerPackage + " (pid=" + callingPid
10648 + ", uid=" + callingUid + ")"
10649 + " requires "
10650 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10651 Log.w(TAG, msg);
10652 throw new SecurityException(msg);
10653 }
10654 }
10655
10656 /*
10657 * If this is the time zone changed action, queue up a message that will reset the timezone
10658 * of all currently running processes. This message will get queued up before the broadcast
10659 * happens.
10660 */
10661 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10662 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10663 }
10664
10665 // Add to the sticky list if requested.
10666 if (sticky) {
10667 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10668 callingPid, callingUid)
10669 != PackageManager.PERMISSION_GRANTED) {
10670 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10671 + callingPid + ", uid=" + callingUid
10672 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10673 Log.w(TAG, msg);
10674 throw new SecurityException(msg);
10675 }
10676 if (requiredPermission != null) {
10677 Log.w(TAG, "Can't broadcast sticky intent " + intent
10678 + " and enforce permission " + requiredPermission);
10679 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10680 }
10681 if (intent.getComponent() != null) {
10682 throw new SecurityException(
10683 "Sticky broadcasts can't target a specific component");
10684 }
10685 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10686 if (list == null) {
10687 list = new ArrayList<Intent>();
10688 mStickyBroadcasts.put(intent.getAction(), list);
10689 }
10690 int N = list.size();
10691 int i;
10692 for (i=0; i<N; i++) {
10693 if (intent.filterEquals(list.get(i))) {
10694 // This sticky already exists, replace it.
10695 list.set(i, new Intent(intent));
10696 break;
10697 }
10698 }
10699 if (i >= N) {
10700 list.add(new Intent(intent));
10701 }
10702 }
10703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010704 // Figure out who all will receive this broadcast.
10705 List receivers = null;
10706 List<BroadcastFilter> registeredReceivers = null;
10707 try {
10708 if (intent.getComponent() != null) {
10709 // Broadcast is going to one specific receiver class...
10710 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010711 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010712 if (ai != null) {
10713 receivers = new ArrayList();
10714 ResolveInfo ri = new ResolveInfo();
10715 ri.activityInfo = ai;
10716 receivers.add(ri);
10717 }
10718 } else {
10719 // Need to resolve the intent to interested receivers...
10720 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10721 == 0) {
10722 receivers =
10723 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010724 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010725 }
Mihai Preda074edef2009-05-18 17:13:31 +020010726 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010727 }
10728 } catch (RemoteException ex) {
10729 // pm is in same process, this will never happen.
10730 }
10731
10732 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10733 if (!ordered && NR > 0) {
10734 // If we are not serializing this broadcast, then send the
10735 // registered receivers separately so they don't wait for the
10736 // components to be launched.
10737 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10738 callerPackage, callingPid, callingUid, requiredPermission,
10739 registeredReceivers, resultTo, resultCode, resultData, map,
10740 ordered);
10741 if (DEBUG_BROADCAST) Log.v(
10742 TAG, "Enqueueing parallel broadcast " + r
10743 + ": prev had " + mParallelBroadcasts.size());
10744 mParallelBroadcasts.add(r);
10745 scheduleBroadcastsLocked();
10746 registeredReceivers = null;
10747 NR = 0;
10748 }
10749
10750 // Merge into one list.
10751 int ir = 0;
10752 if (receivers != null) {
10753 // A special case for PACKAGE_ADDED: do not allow the package
10754 // being added to see this broadcast. This prevents them from
10755 // using this as a back door to get run as soon as they are
10756 // installed. Maybe in the future we want to have a special install
10757 // broadcast or such for apps, but we'd like to deliberately make
10758 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010759 boolean skip = false;
10760 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010761 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010762 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10763 skip = true;
10764 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10765 skip = true;
10766 }
10767 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010768 ? intent.getData().getSchemeSpecificPart()
10769 : null;
10770 if (skipPackage != null && receivers != null) {
10771 int NT = receivers.size();
10772 for (int it=0; it<NT; it++) {
10773 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10774 if (curt.activityInfo.packageName.equals(skipPackage)) {
10775 receivers.remove(it);
10776 it--;
10777 NT--;
10778 }
10779 }
10780 }
10781
10782 int NT = receivers != null ? receivers.size() : 0;
10783 int it = 0;
10784 ResolveInfo curt = null;
10785 BroadcastFilter curr = null;
10786 while (it < NT && ir < NR) {
10787 if (curt == null) {
10788 curt = (ResolveInfo)receivers.get(it);
10789 }
10790 if (curr == null) {
10791 curr = registeredReceivers.get(ir);
10792 }
10793 if (curr.getPriority() >= curt.priority) {
10794 // Insert this broadcast record into the final list.
10795 receivers.add(it, curr);
10796 ir++;
10797 curr = null;
10798 it++;
10799 NT++;
10800 } else {
10801 // Skip to the next ResolveInfo in the final list.
10802 it++;
10803 curt = null;
10804 }
10805 }
10806 }
10807 while (ir < NR) {
10808 if (receivers == null) {
10809 receivers = new ArrayList();
10810 }
10811 receivers.add(registeredReceivers.get(ir));
10812 ir++;
10813 }
10814
10815 if ((receivers != null && receivers.size() > 0)
10816 || resultTo != null) {
10817 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10818 callerPackage, callingPid, callingUid, requiredPermission,
10819 receivers, resultTo, resultCode, resultData, map, ordered);
10820 if (DEBUG_BROADCAST) Log.v(
10821 TAG, "Enqueueing ordered broadcast " + r
10822 + ": prev had " + mOrderedBroadcasts.size());
10823 if (DEBUG_BROADCAST) {
10824 int seq = r.intent.getIntExtra("seq", -1);
10825 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10826 }
10827 mOrderedBroadcasts.add(r);
10828 scheduleBroadcastsLocked();
10829 }
10830
10831 return BROADCAST_SUCCESS;
10832 }
10833
10834 public final int broadcastIntent(IApplicationThread caller,
10835 Intent intent, String resolvedType, IIntentReceiver resultTo,
10836 int resultCode, String resultData, Bundle map,
10837 String requiredPermission, boolean serialized, boolean sticky) {
10838 // Refuse possible leaked file descriptors
10839 if (intent != null && intent.hasFileDescriptors() == true) {
10840 throw new IllegalArgumentException("File descriptors passed in Intent");
10841 }
10842
10843 synchronized(this) {
10844 if (!mSystemReady) {
10845 // if the caller really truly claims to know what they're doing, go
10846 // ahead and allow the broadcast without launching any receivers
10847 int flags = intent.getFlags();
10848 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10849 intent = new Intent(intent);
10850 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10851 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10852 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10853 + " before boot completion");
10854 throw new IllegalStateException("Cannot broadcast before boot completed");
10855 }
10856 }
10857
10858 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10859 final int callingPid = Binder.getCallingPid();
10860 final int callingUid = Binder.getCallingUid();
10861 final long origId = Binder.clearCallingIdentity();
10862 int res = broadcastIntentLocked(callerApp,
10863 callerApp != null ? callerApp.info.packageName : null,
10864 intent, resolvedType, resultTo,
10865 resultCode, resultData, map, requiredPermission, serialized,
10866 sticky, callingPid, callingUid);
10867 Binder.restoreCallingIdentity(origId);
10868 return res;
10869 }
10870 }
10871
10872 int broadcastIntentInPackage(String packageName, int uid,
10873 Intent intent, String resolvedType, IIntentReceiver resultTo,
10874 int resultCode, String resultData, Bundle map,
10875 String requiredPermission, boolean serialized, boolean sticky) {
10876 synchronized(this) {
10877 final long origId = Binder.clearCallingIdentity();
10878 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10879 resultTo, resultCode, resultData, map, requiredPermission,
10880 serialized, sticky, -1, uid);
10881 Binder.restoreCallingIdentity(origId);
10882 return res;
10883 }
10884 }
10885
10886 public final void unbroadcastIntent(IApplicationThread caller,
10887 Intent intent) {
10888 // Refuse possible leaked file descriptors
10889 if (intent != null && intent.hasFileDescriptors() == true) {
10890 throw new IllegalArgumentException("File descriptors passed in Intent");
10891 }
10892
10893 synchronized(this) {
10894 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10895 != PackageManager.PERMISSION_GRANTED) {
10896 String msg = "Permission Denial: unbroadcastIntent() from pid="
10897 + Binder.getCallingPid()
10898 + ", uid=" + Binder.getCallingUid()
10899 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10900 Log.w(TAG, msg);
10901 throw new SecurityException(msg);
10902 }
10903 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10904 if (list != null) {
10905 int N = list.size();
10906 int i;
10907 for (i=0; i<N; i++) {
10908 if (intent.filterEquals(list.get(i))) {
10909 list.remove(i);
10910 break;
10911 }
10912 }
10913 }
10914 }
10915 }
10916
10917 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10918 String resultData, Bundle resultExtras, boolean resultAbort,
10919 boolean explicit) {
10920 if (mOrderedBroadcasts.size() == 0) {
10921 if (explicit) {
10922 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10923 }
10924 return false;
10925 }
10926 BroadcastRecord r = mOrderedBroadcasts.get(0);
10927 if (r.receiver == null) {
10928 if (explicit) {
10929 Log.w(TAG, "finishReceiver called but none active");
10930 }
10931 return false;
10932 }
10933 if (r.receiver != receiver) {
10934 Log.w(TAG, "finishReceiver called but active receiver is different");
10935 return false;
10936 }
10937 int state = r.state;
10938 r.state = r.IDLE;
10939 if (state == r.IDLE) {
10940 if (explicit) {
10941 Log.w(TAG, "finishReceiver called but state is IDLE");
10942 }
10943 }
10944 r.receiver = null;
10945 r.intent.setComponent(null);
10946 if (r.curApp != null) {
10947 r.curApp.curReceiver = null;
10948 }
10949 if (r.curFilter != null) {
10950 r.curFilter.receiverList.curBroadcast = null;
10951 }
10952 r.curFilter = null;
10953 r.curApp = null;
10954 r.curComponent = null;
10955 r.curReceiver = null;
10956 mPendingBroadcast = null;
10957
10958 r.resultCode = resultCode;
10959 r.resultData = resultData;
10960 r.resultExtras = resultExtras;
10961 r.resultAbort = resultAbort;
10962
10963 // We will process the next receiver right now if this is finishing
10964 // an app receiver (which is always asynchronous) or after we have
10965 // come back from calling a receiver.
10966 return state == BroadcastRecord.APP_RECEIVE
10967 || state == BroadcastRecord.CALL_DONE_RECEIVE;
10968 }
10969
10970 public void finishReceiver(IBinder who, int resultCode, String resultData,
10971 Bundle resultExtras, boolean resultAbort) {
10972 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
10973
10974 // Refuse possible leaked file descriptors
10975 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
10976 throw new IllegalArgumentException("File descriptors passed in Bundle");
10977 }
10978
10979 boolean doNext;
10980
10981 final long origId = Binder.clearCallingIdentity();
10982
10983 synchronized(this) {
10984 doNext = finishReceiverLocked(
10985 who, resultCode, resultData, resultExtras, resultAbort, true);
10986 }
10987
10988 if (doNext) {
10989 processNextBroadcast(false);
10990 }
10991 trimApplications();
10992
10993 Binder.restoreCallingIdentity(origId);
10994 }
10995
10996 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
10997 if (r.nextReceiver > 0) {
10998 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10999 if (curReceiver instanceof BroadcastFilter) {
11000 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11001 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11002 System.identityHashCode(r),
11003 r.intent.getAction(),
11004 r.nextReceiver - 1,
11005 System.identityHashCode(bf));
11006 } else {
11007 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11008 System.identityHashCode(r),
11009 r.intent.getAction(),
11010 r.nextReceiver - 1,
11011 ((ResolveInfo)curReceiver).toString());
11012 }
11013 } else {
11014 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11015 + r);
11016 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11017 System.identityHashCode(r),
11018 r.intent.getAction(),
11019 r.nextReceiver,
11020 "NONE");
11021 }
11022 }
11023
11024 private final void broadcastTimeout() {
11025 synchronized (this) {
11026 if (mOrderedBroadcasts.size() == 0) {
11027 return;
11028 }
11029 long now = SystemClock.uptimeMillis();
11030 BroadcastRecord r = mOrderedBroadcasts.get(0);
11031 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11032 if (DEBUG_BROADCAST) Log.v(TAG,
11033 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11034 + (r.startTime + BROADCAST_TIMEOUT));
11035 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11036 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11037 return;
11038 }
11039
11040 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11041 r.startTime = now;
11042 r.anrCount++;
11043
11044 // Current receiver has passed its expiration date.
11045 if (r.nextReceiver <= 0) {
11046 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11047 return;
11048 }
11049
11050 ProcessRecord app = null;
11051
11052 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11053 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11054 logBroadcastReceiverDiscard(r);
11055 if (curReceiver instanceof BroadcastFilter) {
11056 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11057 if (bf.receiverList.pid != 0
11058 && bf.receiverList.pid != MY_PID) {
11059 synchronized (this.mPidsSelfLocked) {
11060 app = this.mPidsSelfLocked.get(
11061 bf.receiverList.pid);
11062 }
11063 }
11064 } else {
11065 app = r.curApp;
11066 }
11067
11068 if (app != null) {
11069 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11070 }
11071
11072 if (mPendingBroadcast == r) {
11073 mPendingBroadcast = null;
11074 }
11075
11076 // Move on to the next receiver.
11077 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11078 r.resultExtras, r.resultAbort, true);
11079 scheduleBroadcastsLocked();
11080 }
11081 }
11082
11083 private final void processCurBroadcastLocked(BroadcastRecord r,
11084 ProcessRecord app) throws RemoteException {
11085 if (app.thread == null) {
11086 throw new RemoteException();
11087 }
11088 r.receiver = app.thread.asBinder();
11089 r.curApp = app;
11090 app.curReceiver = r;
11091 updateLRUListLocked(app, true);
11092
11093 // Tell the application to launch this receiver.
11094 r.intent.setComponent(r.curComponent);
11095
11096 boolean started = false;
11097 try {
11098 if (DEBUG_BROADCAST) Log.v(TAG,
11099 "Delivering to component " + r.curComponent
11100 + ": " + r);
11101 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11102 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11103 started = true;
11104 } finally {
11105 if (!started) {
11106 r.receiver = null;
11107 r.curApp = null;
11108 app.curReceiver = null;
11109 }
11110 }
11111
11112 }
11113
11114 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11115 Intent intent, int resultCode, String data,
11116 Bundle extras, boolean ordered) throws RemoteException {
11117 if (app != null && app.thread != null) {
11118 // If we have an app thread, do the call through that so it is
11119 // correctly ordered with other one-way calls.
11120 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11121 data, extras, ordered);
11122 } else {
11123 receiver.performReceive(intent, resultCode, data, extras, ordered);
11124 }
11125 }
11126
11127 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11128 BroadcastFilter filter, boolean ordered) {
11129 boolean skip = false;
11130 if (filter.requiredPermission != null) {
11131 int perm = checkComponentPermission(filter.requiredPermission,
11132 r.callingPid, r.callingUid, -1);
11133 if (perm != PackageManager.PERMISSION_GRANTED) {
11134 Log.w(TAG, "Permission Denial: broadcasting "
11135 + r.intent.toString()
11136 + " from " + r.callerPackage + " (pid="
11137 + r.callingPid + ", uid=" + r.callingUid + ")"
11138 + " requires " + filter.requiredPermission
11139 + " due to registered receiver " + filter);
11140 skip = true;
11141 }
11142 }
11143 if (r.requiredPermission != null) {
11144 int perm = checkComponentPermission(r.requiredPermission,
11145 filter.receiverList.pid, filter.receiverList.uid, -1);
11146 if (perm != PackageManager.PERMISSION_GRANTED) {
11147 Log.w(TAG, "Permission Denial: receiving "
11148 + r.intent.toString()
11149 + " to " + filter.receiverList.app
11150 + " (pid=" + filter.receiverList.pid
11151 + ", uid=" + filter.receiverList.uid + ")"
11152 + " requires " + r.requiredPermission
11153 + " due to sender " + r.callerPackage
11154 + " (uid " + r.callingUid + ")");
11155 skip = true;
11156 }
11157 }
11158
11159 if (!skip) {
11160 // If this is not being sent as an ordered broadcast, then we
11161 // don't want to touch the fields that keep track of the current
11162 // state of ordered broadcasts.
11163 if (ordered) {
11164 r.receiver = filter.receiverList.receiver.asBinder();
11165 r.curFilter = filter;
11166 filter.receiverList.curBroadcast = r;
11167 r.state = BroadcastRecord.CALL_IN_RECEIVE;
11168 }
11169 try {
11170 if (DEBUG_BROADCAST) {
11171 int seq = r.intent.getIntExtra("seq", -1);
11172 Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
11173 + " app=" + filter.receiverList.app);
11174 }
11175 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11176 new Intent(r.intent), r.resultCode,
11177 r.resultData, r.resultExtras, r.ordered);
11178 if (ordered) {
11179 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11180 }
11181 } catch (RemoteException e) {
11182 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11183 if (ordered) {
11184 r.receiver = null;
11185 r.curFilter = null;
11186 filter.receiverList.curBroadcast = null;
11187 }
11188 }
11189 }
11190 }
11191
11192 private final void processNextBroadcast(boolean fromMsg) {
11193 synchronized(this) {
11194 BroadcastRecord r;
11195
11196 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11197 + mParallelBroadcasts.size() + " broadcasts, "
11198 + mOrderedBroadcasts.size() + " serialized broadcasts");
11199
11200 updateCpuStats();
11201
11202 if (fromMsg) {
11203 mBroadcastsScheduled = false;
11204 }
11205
11206 // First, deliver any non-serialized broadcasts right away.
11207 while (mParallelBroadcasts.size() > 0) {
11208 r = mParallelBroadcasts.remove(0);
11209 final int N = r.receivers.size();
11210 for (int i=0; i<N; i++) {
11211 Object target = r.receivers.get(i);
11212 if (DEBUG_BROADCAST) Log.v(TAG,
11213 "Delivering non-serialized to registered "
11214 + target + ": " + r);
11215 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11216 }
11217 }
11218
11219 // Now take care of the next serialized one...
11220
11221 // If we are waiting for a process to come up to handle the next
11222 // broadcast, then do nothing at this point. Just in case, we
11223 // check that the process we're waiting for still exists.
11224 if (mPendingBroadcast != null) {
11225 Log.i(TAG, "processNextBroadcast: waiting for "
11226 + mPendingBroadcast.curApp);
11227
11228 boolean isDead;
11229 synchronized (mPidsSelfLocked) {
11230 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11231 }
11232 if (!isDead) {
11233 // It's still alive, so keep waiting
11234 return;
11235 } else {
11236 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11237 + " died before responding to broadcast");
11238 mPendingBroadcast = null;
11239 }
11240 }
11241
11242 do {
11243 if (mOrderedBroadcasts.size() == 0) {
11244 // No more broadcasts pending, so all done!
11245 scheduleAppGcsLocked();
11246 return;
11247 }
11248 r = mOrderedBroadcasts.get(0);
11249 boolean forceReceive = false;
11250
11251 // Ensure that even if something goes awry with the timeout
11252 // detection, we catch "hung" broadcasts here, discard them,
11253 // and continue to make progress.
11254 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11255 long now = SystemClock.uptimeMillis();
11256 if (r.dispatchTime > 0) {
11257 if ((numReceivers > 0) &&
11258 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11259 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11260 + " now=" + now
11261 + " dispatchTime=" + r.dispatchTime
11262 + " startTime=" + r.startTime
11263 + " intent=" + r.intent
11264 + " numReceivers=" + numReceivers
11265 + " nextReceiver=" + r.nextReceiver
11266 + " state=" + r.state);
11267 broadcastTimeout(); // forcibly finish this broadcast
11268 forceReceive = true;
11269 r.state = BroadcastRecord.IDLE;
11270 }
11271 }
11272
11273 if (r.state != BroadcastRecord.IDLE) {
11274 if (DEBUG_BROADCAST) Log.d(TAG,
11275 "processNextBroadcast() called when not idle (state="
11276 + r.state + ")");
11277 return;
11278 }
11279
11280 if (r.receivers == null || r.nextReceiver >= numReceivers
11281 || r.resultAbort || forceReceive) {
11282 // No more receivers for this broadcast! Send the final
11283 // result if requested...
11284 if (r.resultTo != null) {
11285 try {
11286 if (DEBUG_BROADCAST) {
11287 int seq = r.intent.getIntExtra("seq", -1);
11288 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11289 + " seq=" + seq + " app=" + r.callerApp);
11290 }
11291 performReceive(r.callerApp, r.resultTo,
11292 new Intent(r.intent), r.resultCode,
11293 r.resultData, r.resultExtras, false);
11294 } catch (RemoteException e) {
11295 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11296 }
11297 }
11298
11299 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11300 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11301
11302 // ... and on to the next...
11303 mOrderedBroadcasts.remove(0);
11304 r = null;
11305 continue;
11306 }
11307 } while (r == null);
11308
11309 // Get the next receiver...
11310 int recIdx = r.nextReceiver++;
11311
11312 // Keep track of when this receiver started, and make sure there
11313 // is a timeout message pending to kill it if need be.
11314 r.startTime = SystemClock.uptimeMillis();
11315 if (recIdx == 0) {
11316 r.dispatchTime = r.startTime;
11317
11318 if (DEBUG_BROADCAST) Log.v(TAG,
11319 "Submitting BROADCAST_TIMEOUT_MSG for "
11320 + (r.startTime + BROADCAST_TIMEOUT));
11321 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11322 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11323 }
11324
11325 Object nextReceiver = r.receivers.get(recIdx);
11326 if (nextReceiver instanceof BroadcastFilter) {
11327 // Simple case: this is a registered receiver who gets
11328 // a direct call.
11329 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11330 if (DEBUG_BROADCAST) Log.v(TAG,
11331 "Delivering serialized to registered "
11332 + filter + ": " + r);
11333 deliverToRegisteredReceiver(r, filter, r.ordered);
11334 if (r.receiver == null || !r.ordered) {
11335 // The receiver has already finished, so schedule to
11336 // process the next one.
11337 r.state = BroadcastRecord.IDLE;
11338 scheduleBroadcastsLocked();
11339 }
11340 return;
11341 }
11342
11343 // Hard case: need to instantiate the receiver, possibly
11344 // starting its application process to host it.
11345
11346 ResolveInfo info =
11347 (ResolveInfo)nextReceiver;
11348
11349 boolean skip = false;
11350 int perm = checkComponentPermission(info.activityInfo.permission,
11351 r.callingPid, r.callingUid,
11352 info.activityInfo.exported
11353 ? -1 : info.activityInfo.applicationInfo.uid);
11354 if (perm != PackageManager.PERMISSION_GRANTED) {
11355 Log.w(TAG, "Permission Denial: broadcasting "
11356 + r.intent.toString()
11357 + " from " + r.callerPackage + " (pid=" + r.callingPid
11358 + ", uid=" + r.callingUid + ")"
11359 + " requires " + info.activityInfo.permission
11360 + " due to receiver " + info.activityInfo.packageName
11361 + "/" + info.activityInfo.name);
11362 skip = true;
11363 }
11364 if (r.callingUid != Process.SYSTEM_UID &&
11365 r.requiredPermission != null) {
11366 try {
11367 perm = ActivityThread.getPackageManager().
11368 checkPermission(r.requiredPermission,
11369 info.activityInfo.applicationInfo.packageName);
11370 } catch (RemoteException e) {
11371 perm = PackageManager.PERMISSION_DENIED;
11372 }
11373 if (perm != PackageManager.PERMISSION_GRANTED) {
11374 Log.w(TAG, "Permission Denial: receiving "
11375 + r.intent + " to "
11376 + info.activityInfo.applicationInfo.packageName
11377 + " requires " + r.requiredPermission
11378 + " due to sender " + r.callerPackage
11379 + " (uid " + r.callingUid + ")");
11380 skip = true;
11381 }
11382 }
11383 if (r.curApp != null && r.curApp.crashing) {
11384 // If the target process is crashing, just skip it.
11385 skip = true;
11386 }
11387
11388 if (skip) {
11389 r.receiver = null;
11390 r.curFilter = null;
11391 r.state = BroadcastRecord.IDLE;
11392 scheduleBroadcastsLocked();
11393 return;
11394 }
11395
11396 r.state = BroadcastRecord.APP_RECEIVE;
11397 String targetProcess = info.activityInfo.processName;
11398 r.curComponent = new ComponentName(
11399 info.activityInfo.applicationInfo.packageName,
11400 info.activityInfo.name);
11401 r.curReceiver = info.activityInfo;
11402
11403 // Is this receiver's application already running?
11404 ProcessRecord app = getProcessRecordLocked(targetProcess,
11405 info.activityInfo.applicationInfo.uid);
11406 if (app != null && app.thread != null) {
11407 try {
11408 processCurBroadcastLocked(r, app);
11409 return;
11410 } catch (RemoteException e) {
11411 Log.w(TAG, "Exception when sending broadcast to "
11412 + r.curComponent, e);
11413 }
11414
11415 // If a dead object exception was thrown -- fall through to
11416 // restart the application.
11417 }
11418
11419 // Not running -- get it started, and enqueue this history record
11420 // to be executed when the app comes up.
11421 if ((r.curApp=startProcessLocked(targetProcess,
11422 info.activityInfo.applicationInfo, true,
11423 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11424 "broadcast", r.curComponent)) == null) {
11425 // Ah, this recipient is unavailable. Finish it if necessary,
11426 // and mark the broadcast record as ready for the next.
11427 Log.w(TAG, "Unable to launch app "
11428 + info.activityInfo.applicationInfo.packageName + "/"
11429 + info.activityInfo.applicationInfo.uid + " for broadcast "
11430 + r.intent + ": process is bad");
11431 logBroadcastReceiverDiscard(r);
11432 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11433 r.resultExtras, r.resultAbort, true);
11434 scheduleBroadcastsLocked();
11435 r.state = BroadcastRecord.IDLE;
11436 return;
11437 }
11438
11439 mPendingBroadcast = r;
11440 }
11441 }
11442
11443 // =========================================================
11444 // INSTRUMENTATION
11445 // =========================================================
11446
11447 public boolean startInstrumentation(ComponentName className,
11448 String profileFile, int flags, Bundle arguments,
11449 IInstrumentationWatcher watcher) {
11450 // Refuse possible leaked file descriptors
11451 if (arguments != null && arguments.hasFileDescriptors()) {
11452 throw new IllegalArgumentException("File descriptors passed in Bundle");
11453 }
11454
11455 synchronized(this) {
11456 InstrumentationInfo ii = null;
11457 ApplicationInfo ai = null;
11458 try {
11459 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011460 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011461 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011462 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011463 } catch (PackageManager.NameNotFoundException e) {
11464 }
11465 if (ii == null) {
11466 reportStartInstrumentationFailure(watcher, className,
11467 "Unable to find instrumentation info for: " + className);
11468 return false;
11469 }
11470 if (ai == null) {
11471 reportStartInstrumentationFailure(watcher, className,
11472 "Unable to find instrumentation target package: " + ii.targetPackage);
11473 return false;
11474 }
11475
11476 int match = mContext.getPackageManager().checkSignatures(
11477 ii.targetPackage, ii.packageName);
11478 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11479 String msg = "Permission Denial: starting instrumentation "
11480 + className + " from pid="
11481 + Binder.getCallingPid()
11482 + ", uid=" + Binder.getCallingPid()
11483 + " not allowed because package " + ii.packageName
11484 + " does not have a signature matching the target "
11485 + ii.targetPackage;
11486 reportStartInstrumentationFailure(watcher, className, msg);
11487 throw new SecurityException(msg);
11488 }
11489
11490 final long origId = Binder.clearCallingIdentity();
11491 uninstallPackageLocked(ii.targetPackage, -1, true);
11492 ProcessRecord app = addAppLocked(ai);
11493 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011494 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011495 app.instrumentationProfileFile = profileFile;
11496 app.instrumentationArguments = arguments;
11497 app.instrumentationWatcher = watcher;
11498 app.instrumentationResultClass = className;
11499 Binder.restoreCallingIdentity(origId);
11500 }
11501
11502 return true;
11503 }
11504
11505 /**
11506 * Report errors that occur while attempting to start Instrumentation. Always writes the
11507 * error to the logs, but if somebody is watching, send the report there too. This enables
11508 * the "am" command to report errors with more information.
11509 *
11510 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11511 * @param cn The component name of the instrumentation.
11512 * @param report The error report.
11513 */
11514 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11515 ComponentName cn, String report) {
11516 Log.w(TAG, report);
11517 try {
11518 if (watcher != null) {
11519 Bundle results = new Bundle();
11520 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11521 results.putString("Error", report);
11522 watcher.instrumentationStatus(cn, -1, results);
11523 }
11524 } catch (RemoteException e) {
11525 Log.w(TAG, e);
11526 }
11527 }
11528
11529 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11530 if (app.instrumentationWatcher != null) {
11531 try {
11532 // NOTE: IInstrumentationWatcher *must* be oneway here
11533 app.instrumentationWatcher.instrumentationFinished(
11534 app.instrumentationClass,
11535 resultCode,
11536 results);
11537 } catch (RemoteException e) {
11538 }
11539 }
11540 app.instrumentationWatcher = null;
11541 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011542 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011543 app.instrumentationProfileFile = null;
11544 app.instrumentationArguments = null;
11545
11546 uninstallPackageLocked(app.processName, -1, false);
11547 }
11548
11549 public void finishInstrumentation(IApplicationThread target,
11550 int resultCode, Bundle results) {
11551 // Refuse possible leaked file descriptors
11552 if (results != null && results.hasFileDescriptors()) {
11553 throw new IllegalArgumentException("File descriptors passed in Intent");
11554 }
11555
11556 synchronized(this) {
11557 ProcessRecord app = getRecordForAppLocked(target);
11558 if (app == null) {
11559 Log.w(TAG, "finishInstrumentation: no app for " + target);
11560 return;
11561 }
11562 final long origId = Binder.clearCallingIdentity();
11563 finishInstrumentationLocked(app, resultCode, results);
11564 Binder.restoreCallingIdentity(origId);
11565 }
11566 }
11567
11568 // =========================================================
11569 // CONFIGURATION
11570 // =========================================================
11571
11572 public ConfigurationInfo getDeviceConfigurationInfo() {
11573 ConfigurationInfo config = new ConfigurationInfo();
11574 synchronized (this) {
11575 config.reqTouchScreen = mConfiguration.touchscreen;
11576 config.reqKeyboardType = mConfiguration.keyboard;
11577 config.reqNavigation = mConfiguration.navigation;
11578 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11579 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11580 }
11581 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11582 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11583 }
11584 }
11585 return config;
11586 }
11587
11588 public Configuration getConfiguration() {
11589 Configuration ci;
11590 synchronized(this) {
11591 ci = new Configuration(mConfiguration);
11592 }
11593 return ci;
11594 }
11595
11596 public void updateConfiguration(Configuration values) {
11597 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11598 "updateConfiguration()");
11599
11600 synchronized(this) {
11601 if (values == null && mWindowManager != null) {
11602 // sentinel: fetch the current configuration from the window manager
11603 values = mWindowManager.computeNewConfiguration();
11604 }
11605
11606 final long origId = Binder.clearCallingIdentity();
11607 updateConfigurationLocked(values, null);
11608 Binder.restoreCallingIdentity(origId);
11609 }
11610 }
11611
11612 /**
11613 * Do either or both things: (1) change the current configuration, and (2)
11614 * make sure the given activity is running with the (now) current
11615 * configuration. Returns true if the activity has been left running, or
11616 * false if <var>starting</var> is being destroyed to match the new
11617 * configuration.
11618 */
11619 public boolean updateConfigurationLocked(Configuration values,
11620 HistoryRecord starting) {
11621 int changes = 0;
11622
11623 boolean kept = true;
11624
11625 if (values != null) {
11626 Configuration newConfig = new Configuration(mConfiguration);
11627 changes = newConfig.updateFrom(values);
11628 if (changes != 0) {
11629 if (DEBUG_SWITCH) {
11630 Log.i(TAG, "Updating configuration to: " + values);
11631 }
11632
11633 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11634
11635 if (values.locale != null) {
11636 saveLocaleLocked(values.locale,
11637 !values.locale.equals(mConfiguration.locale),
11638 values.userSetLocale);
11639 }
11640
11641 mConfiguration = newConfig;
11642
11643 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11644 msg.obj = new Configuration(mConfiguration);
11645 mHandler.sendMessage(msg);
11646
11647 final int N = mLRUProcesses.size();
11648 for (int i=0; i<N; i++) {
11649 ProcessRecord app = mLRUProcesses.get(i);
11650 try {
11651 if (app.thread != null) {
11652 app.thread.scheduleConfigurationChanged(mConfiguration);
11653 }
11654 } catch (Exception e) {
11655 }
11656 }
11657 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11658 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11659 null, false, false, MY_PID, Process.SYSTEM_UID);
11660 }
11661 }
11662
11663 if (changes != 0 && starting == null) {
11664 // If the configuration changed, and the caller is not already
11665 // in the process of starting an activity, then find the top
11666 // activity to check if its configuration needs to change.
11667 starting = topRunningActivityLocked(null);
11668 }
11669
11670 if (starting != null) {
11671 kept = ensureActivityConfigurationLocked(starting, changes);
11672 if (kept) {
11673 // If this didn't result in the starting activity being
11674 // destroyed, then we need to make sure at this point that all
11675 // other activities are made visible.
11676 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11677 + ", ensuring others are correct.");
11678 ensureActivitiesVisibleLocked(starting, changes);
11679 }
11680 }
11681
11682 return kept;
11683 }
11684
11685 private final boolean relaunchActivityLocked(HistoryRecord r,
11686 int changes, boolean andResume) {
11687 List<ResultInfo> results = null;
11688 List<Intent> newIntents = null;
11689 if (andResume) {
11690 results = r.results;
11691 newIntents = r.newIntents;
11692 }
11693 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11694 + " with results=" + results + " newIntents=" + newIntents
11695 + " andResume=" + andResume);
11696 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11697 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11698 r.task.taskId, r.shortComponentName);
11699
11700 r.startFreezingScreenLocked(r.app, 0);
11701
11702 try {
11703 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11704 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11705 changes, !andResume);
11706 // Note: don't need to call pauseIfSleepingLocked() here, because
11707 // the caller will only pass in 'andResume' if this activity is
11708 // currently resumed, which implies we aren't sleeping.
11709 } catch (RemoteException e) {
11710 return false;
11711 }
11712
11713 if (andResume) {
11714 r.results = null;
11715 r.newIntents = null;
11716 }
11717
11718 return true;
11719 }
11720
11721 /**
11722 * Make sure the given activity matches the current configuration. Returns
11723 * false if the activity had to be destroyed. Returns true if the
11724 * configuration is the same, or the activity will remain running as-is
11725 * for whatever reason. Ensures the HistoryRecord is updated with the
11726 * correct configuration and all other bookkeeping is handled.
11727 */
11728 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11729 int globalChanges) {
11730 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11731
11732 // Short circuit: if the two configurations are the exact same
11733 // object (the common case), then there is nothing to do.
11734 Configuration newConfig = mConfiguration;
11735 if (r.configuration == newConfig) {
11736 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11737 return true;
11738 }
11739
11740 // We don't worry about activities that are finishing.
11741 if (r.finishing) {
11742 if (DEBUG_SWITCH) Log.i(TAG,
11743 "Configuration doesn't matter in finishing " + r);
11744 r.stopFreezingScreenLocked(false);
11745 return true;
11746 }
11747
11748 // Okay we now are going to make this activity have the new config.
11749 // But then we need to figure out how it needs to deal with that.
11750 Configuration oldConfig = r.configuration;
11751 r.configuration = newConfig;
11752
11753 // If the activity isn't currently running, just leave the new
11754 // configuration and it will pick that up next time it starts.
11755 if (r.app == null || r.app.thread == null) {
11756 if (DEBUG_SWITCH) Log.i(TAG,
11757 "Configuration doesn't matter not running " + r);
11758 r.stopFreezingScreenLocked(false);
11759 return true;
11760 }
11761
11762 // If the activity isn't persistent, there is a chance we will
11763 // need to restart it.
11764 if (!r.persistent) {
11765
11766 // Figure out what has changed between the two configurations.
11767 int changes = oldConfig.diff(newConfig);
11768 if (DEBUG_SWITCH) {
11769 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11770 + Integer.toHexString(changes) + ", handles=0x"
11771 + Integer.toHexString(r.info.configChanges));
11772 }
11773 if ((changes&(~r.info.configChanges)) != 0) {
11774 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11775 r.configChangeFlags |= changes;
11776 r.startFreezingScreenLocked(r.app, globalChanges);
11777 if (r.app == null || r.app.thread == null) {
11778 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11779 destroyActivityLocked(r, true);
11780 } else if (r.state == ActivityState.PAUSING) {
11781 // A little annoying: we are waiting for this activity to
11782 // finish pausing. Let's not do anything now, but just
11783 // flag that it needs to be restarted when done pausing.
11784 r.configDestroy = true;
11785 return true;
11786 } else if (r.state == ActivityState.RESUMED) {
11787 // Try to optimize this case: the configuration is changing
11788 // and we need to restart the top, resumed activity.
11789 // Instead of doing the normal handshaking, just say
11790 // "restart!".
11791 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11792 relaunchActivityLocked(r, r.configChangeFlags, true);
11793 r.configChangeFlags = 0;
11794 } else {
11795 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11796 relaunchActivityLocked(r, r.configChangeFlags, false);
11797 r.configChangeFlags = 0;
11798 }
11799
11800 // All done... tell the caller we weren't able to keep this
11801 // activity around.
11802 return false;
11803 }
11804 }
11805
11806 // Default case: the activity can handle this new configuration, so
11807 // hand it over. Note that we don't need to give it the new
11808 // configuration, since we always send configuration changes to all
11809 // process when they happen so it can just use whatever configuration
11810 // it last got.
11811 if (r.app != null && r.app.thread != null) {
11812 try {
11813 r.app.thread.scheduleActivityConfigurationChanged(r);
11814 } catch (RemoteException e) {
11815 // If process died, whatever.
11816 }
11817 }
11818 r.stopFreezingScreenLocked(false);
11819
11820 return true;
11821 }
11822
11823 /**
11824 * Save the locale. You must be inside a synchronized (this) block.
11825 */
11826 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11827 if(isDiff) {
11828 SystemProperties.set("user.language", l.getLanguage());
11829 SystemProperties.set("user.region", l.getCountry());
11830 }
11831
11832 if(isPersist) {
11833 SystemProperties.set("persist.sys.language", l.getLanguage());
11834 SystemProperties.set("persist.sys.country", l.getCountry());
11835 SystemProperties.set("persist.sys.localevar", l.getVariant());
11836 }
11837 }
11838
11839 // =========================================================
11840 // LIFETIME MANAGEMENT
11841 // =========================================================
11842
11843 private final int computeOomAdjLocked(
11844 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11845 if (mAdjSeq == app.adjSeq) {
11846 // This adjustment has already been computed.
11847 return app.curAdj;
11848 }
11849
11850 if (app.thread == null) {
11851 app.adjSeq = mAdjSeq;
11852 return (app.curAdj=EMPTY_APP_ADJ);
11853 }
11854
11855 app.isForeground = false;
11856
The Android Open Source Project4df24232009-03-05 14:34:35 -080011857 // Determine the importance of the process, starting with most
11858 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011859 int adj;
11860 int N;
11861 if (app == TOP_APP || app.instrumentationClass != null
11862 || app.persistentActivities > 0) {
11863 // The last app on the list is the foreground app.
11864 adj = FOREGROUND_APP_ADJ;
11865 app.isForeground = true;
11866 } else if (app.curReceiver != null ||
11867 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11868 // An app that is currently receiving a broadcast also
11869 // counts as being in the foreground.
11870 adj = FOREGROUND_APP_ADJ;
11871 } else if (app.executingServices.size() > 0) {
11872 // An app that is currently executing a service callback also
11873 // counts as being in the foreground.
11874 adj = FOREGROUND_APP_ADJ;
11875 } else if (app.foregroundServices || app.forcingToForeground != null) {
11876 // The user is aware of this app, so make it visible.
11877 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011878 } else if (app == mHomeProcess) {
11879 // This process is hosting what we currently consider to be the
11880 // home app, so we don't want to let it go into the background.
11881 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011882 } else if ((N=app.activities.size()) != 0) {
11883 // This app is in the background with paused activities.
11884 adj = hiddenAdj;
11885 for (int j=0; j<N; j++) {
11886 if (((HistoryRecord)app.activities.get(j)).visible) {
11887 // This app has a visible activity!
11888 adj = VISIBLE_APP_ADJ;
11889 break;
11890 }
11891 }
11892 } else {
11893 // A very not-needed process.
11894 adj = EMPTY_APP_ADJ;
11895 }
11896
The Android Open Source Project4df24232009-03-05 14:34:35 -080011897 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011898 // there are applications dependent on our services or providers, but
11899 // this gives us a baseline and makes sure we don't get into an
11900 // infinite recursion.
11901 app.adjSeq = mAdjSeq;
11902 app.curRawAdj = adj;
11903 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11904
Christopher Tate6fa95972009-06-05 18:43:55 -070011905 if (mBackupTarget != null && app == mBackupTarget.app) {
11906 // If possible we want to avoid killing apps while they're being backed up
11907 if (adj > BACKUP_APP_ADJ) {
11908 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
11909 adj = BACKUP_APP_ADJ;
11910 }
11911 }
11912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011913 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11914 // If this process has active services running in it, we would
11915 // like to avoid killing it unless it would prevent the current
11916 // application from running.
11917 if (adj > hiddenAdj) {
11918 adj = hiddenAdj;
11919 }
11920 final long now = SystemClock.uptimeMillis();
11921 // This process is more important if the top activity is
11922 // bound to the service.
11923 Iterator jt = app.services.iterator();
11924 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11925 ServiceRecord s = (ServiceRecord)jt.next();
11926 if (s.startRequested) {
11927 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
11928 // This service has seen some activity within
11929 // recent memory, so we will keep its process ahead
11930 // of the background processes.
11931 if (adj > SECONDARY_SERVER_ADJ) {
11932 adj = SECONDARY_SERVER_ADJ;
11933 }
11934 } else {
11935 // This service has been inactive for too long, just
11936 // put it with the rest of the background processes.
11937 if (adj > hiddenAdj) {
11938 adj = hiddenAdj;
11939 }
11940 }
11941 }
11942 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
11943 Iterator<ConnectionRecord> kt
11944 = s.connections.values().iterator();
11945 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11946 // XXX should compute this based on the max of
11947 // all connected clients.
11948 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011949 if (cr.binding.client == app) {
11950 // Binding to ourself is not interesting.
11951 continue;
11952 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011953 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
11954 ProcessRecord client = cr.binding.client;
11955 int myHiddenAdj = hiddenAdj;
11956 if (myHiddenAdj > client.hiddenAdj) {
11957 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
11958 myHiddenAdj = client.hiddenAdj;
11959 } else {
11960 myHiddenAdj = VISIBLE_APP_ADJ;
11961 }
11962 }
11963 int clientAdj = computeOomAdjLocked(
11964 client, myHiddenAdj, TOP_APP);
11965 if (adj > clientAdj) {
11966 adj = clientAdj > VISIBLE_APP_ADJ
11967 ? clientAdj : VISIBLE_APP_ADJ;
11968 }
11969 }
11970 HistoryRecord a = cr.activity;
11971 //if (a != null) {
11972 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
11973 //}
11974 if (a != null && adj > FOREGROUND_APP_ADJ &&
11975 (a.state == ActivityState.RESUMED
11976 || a.state == ActivityState.PAUSING)) {
11977 adj = FOREGROUND_APP_ADJ;
11978 }
11979 }
11980 }
11981 }
11982 }
11983
11984 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11985 // If this process has published any content providers, then
11986 // its adjustment makes it at least as important as any of the
11987 // processes using those providers, and no less important than
11988 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
11989 if (adj > CONTENT_PROVIDER_ADJ) {
11990 adj = CONTENT_PROVIDER_ADJ;
11991 }
11992 Iterator jt = app.pubProviders.values().iterator();
11993 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11994 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
11995 if (cpr.clients.size() != 0) {
11996 Iterator<ProcessRecord> kt = cpr.clients.iterator();
11997 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11998 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011999 if (client == app) {
12000 // Being our own client is not interesting.
12001 continue;
12002 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012003 int myHiddenAdj = hiddenAdj;
12004 if (myHiddenAdj > client.hiddenAdj) {
12005 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12006 myHiddenAdj = client.hiddenAdj;
12007 } else {
12008 myHiddenAdj = FOREGROUND_APP_ADJ;
12009 }
12010 }
12011 int clientAdj = computeOomAdjLocked(
12012 client, myHiddenAdj, TOP_APP);
12013 if (adj > clientAdj) {
12014 adj = clientAdj > FOREGROUND_APP_ADJ
12015 ? clientAdj : FOREGROUND_APP_ADJ;
12016 }
12017 }
12018 }
12019 // If the provider has external (non-framework) process
12020 // dependencies, ensure that its adjustment is at least
12021 // FOREGROUND_APP_ADJ.
12022 if (cpr.externals != 0) {
12023 if (adj > FOREGROUND_APP_ADJ) {
12024 adj = FOREGROUND_APP_ADJ;
12025 }
12026 }
12027 }
12028 }
12029
12030 app.curRawAdj = adj;
12031
12032 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12033 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12034 if (adj > app.maxAdj) {
12035 adj = app.maxAdj;
12036 }
12037
12038 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012039 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12040 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12041 : Process.THREAD_GROUP_DEFAULT;
12042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012043 return adj;
12044 }
12045
12046 /**
12047 * Ask a given process to GC right now.
12048 */
12049 final void performAppGcLocked(ProcessRecord app) {
12050 try {
12051 app.lastRequestedGc = SystemClock.uptimeMillis();
12052 if (app.thread != null) {
12053 app.thread.processInBackground();
12054 }
12055 } catch (Exception e) {
12056 // whatever.
12057 }
12058 }
12059
12060 /**
12061 * Returns true if things are idle enough to perform GCs.
12062 */
12063 private final boolean canGcNow() {
12064 return mParallelBroadcasts.size() == 0
12065 && mOrderedBroadcasts.size() == 0
12066 && (mSleeping || (mResumedActivity != null &&
12067 mResumedActivity.idle));
12068 }
12069
12070 /**
12071 * Perform GCs on all processes that are waiting for it, but only
12072 * if things are idle.
12073 */
12074 final void performAppGcsLocked() {
12075 final int N = mProcessesToGc.size();
12076 if (N <= 0) {
12077 return;
12078 }
12079 if (canGcNow()) {
12080 while (mProcessesToGc.size() > 0) {
12081 ProcessRecord proc = mProcessesToGc.remove(0);
12082 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12083 // To avoid spamming the system, we will GC processes one
12084 // at a time, waiting a few seconds between each.
12085 performAppGcLocked(proc);
12086 scheduleAppGcsLocked();
12087 return;
12088 }
12089 }
12090 }
12091 }
12092
12093 /**
12094 * If all looks good, perform GCs on all processes waiting for them.
12095 */
12096 final void performAppGcsIfAppropriateLocked() {
12097 if (canGcNow()) {
12098 performAppGcsLocked();
12099 return;
12100 }
12101 // Still not idle, wait some more.
12102 scheduleAppGcsLocked();
12103 }
12104
12105 /**
12106 * Schedule the execution of all pending app GCs.
12107 */
12108 final void scheduleAppGcsLocked() {
12109 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12110 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12111 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12112 }
12113
12114 /**
12115 * Set up to ask a process to GC itself. This will either do it
12116 * immediately, or put it on the list of processes to gc the next
12117 * time things are idle.
12118 */
12119 final void scheduleAppGcLocked(ProcessRecord app) {
12120 long now = SystemClock.uptimeMillis();
12121 if ((app.lastRequestedGc+5000) > now) {
12122 return;
12123 }
12124 if (!mProcessesToGc.contains(app)) {
12125 mProcessesToGc.add(app);
12126 scheduleAppGcsLocked();
12127 }
12128 }
12129
12130 private final boolean updateOomAdjLocked(
12131 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12132 app.hiddenAdj = hiddenAdj;
12133
12134 if (app.thread == null) {
12135 return true;
12136 }
12137
12138 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12139
12140 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12141 //Thread priority adjustment is disabled out to see
12142 //how the kernel scheduler performs.
12143 if (false) {
12144 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12145 app.setIsForeground = app.isForeground;
12146 if (app.pid != MY_PID) {
12147 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12148 + " to " + (app.isForeground
12149 ? Process.THREAD_PRIORITY_FOREGROUND
12150 : Process.THREAD_PRIORITY_DEFAULT));
12151 try {
12152 Process.setThreadPriority(app.pid, app.isForeground
12153 ? Process.THREAD_PRIORITY_FOREGROUND
12154 : Process.THREAD_PRIORITY_DEFAULT);
12155 } catch (RuntimeException e) {
12156 Log.w(TAG, "Exception trying to set priority of application thread "
12157 + app.pid, e);
12158 }
12159 }
12160 }
12161 }
12162 if (app.pid != 0 && app.pid != MY_PID) {
12163 if (app.curRawAdj != app.setRawAdj) {
12164 if (app.curRawAdj > FOREGROUND_APP_ADJ
12165 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12166 // If this app is transitioning from foreground to
12167 // non-foreground, have it do a gc.
12168 scheduleAppGcLocked(app);
12169 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12170 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12171 // Likewise do a gc when an app is moving in to the
12172 // background (such as a service stopping).
12173 scheduleAppGcLocked(app);
12174 }
12175 app.setRawAdj = app.curRawAdj;
12176 }
12177 if (adj != app.setAdj) {
12178 if (Process.setOomAdj(app.pid, adj)) {
12179 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12180 TAG, "Set app " + app.processName +
12181 " oom adj to " + adj);
12182 app.setAdj = adj;
12183 } else {
12184 return false;
12185 }
12186 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012187 if (app.setSchedGroup != app.curSchedGroup) {
12188 app.setSchedGroup = app.curSchedGroup;
12189 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12190 "Setting process group of " + app.processName
12191 + " to " + app.curSchedGroup);
12192 if (true) {
12193 try {
12194 Process.setProcessGroup(app.pid, app.curSchedGroup);
12195 } catch (Exception e) {
12196 Log.w(TAG, "Failed setting process group of " + app.pid
12197 + " to " + app.curSchedGroup);
12198 }
12199 }
12200 if (false) {
12201 if (app.thread != null) {
12202 try {
12203 app.thread.setSchedulingGroup(app.curSchedGroup);
12204 } catch (RemoteException e) {
12205 }
12206 }
12207 }
12208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012209 }
12210
12211 return true;
12212 }
12213
12214 private final HistoryRecord resumedAppLocked() {
12215 HistoryRecord resumedActivity = mResumedActivity;
12216 if (resumedActivity == null || resumedActivity.app == null) {
12217 resumedActivity = mPausingActivity;
12218 if (resumedActivity == null || resumedActivity.app == null) {
12219 resumedActivity = topRunningActivityLocked(null);
12220 }
12221 }
12222 return resumedActivity;
12223 }
12224
12225 private final boolean updateOomAdjLocked(ProcessRecord app) {
12226 final HistoryRecord TOP_ACT = resumedAppLocked();
12227 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12228 int curAdj = app.curAdj;
12229 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12230 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12231
12232 mAdjSeq++;
12233
12234 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12235 if (res) {
12236 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12237 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12238 if (nowHidden != wasHidden) {
12239 // Changed to/from hidden state, so apps after it in the LRU
12240 // list may also be changed.
12241 updateOomAdjLocked();
12242 }
12243 }
12244 return res;
12245 }
12246
12247 private final boolean updateOomAdjLocked() {
12248 boolean didOomAdj = true;
12249 final HistoryRecord TOP_ACT = resumedAppLocked();
12250 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12251
12252 if (false) {
12253 RuntimeException e = new RuntimeException();
12254 e.fillInStackTrace();
12255 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12256 }
12257
12258 mAdjSeq++;
12259
12260 // First try updating the OOM adjustment for each of the
12261 // application processes based on their current state.
12262 int i = mLRUProcesses.size();
12263 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12264 while (i > 0) {
12265 i--;
12266 ProcessRecord app = mLRUProcesses.get(i);
12267 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12268 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12269 && app.curAdj == curHiddenAdj) {
12270 curHiddenAdj++;
12271 }
12272 } else {
12273 didOomAdj = false;
12274 }
12275 }
12276
12277 // todo: for now pretend like OOM ADJ didn't work, because things
12278 // aren't behaving as expected on Linux -- it's not killing processes.
12279 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12280 }
12281
12282 private final void trimApplications() {
12283 synchronized (this) {
12284 int i;
12285
12286 // First remove any unused application processes whose package
12287 // has been removed.
12288 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12289 final ProcessRecord app = mRemovedProcesses.get(i);
12290 if (app.activities.size() == 0
12291 && app.curReceiver == null && app.services.size() == 0) {
12292 Log.i(
12293 TAG, "Exiting empty application process "
12294 + app.processName + " ("
12295 + (app.thread != null ? app.thread.asBinder() : null)
12296 + ")\n");
12297 if (app.pid > 0 && app.pid != MY_PID) {
12298 Process.killProcess(app.pid);
12299 } else {
12300 try {
12301 app.thread.scheduleExit();
12302 } catch (Exception e) {
12303 // Ignore exceptions.
12304 }
12305 }
12306 cleanUpApplicationRecordLocked(app, false, -1);
12307 mRemovedProcesses.remove(i);
12308
12309 if (app.persistent) {
12310 if (app.persistent) {
12311 addAppLocked(app.info);
12312 }
12313 }
12314 }
12315 }
12316
12317 // Now try updating the OOM adjustment for each of the
12318 // application processes based on their current state.
12319 // If the setOomAdj() API is not supported, then go with our
12320 // back-up plan...
12321 if (!updateOomAdjLocked()) {
12322
12323 // Count how many processes are running services.
12324 int numServiceProcs = 0;
12325 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12326 final ProcessRecord app = mLRUProcesses.get(i);
12327
12328 if (app.persistent || app.services.size() != 0
12329 || app.curReceiver != null
12330 || app.persistentActivities > 0) {
12331 // Don't count processes holding services against our
12332 // maximum process count.
12333 if (localLOGV) Log.v(
12334 TAG, "Not trimming app " + app + " with services: "
12335 + app.services);
12336 numServiceProcs++;
12337 }
12338 }
12339
12340 int curMaxProcs = mProcessLimit;
12341 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12342 if (mAlwaysFinishActivities) {
12343 curMaxProcs = 1;
12344 }
12345 curMaxProcs += numServiceProcs;
12346
12347 // Quit as many processes as we can to get down to the desired
12348 // process count. First remove any processes that no longer
12349 // have activites running in them.
12350 for ( i=0;
12351 i<mLRUProcesses.size()
12352 && mLRUProcesses.size() > curMaxProcs;
12353 i++) {
12354 final ProcessRecord app = mLRUProcesses.get(i);
12355 // Quit an application only if it is not currently
12356 // running any activities.
12357 if (!app.persistent && app.activities.size() == 0
12358 && app.curReceiver == null && app.services.size() == 0) {
12359 Log.i(
12360 TAG, "Exiting empty application process "
12361 + app.processName + " ("
12362 + (app.thread != null ? app.thread.asBinder() : null)
12363 + ")\n");
12364 if (app.pid > 0 && app.pid != MY_PID) {
12365 Process.killProcess(app.pid);
12366 } else {
12367 try {
12368 app.thread.scheduleExit();
12369 } catch (Exception e) {
12370 // Ignore exceptions.
12371 }
12372 }
12373 // todo: For now we assume the application is not buggy
12374 // or evil, and will quit as a result of our request.
12375 // Eventually we need to drive this off of the death
12376 // notification, and kill the process if it takes too long.
12377 cleanUpApplicationRecordLocked(app, false, i);
12378 i--;
12379 }
12380 }
12381
12382 // If we still have too many processes, now from the least
12383 // recently used process we start finishing activities.
12384 if (Config.LOGV) Log.v(
12385 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12386 " of " + curMaxProcs + " processes");
12387 for ( i=0;
12388 i<mLRUProcesses.size()
12389 && mLRUProcesses.size() > curMaxProcs;
12390 i++) {
12391 final ProcessRecord app = mLRUProcesses.get(i);
12392 // Quit the application only if we have a state saved for
12393 // all of its activities.
12394 boolean canQuit = !app.persistent && app.curReceiver == null
12395 && app.services.size() == 0
12396 && app.persistentActivities == 0;
12397 int NUMA = app.activities.size();
12398 int j;
12399 if (Config.LOGV) Log.v(
12400 TAG, "Looking to quit " + app.processName);
12401 for (j=0; j<NUMA && canQuit; j++) {
12402 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12403 if (Config.LOGV) Log.v(
12404 TAG, " " + r.intent.getComponent().flattenToShortString()
12405 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12406 canQuit = (r.haveState || !r.stateNotNeeded)
12407 && !r.visible && r.stopped;
12408 }
12409 if (canQuit) {
12410 // Finish all of the activities, and then the app itself.
12411 for (j=0; j<NUMA; j++) {
12412 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12413 if (!r.finishing) {
12414 destroyActivityLocked(r, false);
12415 }
12416 r.resultTo = null;
12417 }
12418 Log.i(TAG, "Exiting application process "
12419 + app.processName + " ("
12420 + (app.thread != null ? app.thread.asBinder() : null)
12421 + ")\n");
12422 if (app.pid > 0 && app.pid != MY_PID) {
12423 Process.killProcess(app.pid);
12424 } else {
12425 try {
12426 app.thread.scheduleExit();
12427 } catch (Exception e) {
12428 // Ignore exceptions.
12429 }
12430 }
12431 // todo: For now we assume the application is not buggy
12432 // or evil, and will quit as a result of our request.
12433 // Eventually we need to drive this off of the death
12434 // notification, and kill the process if it takes too long.
12435 cleanUpApplicationRecordLocked(app, false, i);
12436 i--;
12437 //dump();
12438 }
12439 }
12440
12441 }
12442
12443 int curMaxActivities = MAX_ACTIVITIES;
12444 if (mAlwaysFinishActivities) {
12445 curMaxActivities = 1;
12446 }
12447
12448 // Finally, if there are too many activities now running, try to
12449 // finish as many as we can to get back down to the limit.
12450 for ( i=0;
12451 i<mLRUActivities.size()
12452 && mLRUActivities.size() > curMaxActivities;
12453 i++) {
12454 final HistoryRecord r
12455 = (HistoryRecord)mLRUActivities.get(i);
12456
12457 // We can finish this one if we have its icicle saved and
12458 // it is not persistent.
12459 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12460 && r.stopped && !r.persistent && !r.finishing) {
12461 final int origSize = mLRUActivities.size();
12462 destroyActivityLocked(r, true);
12463
12464 // This will remove it from the LRU list, so keep
12465 // our index at the same value. Note that this check to
12466 // see if the size changes is just paranoia -- if
12467 // something unexpected happens, we don't want to end up
12468 // in an infinite loop.
12469 if (origSize > mLRUActivities.size()) {
12470 i--;
12471 }
12472 }
12473 }
12474 }
12475 }
12476
12477 /** This method sends the specified signal to each of the persistent apps */
12478 public void signalPersistentProcesses(int sig) throws RemoteException {
12479 if (sig != Process.SIGNAL_USR1) {
12480 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12481 }
12482
12483 synchronized (this) {
12484 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12485 != PackageManager.PERMISSION_GRANTED) {
12486 throw new SecurityException("Requires permission "
12487 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12488 }
12489
12490 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12491 ProcessRecord r = mLRUProcesses.get(i);
12492 if (r.thread != null && r.persistent) {
12493 Process.sendSignal(r.pid, sig);
12494 }
12495 }
12496 }
12497 }
12498
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012499 public boolean profileControl(String process, boolean start,
12500 String path) throws RemoteException {
12501
12502 synchronized (this) {
12503 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12504 // its own permission.
12505 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12506 != PackageManager.PERMISSION_GRANTED) {
12507 throw new SecurityException("Requires permission "
12508 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12509 }
12510
12511 ProcessRecord proc = null;
12512 try {
12513 int pid = Integer.parseInt(process);
12514 synchronized (mPidsSelfLocked) {
12515 proc = mPidsSelfLocked.get(pid);
12516 }
12517 } catch (NumberFormatException e) {
12518 }
12519
12520 if (proc == null) {
12521 HashMap<String, SparseArray<ProcessRecord>> all
12522 = mProcessNames.getMap();
12523 SparseArray<ProcessRecord> procs = all.get(process);
12524 if (procs != null && procs.size() > 0) {
12525 proc = procs.valueAt(0);
12526 }
12527 }
12528
12529 if (proc == null || proc.thread == null) {
12530 throw new IllegalArgumentException("Unknown process: " + process);
12531 }
12532
12533 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12534 if (isSecure) {
12535 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12536 throw new SecurityException("Process not debuggable: " + proc);
12537 }
12538 }
12539
12540 try {
12541 proc.thread.profilerControl(start, path);
12542 return true;
12543 } catch (RemoteException e) {
12544 throw new IllegalStateException("Process disappeared");
12545 }
12546 }
12547 }
12548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012549 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12550 public void monitor() {
12551 synchronized (this) { }
12552 }
12553}