blob: 965079067c329d5b5f28bc7f0318acc5d7958a1d [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
186 | PackageManager.GET_SUPPORTS_DENSITIES;
187
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 // This is a process holding a secondary server -- killing it will not
293 // have much of an impact as far as the user is concerned. Value set in
294 // system/rootdir/init.rc on startup.
295 final int SECONDARY_SERVER_ADJ;
296
297 // This is a process only hosting activities that are visible to the
298 // user, so we'd prefer they don't disappear. Value set in
299 // system/rootdir/init.rc on startup.
300 final int VISIBLE_APP_ADJ;
301
302 // This is the process running the current foreground app. We'd really
303 // rather not kill it! Value set in system/rootdir/init.rc on startup.
304 final int FOREGROUND_APP_ADJ;
305
306 // This is a process running a core server, such as telephony. Definitely
307 // don't want to kill it, but doing so is not completely fatal.
308 static final int CORE_SERVER_ADJ = -12;
309
310 // The system process runs at the default adjustment.
311 static final int SYSTEM_ADJ = -16;
312
313 // Memory pages are 4K.
314 static final int PAGE_SIZE = 4*1024;
315
316 // Corresponding memory levels for above adjustments.
317 final int EMPTY_APP_MEM;
318 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800319 final int HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 final int SECONDARY_SERVER_MEM;
321 final int VISIBLE_APP_MEM;
322 final int FOREGROUND_APP_MEM;
323
324 final int MY_PID;
325
326 static final String[] EMPTY_STRING_ARRAY = new String[0];
327
328 enum ActivityState {
329 INITIALIZING,
330 RESUMED,
331 PAUSING,
332 PAUSED,
333 STOPPING,
334 STOPPED,
335 FINISHING,
336 DESTROYING,
337 DESTROYED
338 }
339
340 /**
341 * The back history of all previous (and possibly still
342 * running) activities. It contains HistoryRecord objects.
343 */
344 final ArrayList mHistory = new ArrayList();
345
346 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700347 * Description of a request to start a new activity, which has been held
348 * due to app switches being disabled.
349 */
350 class PendingActivityLaunch {
351 HistoryRecord r;
352 HistoryRecord sourceRecord;
353 Uri[] grantedUriPermissions;
354 int grantedMode;
355 boolean onlyIfNeeded;
356 }
357
358 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
359 = new ArrayList<PendingActivityLaunch>();
360
361 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 * List of all active broadcasts that are to be executed immediately
363 * (without waiting for another broadcast to finish). Currently this only
364 * contains broadcasts to registered receivers, to avoid spinning up
365 * a bunch of processes to execute IntentReceiver components.
366 */
367 final ArrayList<BroadcastRecord> mParallelBroadcasts
368 = new ArrayList<BroadcastRecord>();
369
370 /**
371 * List of all active broadcasts that are to be executed one at a time.
372 * The object at the top of the list is the currently activity broadcasts;
373 * those after it are waiting for the top to finish..
374 */
375 final ArrayList<BroadcastRecord> mOrderedBroadcasts
376 = new ArrayList<BroadcastRecord>();
377
378 /**
379 * Set when we current have a BROADCAST_INTENT_MSG in flight.
380 */
381 boolean mBroadcastsScheduled = false;
382
383 /**
384 * Set to indicate whether to issue an onUserLeaving callback when a
385 * newly launched activity is being brought in front of us.
386 */
387 boolean mUserLeaving = false;
388
389 /**
390 * When we are in the process of pausing an activity, before starting the
391 * next one, this variable holds the activity that is currently being paused.
392 */
393 HistoryRecord mPausingActivity = null;
394
395 /**
396 * Current activity that is resumed, or null if there is none.
397 */
398 HistoryRecord mResumedActivity = null;
399
400 /**
401 * Activity we have told the window manager to have key focus.
402 */
403 HistoryRecord mFocusedActivity = null;
404
405 /**
406 * This is the last activity that we put into the paused state. This is
407 * used to determine if we need to do an activity transition while sleeping,
408 * when we normally hold the top activity paused.
409 */
410 HistoryRecord mLastPausedActivity = null;
411
412 /**
413 * List of activities that are waiting for a new activity
414 * to become visible before completing whatever operation they are
415 * supposed to do.
416 */
417 final ArrayList mWaitingVisibleActivities = new ArrayList();
418
419 /**
420 * List of activities that are ready to be stopped, but waiting
421 * for the next activity to settle down before doing so. It contains
422 * HistoryRecord objects.
423 */
424 final ArrayList<HistoryRecord> mStoppingActivities
425 = new ArrayList<HistoryRecord>();
426
427 /**
428 * List of intents that were used to start the most recent tasks.
429 */
430 final ArrayList<TaskRecord> mRecentTasks
431 = new ArrayList<TaskRecord>();
432
433 /**
434 * List of activities that are ready to be finished, but waiting
435 * for the previous activity to settle down before doing so. It contains
436 * HistoryRecord objects.
437 */
438 final ArrayList mFinishingActivities = new ArrayList();
439
440 /**
441 * All of the applications we currently have running organized by name.
442 * The keys are strings of the application package name (as
443 * returned by the package manager), and the keys are ApplicationRecord
444 * objects.
445 */
446 final ProcessMap<ProcessRecord> mProcessNames
447 = new ProcessMap<ProcessRecord>();
448
449 /**
450 * The last time that various processes have crashed.
451 */
452 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
453
454 /**
455 * Set of applications that we consider to be bad, and will reject
456 * incoming broadcasts from (which the user has no control over).
457 * Processes are added to this set when they have crashed twice within
458 * a minimum amount of time; they are removed from it when they are
459 * later restarted (hopefully due to some user action). The value is the
460 * time it was added to the list.
461 */
462 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
463
464 /**
465 * All of the processes we currently have running organized by pid.
466 * The keys are the pid running the application.
467 *
468 * <p>NOTE: This object is protected by its own lock, NOT the global
469 * activity manager lock!
470 */
471 final SparseArray<ProcessRecord> mPidsSelfLocked
472 = new SparseArray<ProcessRecord>();
473
474 /**
475 * All of the processes that have been forced to be foreground. The key
476 * is the pid of the caller who requested it (we hold a death
477 * link on it).
478 */
479 abstract class ForegroundToken implements IBinder.DeathRecipient {
480 int pid;
481 IBinder token;
482 }
483 final SparseArray<ForegroundToken> mForegroundProcesses
484 = new SparseArray<ForegroundToken>();
485
486 /**
487 * List of records for processes that someone had tried to start before the
488 * system was ready. We don't start them at that point, but ensure they
489 * are started by the time booting is complete.
490 */
491 final ArrayList<ProcessRecord> mProcessesOnHold
492 = new ArrayList<ProcessRecord>();
493
494 /**
495 * List of records for processes that we have started and are waiting
496 * for them to call back. This is really only needed when running in
497 * single processes mode, in which case we do not have a unique pid for
498 * each process.
499 */
500 final ArrayList<ProcessRecord> mStartingProcesses
501 = new ArrayList<ProcessRecord>();
502
503 /**
504 * List of persistent applications that are in the process
505 * of being started.
506 */
507 final ArrayList<ProcessRecord> mPersistentStartingProcesses
508 = new ArrayList<ProcessRecord>();
509
510 /**
511 * Processes that are being forcibly torn down.
512 */
513 final ArrayList<ProcessRecord> mRemovedProcesses
514 = new ArrayList<ProcessRecord>();
515
516 /**
517 * List of running applications, sorted by recent usage.
518 * The first entry in the list is the least recently used.
519 * It contains ApplicationRecord objects. This list does NOT include
520 * any persistent application records (since we never want to exit them).
521 */
522 final ArrayList<ProcessRecord> mLRUProcesses
523 = new ArrayList<ProcessRecord>();
524
525 /**
526 * List of processes that should gc as soon as things are idle.
527 */
528 final ArrayList<ProcessRecord> mProcessesToGc
529 = new ArrayList<ProcessRecord>();
530
531 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800532 * This is the process holding what we currently consider to be
533 * the "home" activity.
534 */
535 private ProcessRecord mHomeProcess;
536
537 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 * List of running activities, sorted by recent usage.
539 * The first entry in the list is the least recently used.
540 * It contains HistoryRecord objects.
541 */
542 private final ArrayList mLRUActivities = new ArrayList();
543
544 /**
545 * Set of PendingResultRecord objects that are currently active.
546 */
547 final HashSet mPendingResultRecords = new HashSet();
548
549 /**
550 * Set of IntentSenderRecord objects that are currently active.
551 */
552 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
553 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
554
555 /**
556 * Intent broadcast that we have tried to start, but are
557 * waiting for its application's process to be created. We only
558 * need one (instead of a list) because we always process broadcasts
559 * one at a time, so no others can be started while waiting for this
560 * one.
561 */
562 BroadcastRecord mPendingBroadcast = null;
563
564 /**
565 * Keeps track of all IIntentReceivers that have been registered for
566 * broadcasts. Hash keys are the receiver IBinder, hash value is
567 * a ReceiverList.
568 */
569 final HashMap mRegisteredReceivers = new HashMap();
570
571 /**
572 * Resolver for broadcast intents to registered receivers.
573 * Holds BroadcastFilter (subclass of IntentFilter).
574 */
575 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
576 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
577 @Override
578 protected boolean allowFilterResult(
579 BroadcastFilter filter, List<BroadcastFilter> dest) {
580 IBinder target = filter.receiverList.receiver.asBinder();
581 for (int i=dest.size()-1; i>=0; i--) {
582 if (dest.get(i).receiverList.receiver.asBinder() == target) {
583 return false;
584 }
585 }
586 return true;
587 }
588 };
589
590 /**
591 * State of all active sticky broadcasts. Keys are the action of the
592 * sticky Intent, values are an ArrayList of all broadcasted intents with
593 * that action (which should usually be one).
594 */
595 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
596 new HashMap<String, ArrayList<Intent>>();
597
598 /**
599 * All currently running services.
600 */
601 final HashMap<ComponentName, ServiceRecord> mServices =
602 new HashMap<ComponentName, ServiceRecord>();
603
604 /**
605 * All currently running services indexed by the Intent used to start them.
606 */
607 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
608 new HashMap<Intent.FilterComparison, ServiceRecord>();
609
610 /**
611 * All currently bound service connections. Keys are the IBinder of
612 * the client's IServiceConnection.
613 */
614 final HashMap<IBinder, ConnectionRecord> mServiceConnections
615 = new HashMap<IBinder, ConnectionRecord>();
616
617 /**
618 * List of services that we have been asked to start,
619 * but haven't yet been able to. It is used to hold start requests
620 * while waiting for their corresponding application thread to get
621 * going.
622 */
623 final ArrayList<ServiceRecord> mPendingServices
624 = new ArrayList<ServiceRecord>();
625
626 /**
627 * List of services that are scheduled to restart following a crash.
628 */
629 final ArrayList<ServiceRecord> mRestartingServices
630 = new ArrayList<ServiceRecord>();
631
632 /**
633 * List of services that are in the process of being stopped.
634 */
635 final ArrayList<ServiceRecord> mStoppingServices
636 = new ArrayList<ServiceRecord>();
637
638 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700639 * Backup/restore process management
640 */
641 String mBackupAppName = null;
642 BackupRecord mBackupTarget = null;
643
644 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 * List of PendingThumbnailsRecord objects of clients who are still
646 * waiting to receive all of the thumbnails for a task.
647 */
648 final ArrayList mPendingThumbnails = new ArrayList();
649
650 /**
651 * List of HistoryRecord objects that have been finished and must
652 * still report back to a pending thumbnail receiver.
653 */
654 final ArrayList mCancelledThumbnails = new ArrayList();
655
656 /**
657 * All of the currently running global content providers. Keys are a
658 * string containing the provider name and values are a
659 * ContentProviderRecord object containing the data about it. Note
660 * that a single provider may be published under multiple names, so
661 * there may be multiple entries here for a single one in mProvidersByClass.
662 */
663 final HashMap mProvidersByName = new HashMap();
664
665 /**
666 * All of the currently running global content providers. Keys are a
667 * string containing the provider's implementation class and values are a
668 * ContentProviderRecord object containing the data about it.
669 */
670 final HashMap mProvidersByClass = new HashMap();
671
672 /**
673 * List of content providers who have clients waiting for them. The
674 * application is currently being launched and the provider will be
675 * removed from this list once it is published.
676 */
677 final ArrayList mLaunchingProviders = new ArrayList();
678
679 /**
680 * Global set of specific Uri permissions that have been granted.
681 */
682 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
683 = new SparseArray<HashMap<Uri, UriPermission>>();
684
685 /**
686 * Thread-local storage used to carry caller permissions over through
687 * indirect content-provider access.
688 * @see #ActivityManagerService.openContentUri()
689 */
690 private class Identity {
691 public int pid;
692 public int uid;
693
694 Identity(int _pid, int _uid) {
695 pid = _pid;
696 uid = _uid;
697 }
698 }
699 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
700
701 /**
702 * All information we have collected about the runtime performance of
703 * any user id that can impact battery performance.
704 */
705 final BatteryStatsService mBatteryStatsService;
706
707 /**
708 * information about component usage
709 */
710 final UsageStatsService mUsageStatsService;
711
712 /**
713 * Current configuration information. HistoryRecord objects are given
714 * a reference to this object to indicate which configuration they are
715 * currently running in, so this object must be kept immutable.
716 */
717 Configuration mConfiguration = new Configuration();
718
719 /**
720 * List of initialization arguments to pass to all processes when binding applications to them.
721 * For example, references to the commonly used services.
722 */
723 HashMap<String, IBinder> mAppBindArgs;
724
725 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700726 * Temporary to avoid allocations. Protected by main lock.
727 */
728 final StringBuilder mStringBuilder = new StringBuilder(256);
729
730 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 * Used to control how we initialize the service.
732 */
733 boolean mStartRunning = false;
734 ComponentName mTopComponent;
735 String mTopAction;
736 String mTopData;
737 boolean mSystemReady = false;
738 boolean mBooting = false;
739
740 Context mContext;
741
742 int mFactoryTest;
743
744 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700745 * The time at which we will allow normal application switches again,
746 * after a call to {@link #stopAppSwitches()}.
747 */
748 long mAppSwitchesAllowedTime;
749
750 /**
751 * This is set to true after the first switch after mAppSwitchesAllowedTime
752 * is set; any switches after that will clear the time.
753 */
754 boolean mDidAppSwitch;
755
756 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 * Set while we are wanting to sleep, to prevent any
758 * activities from being started/resumed.
759 */
760 boolean mSleeping = false;
761
762 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700763 * Set if we are shutting down the system, similar to sleeping.
764 */
765 boolean mShuttingDown = false;
766
767 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 * Set when the system is going to sleep, until we have
769 * successfully paused the current activity and released our wake lock.
770 * At that point the system is allowed to actually sleep.
771 */
772 PowerManager.WakeLock mGoingToSleep;
773
774 /**
775 * We don't want to allow the device to go to sleep while in the process
776 * of launching an activity. This is primarily to allow alarm intent
777 * receivers to launch an activity and get that to run before the device
778 * goes back to sleep.
779 */
780 PowerManager.WakeLock mLaunchingActivity;
781
782 /**
783 * Task identifier that activities are currently being started
784 * in. Incremented each time a new task is created.
785 * todo: Replace this with a TokenSpace class that generates non-repeating
786 * integers that won't wrap.
787 */
788 int mCurTask = 1;
789
790 /**
791 * Current sequence id for oom_adj computation traversal.
792 */
793 int mAdjSeq = 0;
794
795 /**
796 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
797 * is set, indicating the user wants processes started in such a way
798 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
799 * running in each process (thus no pre-initialized process, etc).
800 */
801 boolean mSimpleProcessManagement = false;
802
803 /**
804 * System monitoring: number of processes that died since the last
805 * N procs were started.
806 */
807 int[] mProcDeaths = new int[20];
808
809 String mDebugApp = null;
810 boolean mWaitForDebugger = false;
811 boolean mDebugTransient = false;
812 String mOrigDebugApp = null;
813 boolean mOrigWaitForDebugger = false;
814 boolean mAlwaysFinishActivities = false;
815 IActivityWatcher mWatcher = null;
816
817 /**
818 * Callback of last caller to {@link #requestPss}.
819 */
820 Runnable mRequestPssCallback;
821
822 /**
823 * Remaining processes for which we are waiting results from the last
824 * call to {@link #requestPss}.
825 */
826 final ArrayList<ProcessRecord> mRequestPssList
827 = new ArrayList<ProcessRecord>();
828
829 /**
830 * Runtime statistics collection thread. This object's lock is used to
831 * protect all related state.
832 */
833 final Thread mProcessStatsThread;
834
835 /**
836 * Used to collect process stats when showing not responding dialog.
837 * Protected by mProcessStatsThread.
838 */
839 final ProcessStats mProcessStats = new ProcessStats(
840 MONITOR_THREAD_CPU_USAGE);
841 long mLastCpuTime = 0;
842 long mLastWriteTime = 0;
843
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700844 long mInitialStartTime = 0;
845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 /**
847 * Set to true after the system has finished booting.
848 */
849 boolean mBooted = false;
850
851 int mProcessLimit = 0;
852
853 WindowManagerService mWindowManager;
854
855 static ActivityManagerService mSelf;
856 static ActivityThread mSystemThread;
857
858 private final class AppDeathRecipient implements IBinder.DeathRecipient {
859 final ProcessRecord mApp;
860 final int mPid;
861 final IApplicationThread mAppThread;
862
863 AppDeathRecipient(ProcessRecord app, int pid,
864 IApplicationThread thread) {
865 if (localLOGV) Log.v(
866 TAG, "New death recipient " + this
867 + " for thread " + thread.asBinder());
868 mApp = app;
869 mPid = pid;
870 mAppThread = thread;
871 }
872
873 public void binderDied() {
874 if (localLOGV) Log.v(
875 TAG, "Death received in " + this
876 + " for thread " + mAppThread.asBinder());
877 removeRequestedPss(mApp);
878 synchronized(ActivityManagerService.this) {
879 appDiedLocked(mApp, mPid, mAppThread);
880 }
881 }
882 }
883
884 static final int SHOW_ERROR_MSG = 1;
885 static final int SHOW_NOT_RESPONDING_MSG = 2;
886 static final int SHOW_FACTORY_ERROR_MSG = 3;
887 static final int UPDATE_CONFIGURATION_MSG = 4;
888 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
889 static final int WAIT_FOR_DEBUGGER_MSG = 6;
890 static final int BROADCAST_INTENT_MSG = 7;
891 static final int BROADCAST_TIMEOUT_MSG = 8;
892 static final int PAUSE_TIMEOUT_MSG = 9;
893 static final int IDLE_TIMEOUT_MSG = 10;
894 static final int IDLE_NOW_MSG = 11;
895 static final int SERVICE_TIMEOUT_MSG = 12;
896 static final int UPDATE_TIME_ZONE = 13;
897 static final int SHOW_UID_ERROR_MSG = 14;
898 static final int IM_FEELING_LUCKY_MSG = 15;
899 static final int LAUNCH_TIMEOUT_MSG = 16;
900 static final int DESTROY_TIMEOUT_MSG = 17;
901 static final int SERVICE_ERROR_MSG = 18;
902 static final int RESUME_TOP_ACTIVITY_MSG = 19;
903 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700904 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905
906 AlertDialog mUidAlert;
907
908 final Handler mHandler = new Handler() {
909 //public Handler() {
910 // if (localLOGV) Log.v(TAG, "Handler started!");
911 //}
912
913 public void handleMessage(Message msg) {
914 switch (msg.what) {
915 case SHOW_ERROR_MSG: {
916 HashMap data = (HashMap) msg.obj;
917 byte[] crashData = (byte[])data.get("crashData");
918 if (crashData != null) {
919 // This needs to be *un*synchronized to avoid deadlock.
920 ContentResolver resolver = mContext.getContentResolver();
921 Checkin.reportCrash(resolver, crashData);
922 }
923 synchronized (ActivityManagerService.this) {
924 ProcessRecord proc = (ProcessRecord)data.get("app");
925 if (proc != null && proc.crashDialog != null) {
926 Log.e(TAG, "App already has crash dialog: " + proc);
927 return;
928 }
929 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700930 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 Dialog d = new AppErrorDialog(
932 mContext, res, proc,
933 (Integer)data.get("flags"),
934 (String)data.get("shortMsg"),
935 (String)data.get("longMsg"));
936 d.show();
937 proc.crashDialog = d;
938 } else {
939 // The device is asleep, so just pretend that the user
940 // saw a crash dialog and hit "force quit".
941 res.set(0);
942 }
943 }
944 } break;
945 case SHOW_NOT_RESPONDING_MSG: {
946 synchronized (ActivityManagerService.this) {
947 HashMap data = (HashMap) msg.obj;
948 ProcessRecord proc = (ProcessRecord)data.get("app");
949 if (proc != null && proc.anrDialog != null) {
950 Log.e(TAG, "App already has anr dialog: " + proc);
951 return;
952 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800953
954 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
955 null, null, 0, null, null, null,
956 false, false, MY_PID, Process.SYSTEM_UID);
957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
959 mContext, proc, (HistoryRecord)data.get("activity"));
960 d.show();
961 proc.anrDialog = d;
962 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700963
964 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 } break;
966 case SHOW_FACTORY_ERROR_MSG: {
967 Dialog d = new FactoryErrorDialog(
968 mContext, msg.getData().getCharSequence("msg"));
969 d.show();
970 enableScreenAfterBoot();
971 } break;
972 case UPDATE_CONFIGURATION_MSG: {
973 final ContentResolver resolver = mContext.getContentResolver();
974 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
975 } break;
976 case GC_BACKGROUND_PROCESSES_MSG: {
977 synchronized (ActivityManagerService.this) {
978 performAppGcsIfAppropriateLocked();
979 }
980 } break;
981 case WAIT_FOR_DEBUGGER_MSG: {
982 synchronized (ActivityManagerService.this) {
983 ProcessRecord app = (ProcessRecord)msg.obj;
984 if (msg.arg1 != 0) {
985 if (!app.waitedForDebugger) {
986 Dialog d = new AppWaitingForDebuggerDialog(
987 ActivityManagerService.this,
988 mContext, app);
989 app.waitDialog = d;
990 app.waitedForDebugger = true;
991 d.show();
992 }
993 } else {
994 if (app.waitDialog != null) {
995 app.waitDialog.dismiss();
996 app.waitDialog = null;
997 }
998 }
999 }
1000 } break;
1001 case BROADCAST_INTENT_MSG: {
1002 if (DEBUG_BROADCAST) Log.v(
1003 TAG, "Received BROADCAST_INTENT_MSG");
1004 processNextBroadcast(true);
1005 } break;
1006 case BROADCAST_TIMEOUT_MSG: {
1007 broadcastTimeout();
1008 } break;
1009 case PAUSE_TIMEOUT_MSG: {
1010 IBinder token = (IBinder)msg.obj;
1011 // We don't at this point know if the activity is fullscreen,
1012 // so we need to be conservative and assume it isn't.
1013 Log.w(TAG, "Activity pause timeout for " + token);
1014 activityPaused(token, null, true);
1015 } break;
1016 case IDLE_TIMEOUT_MSG: {
1017 IBinder token = (IBinder)msg.obj;
1018 // We don't at this point know if the activity is fullscreen,
1019 // so we need to be conservative and assume it isn't.
1020 Log.w(TAG, "Activity idle timeout for " + token);
1021 activityIdleInternal(token, true);
1022 } break;
1023 case DESTROY_TIMEOUT_MSG: {
1024 IBinder token = (IBinder)msg.obj;
1025 // We don't at this point know if the activity is fullscreen,
1026 // so we need to be conservative and assume it isn't.
1027 Log.w(TAG, "Activity destroy timeout for " + token);
1028 activityDestroyed(token);
1029 } break;
1030 case IDLE_NOW_MSG: {
1031 IBinder token = (IBinder)msg.obj;
1032 activityIdle(token);
1033 } break;
1034 case SERVICE_TIMEOUT_MSG: {
1035 serviceTimeout((ProcessRecord)msg.obj);
1036 } break;
1037 case UPDATE_TIME_ZONE: {
1038 synchronized (ActivityManagerService.this) {
1039 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1040 ProcessRecord r = mLRUProcesses.get(i);
1041 if (r.thread != null) {
1042 try {
1043 r.thread.updateTimeZone();
1044 } catch (RemoteException ex) {
1045 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1046 }
1047 }
1048 }
1049 }
1050 break;
1051 }
1052 case SHOW_UID_ERROR_MSG: {
1053 // XXX This is a temporary dialog, no need to localize.
1054 AlertDialog d = new BaseErrorDialog(mContext);
1055 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1056 d.setCancelable(false);
1057 d.setTitle("System UIDs Inconsistent");
1058 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1059 d.setButton("I'm Feeling Lucky",
1060 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1061 mUidAlert = d;
1062 d.show();
1063 } break;
1064 case IM_FEELING_LUCKY_MSG: {
1065 if (mUidAlert != null) {
1066 mUidAlert.dismiss();
1067 mUidAlert = null;
1068 }
1069 } break;
1070 case LAUNCH_TIMEOUT_MSG: {
1071 synchronized (ActivityManagerService.this) {
1072 if (mLaunchingActivity.isHeld()) {
1073 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1074 mLaunchingActivity.release();
1075 }
1076 }
1077 } break;
1078 case SERVICE_ERROR_MSG: {
1079 ServiceRecord srv = (ServiceRecord)msg.obj;
1080 // This needs to be *un*synchronized to avoid deadlock.
1081 Checkin.logEvent(mContext.getContentResolver(),
1082 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1083 srv.name.toShortString());
1084 } break;
1085 case RESUME_TOP_ACTIVITY_MSG: {
1086 synchronized (ActivityManagerService.this) {
1087 resumeTopActivityLocked(null);
1088 }
1089 }
1090 case PROC_START_TIMEOUT_MSG: {
1091 ProcessRecord app = (ProcessRecord)msg.obj;
1092 synchronized (ActivityManagerService.this) {
1093 processStartTimedOutLocked(app);
1094 }
1095 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001096 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1097 synchronized (ActivityManagerService.this) {
1098 doPendingActivityLaunchesLocked(true);
1099 }
1100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
1102 }
1103 };
1104
1105 public static void setSystemProcess() {
1106 try {
1107 ActivityManagerService m = mSelf;
1108
1109 ServiceManager.addService("activity", m);
1110 ServiceManager.addService("meminfo", new MemBinder(m));
1111 if (MONITOR_CPU_USAGE) {
1112 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1113 }
1114 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1115 ServiceManager.addService("activity.services", new ServicesBinder(m));
1116 ServiceManager.addService("activity.senders", new SendersBinder(m));
1117 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1118 ServiceManager.addService("permission", new PermissionController(m));
1119
1120 ApplicationInfo info =
1121 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001122 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 synchronized (mSelf) {
1124 ProcessRecord app = mSelf.newProcessRecordLocked(
1125 mSystemThread.getApplicationThread(), info,
1126 info.processName);
1127 app.persistent = true;
1128 app.pid = Process.myPid();
1129 app.maxAdj = SYSTEM_ADJ;
1130 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1131 synchronized (mSelf.mPidsSelfLocked) {
1132 mSelf.mPidsSelfLocked.put(app.pid, app);
1133 }
1134 mSelf.updateLRUListLocked(app, true);
1135 }
1136 } catch (PackageManager.NameNotFoundException e) {
1137 throw new RuntimeException(
1138 "Unable to find android system package", e);
1139 }
1140 }
1141
1142 public void setWindowManager(WindowManagerService wm) {
1143 mWindowManager = wm;
1144 }
1145
1146 public static final Context main(int factoryTest) {
1147 AThread thr = new AThread();
1148 thr.start();
1149
1150 synchronized (thr) {
1151 while (thr.mService == null) {
1152 try {
1153 thr.wait();
1154 } catch (InterruptedException e) {
1155 }
1156 }
1157 }
1158
1159 ActivityManagerService m = thr.mService;
1160 mSelf = m;
1161 ActivityThread at = ActivityThread.systemMain();
1162 mSystemThread = at;
1163 Context context = at.getSystemContext();
1164 m.mContext = context;
1165 m.mFactoryTest = factoryTest;
1166 PowerManager pm =
1167 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1168 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1169 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1170 m.mLaunchingActivity.setReferenceCounted(false);
1171
1172 m.mBatteryStatsService.publish(context);
1173 m.mUsageStatsService.publish(context);
1174
1175 synchronized (thr) {
1176 thr.mReady = true;
1177 thr.notifyAll();
1178 }
1179
1180 m.startRunning(null, null, null, null);
1181
1182 return context;
1183 }
1184
1185 public static ActivityManagerService self() {
1186 return mSelf;
1187 }
1188
1189 static class AThread extends Thread {
1190 ActivityManagerService mService;
1191 boolean mReady = false;
1192
1193 public AThread() {
1194 super("ActivityManager");
1195 }
1196
1197 public void run() {
1198 Looper.prepare();
1199
1200 android.os.Process.setThreadPriority(
1201 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1202
1203 ActivityManagerService m = new ActivityManagerService();
1204
1205 synchronized (this) {
1206 mService = m;
1207 notifyAll();
1208 }
1209
1210 synchronized (this) {
1211 while (!mReady) {
1212 try {
1213 wait();
1214 } catch (InterruptedException e) {
1215 }
1216 }
1217 }
1218
1219 Looper.loop();
1220 }
1221 }
1222
1223 static class BroadcastsBinder extends Binder {
1224 ActivityManagerService mActivityManagerService;
1225 BroadcastsBinder(ActivityManagerService activityManagerService) {
1226 mActivityManagerService = activityManagerService;
1227 }
1228
1229 @Override
1230 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1231 mActivityManagerService.dumpBroadcasts(pw);
1232 }
1233 }
1234
1235 static class ServicesBinder extends Binder {
1236 ActivityManagerService mActivityManagerService;
1237 ServicesBinder(ActivityManagerService activityManagerService) {
1238 mActivityManagerService = activityManagerService;
1239 }
1240
1241 @Override
1242 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1243 mActivityManagerService.dumpServices(pw);
1244 }
1245 }
1246
1247 static class SendersBinder extends Binder {
1248 ActivityManagerService mActivityManagerService;
1249 SendersBinder(ActivityManagerService activityManagerService) {
1250 mActivityManagerService = activityManagerService;
1251 }
1252
1253 @Override
1254 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1255 mActivityManagerService.dumpSenders(pw);
1256 }
1257 }
1258
1259 static class ProvidersBinder extends Binder {
1260 ActivityManagerService mActivityManagerService;
1261 ProvidersBinder(ActivityManagerService activityManagerService) {
1262 mActivityManagerService = activityManagerService;
1263 }
1264
1265 @Override
1266 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1267 mActivityManagerService.dumpProviders(pw);
1268 }
1269 }
1270
1271 static class MemBinder extends Binder {
1272 ActivityManagerService mActivityManagerService;
1273 MemBinder(ActivityManagerService activityManagerService) {
1274 mActivityManagerService = activityManagerService;
1275 }
1276
1277 @Override
1278 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1279 ActivityManagerService service = mActivityManagerService;
1280 ArrayList<ProcessRecord> procs;
1281 synchronized (mActivityManagerService) {
1282 if (args != null && args.length > 0
1283 && args[0].charAt(0) != '-') {
1284 procs = new ArrayList<ProcessRecord>();
1285 int pid = -1;
1286 try {
1287 pid = Integer.parseInt(args[0]);
1288 } catch (NumberFormatException e) {
1289
1290 }
1291 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1292 ProcessRecord proc = service.mLRUProcesses.get(i);
1293 if (proc.pid == pid) {
1294 procs.add(proc);
1295 } else if (proc.processName.equals(args[0])) {
1296 procs.add(proc);
1297 }
1298 }
1299 if (procs.size() <= 0) {
1300 pw.println("No process found for: " + args[0]);
1301 return;
1302 }
1303 } else {
1304 procs = service.mLRUProcesses;
1305 }
1306 }
1307 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1308 }
1309 }
1310
1311 static class CpuBinder extends Binder {
1312 ActivityManagerService mActivityManagerService;
1313 CpuBinder(ActivityManagerService activityManagerService) {
1314 mActivityManagerService = activityManagerService;
1315 }
1316
1317 @Override
1318 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1319 synchronized (mActivityManagerService.mProcessStatsThread) {
1320 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1321 }
1322 }
1323 }
1324
1325 private ActivityManagerService() {
1326 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1327 if (v != null && Integer.getInteger(v) != 0) {
1328 mSimpleProcessManagement = true;
1329 }
1330 v = System.getenv("ANDROID_DEBUG_APP");
1331 if (v != null) {
1332 mSimpleProcessManagement = true;
1333 }
1334
1335 MY_PID = Process.myPid();
1336
1337 File dataDir = Environment.getDataDirectory();
1338 File systemDir = new File(dataDir, "system");
1339 systemDir.mkdirs();
1340 mBatteryStatsService = new BatteryStatsService(new File(
1341 systemDir, "batterystats.bin").toString());
1342 mBatteryStatsService.getActiveStatistics().readLocked();
1343 mBatteryStatsService.getActiveStatistics().writeLocked();
1344
1345 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001346 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347
1348 mConfiguration.makeDefault();
1349 mProcessStats.init();
1350
1351 // Add ourself to the Watchdog monitors.
1352 Watchdog.getInstance().addMonitor(this);
1353
1354 // These values are set in system/rootdir/init.rc on startup.
1355 FOREGROUND_APP_ADJ =
1356 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1357 VISIBLE_APP_ADJ =
1358 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1359 SECONDARY_SERVER_ADJ =
1360 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001361 HOME_APP_ADJ =
1362 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 HIDDEN_APP_MIN_ADJ =
1364 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1365 CONTENT_PROVIDER_ADJ =
1366 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1367 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1368 EMPTY_APP_ADJ =
1369 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1370 FOREGROUND_APP_MEM =
1371 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1372 VISIBLE_APP_MEM =
1373 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1374 SECONDARY_SERVER_MEM =
1375 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001376 HOME_APP_MEM =
1377 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 HIDDEN_APP_MEM =
1379 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1380 EMPTY_APP_MEM =
1381 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1382
1383 mProcessStatsThread = new Thread("ProcessStats") {
1384 public void run() {
1385 while (true) {
1386 try {
1387 try {
1388 synchronized(this) {
1389 final long now = SystemClock.uptimeMillis();
1390 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1391 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1392 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1393 // + ", write delay=" + nextWriteDelay);
1394 if (nextWriteDelay < nextCpuDelay) {
1395 nextCpuDelay = nextWriteDelay;
1396 }
1397 if (nextCpuDelay > 0) {
1398 this.wait(nextCpuDelay);
1399 }
1400 }
1401 } catch (InterruptedException e) {
1402 }
1403
1404 updateCpuStatsNow();
1405 } catch (Exception e) {
1406 Log.e(TAG, "Unexpected exception collecting process stats", e);
1407 }
1408 }
1409 }
1410 };
1411 mProcessStatsThread.start();
1412 }
1413
1414 @Override
1415 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1416 throws RemoteException {
1417 try {
1418 return super.onTransact(code, data, reply, flags);
1419 } catch (RuntimeException e) {
1420 // The activity manager only throws security exceptions, so let's
1421 // log all others.
1422 if (!(e instanceof SecurityException)) {
1423 Log.e(TAG, "Activity Manager Crash", e);
1424 }
1425 throw e;
1426 }
1427 }
1428
1429 void updateCpuStats() {
1430 synchronized (mProcessStatsThread) {
1431 final long now = SystemClock.uptimeMillis();
1432 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1433 mProcessStatsThread.notify();
1434 }
1435 }
1436 }
1437
1438 void updateCpuStatsNow() {
1439 synchronized (mProcessStatsThread) {
1440 final long now = SystemClock.uptimeMillis();
1441 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 if (MONITOR_CPU_USAGE &&
1444 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1445 mLastCpuTime = now;
1446 haveNewCpuStats = true;
1447 mProcessStats.update();
1448 //Log.i(TAG, mProcessStats.printCurrentState());
1449 //Log.i(TAG, "Total CPU usage: "
1450 // + mProcessStats.getTotalCpuPercent() + "%");
1451
1452 // Log the cpu usage if the property is set.
1453 if ("true".equals(SystemProperties.get("events.cpu"))) {
1454 int user = mProcessStats.getLastUserTime();
1455 int system = mProcessStats.getLastSystemTime();
1456 int iowait = mProcessStats.getLastIoWaitTime();
1457 int irq = mProcessStats.getLastIrqTime();
1458 int softIrq = mProcessStats.getLastSoftIrqTime();
1459 int idle = mProcessStats.getLastIdleTime();
1460
1461 int total = user + system + iowait + irq + softIrq + idle;
1462 if (total == 0) total = 1;
1463
1464 EventLog.writeEvent(LOG_CPU,
1465 ((user+system+iowait+irq+softIrq) * 100) / total,
1466 (user * 100) / total,
1467 (system * 100) / total,
1468 (iowait * 100) / total,
1469 (irq * 100) / total,
1470 (softIrq * 100) / total);
1471 }
1472 }
1473
1474 synchronized(mBatteryStatsService.getActiveStatistics()) {
1475 synchronized(mPidsSelfLocked) {
1476 if (haveNewCpuStats) {
1477 if (mBatteryStatsService.isOnBattery()) {
1478 final int N = mProcessStats.countWorkingStats();
1479 for (int i=0; i<N; i++) {
1480 ProcessStats.Stats st
1481 = mProcessStats.getWorkingStats(i);
1482 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1483 if (pr != null) {
1484 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1485 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1486 }
1487 }
1488 }
1489 }
1490 }
1491
1492 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1493 mLastWriteTime = now;
1494 mBatteryStatsService.getActiveStatistics().writeLocked();
1495 }
1496 }
1497 }
1498 }
1499
1500 /**
1501 * Initialize the application bind args. These are passed to each
1502 * process when the bindApplication() IPC is sent to the process. They're
1503 * lazily setup to make sure the services are running when they're asked for.
1504 */
1505 private HashMap<String, IBinder> getCommonServicesLocked() {
1506 if (mAppBindArgs == null) {
1507 mAppBindArgs = new HashMap<String, IBinder>();
1508
1509 // Setup the application init args
1510 mAppBindArgs.put("package", ServiceManager.getService("package"));
1511 mAppBindArgs.put("window", ServiceManager.getService("window"));
1512 mAppBindArgs.put(Context.ALARM_SERVICE,
1513 ServiceManager.getService(Context.ALARM_SERVICE));
1514 }
1515 return mAppBindArgs;
1516 }
1517
1518 private final void setFocusedActivityLocked(HistoryRecord r) {
1519 if (mFocusedActivity != r) {
1520 mFocusedActivity = r;
1521 mWindowManager.setFocusedApp(r, true);
1522 }
1523 }
1524
1525 private final void updateLRUListLocked(ProcessRecord app,
1526 boolean oomAdj) {
1527 // put it on the LRU to keep track of when it should be exited.
1528 int lrui = mLRUProcesses.indexOf(app);
1529 if (lrui >= 0) mLRUProcesses.remove(lrui);
1530 mLRUProcesses.add(app);
1531 //Log.i(TAG, "Putting proc to front: " + app.processName);
1532 if (oomAdj) {
1533 updateOomAdjLocked();
1534 }
1535 }
1536
1537 private final boolean updateLRUListLocked(HistoryRecord r) {
1538 final boolean hadit = mLRUActivities.remove(r);
1539 mLRUActivities.add(r);
1540 return hadit;
1541 }
1542
1543 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1544 int i = mHistory.size()-1;
1545 while (i >= 0) {
1546 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1547 if (!r.finishing && r != notTop) {
1548 return r;
1549 }
1550 i--;
1551 }
1552 return null;
1553 }
1554
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001555 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1556 int i = mHistory.size()-1;
1557 while (i >= 0) {
1558 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1559 if (!r.finishing && !r.delayedResume && r != notTop) {
1560 return r;
1561 }
1562 i--;
1563 }
1564 return null;
1565 }
1566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001567 /**
1568 * This is a simplified version of topRunningActivityLocked that provides a number of
1569 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1570 *
1571 * @param token If non-null, any history records matching this token will be skipped.
1572 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1573 *
1574 * @return Returns the HistoryRecord of the next activity on the stack.
1575 */
1576 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1577 int i = mHistory.size()-1;
1578 while (i >= 0) {
1579 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1580 // Note: the taskId check depends on real taskId fields being non-zero
1581 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1582 return r;
1583 }
1584 i--;
1585 }
1586 return null;
1587 }
1588
1589 private final ProcessRecord getProcessRecordLocked(
1590 String processName, int uid) {
1591 if (uid == Process.SYSTEM_UID) {
1592 // The system gets to run in any process. If there are multiple
1593 // processes with the same uid, just pick the first (this
1594 // should never happen).
1595 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1596 processName);
1597 return procs != null ? procs.valueAt(0) : null;
1598 }
1599 ProcessRecord proc = mProcessNames.get(processName, uid);
1600 return proc;
1601 }
1602
1603 private boolean isNextTransitionForward() {
1604 int transit = mWindowManager.getPendingAppTransition();
1605 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1606 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1607 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1608 }
1609
1610 private final boolean realStartActivityLocked(HistoryRecord r,
1611 ProcessRecord app, boolean andResume, boolean checkConfig)
1612 throws RemoteException {
1613
1614 r.startFreezingScreenLocked(app, 0);
1615 mWindowManager.setAppVisibility(r, true);
1616
1617 // Have the window manager re-evaluate the orientation of
1618 // the screen based on the new activity order. Note that
1619 // as a result of this, it can call back into the activity
1620 // manager with a new orientation. We don't care about that,
1621 // because the activity is not currently running so we are
1622 // just restarting it anyway.
1623 if (checkConfig) {
1624 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001625 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001626 r.mayFreezeScreenLocked(app) ? r : null);
1627 updateConfigurationLocked(config, r);
1628 }
1629
1630 r.app = app;
1631
1632 if (localLOGV) Log.v(TAG, "Launching: " + r);
1633
1634 int idx = app.activities.indexOf(r);
1635 if (idx < 0) {
1636 app.activities.add(r);
1637 }
1638 updateLRUListLocked(app, true);
1639
1640 try {
1641 if (app.thread == null) {
1642 throw new RemoteException();
1643 }
1644 List<ResultInfo> results = null;
1645 List<Intent> newIntents = null;
1646 if (andResume) {
1647 results = r.results;
1648 newIntents = r.newIntents;
1649 }
1650 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1651 + " icicle=" + r.icicle
1652 + " with results=" + results + " newIntents=" + newIntents
1653 + " andResume=" + andResume);
1654 if (andResume) {
1655 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1656 System.identityHashCode(r),
1657 r.task.taskId, r.shortComponentName);
1658 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001659 if (r.isHomeActivity) {
1660 mHomeProcess = app;
1661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1663 r.info, r.icicle, results, newIntents, !andResume,
1664 isNextTransitionForward());
1665 // Update usage stats for launched activity
1666 updateUsageStats(r, true);
1667 } catch (RemoteException e) {
1668 if (r.launchFailed) {
1669 // This is the second time we failed -- finish activity
1670 // and give up.
1671 Log.e(TAG, "Second failure launching "
1672 + r.intent.getComponent().flattenToShortString()
1673 + ", giving up", e);
1674 appDiedLocked(app, app.pid, app.thread);
1675 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1676 "2nd-crash");
1677 return false;
1678 }
1679
1680 // This is the first time we failed -- restart process and
1681 // retry.
1682 app.activities.remove(r);
1683 throw e;
1684 }
1685
1686 r.launchFailed = false;
1687 if (updateLRUListLocked(r)) {
1688 Log.w(TAG, "Activity " + r
1689 + " being launched, but already in LRU list");
1690 }
1691
1692 if (andResume) {
1693 // As part of the process of launching, ActivityThread also performs
1694 // a resume.
1695 r.state = ActivityState.RESUMED;
1696 r.icicle = null;
1697 r.haveState = false;
1698 r.stopped = false;
1699 mResumedActivity = r;
1700 r.task.touchActiveTime();
1701 completeResumeLocked(r);
1702 pauseIfSleepingLocked();
1703 } else {
1704 // This activity is not starting in the resumed state... which
1705 // should look like we asked it to pause+stop (but remain visible),
1706 // and it has done so and reported back the current icicle and
1707 // other state.
1708 r.state = ActivityState.STOPPED;
1709 r.stopped = true;
1710 }
1711
1712 return true;
1713 }
1714
1715 private final void startSpecificActivityLocked(HistoryRecord r,
1716 boolean andResume, boolean checkConfig) {
1717 // Is this activity's application already running?
1718 ProcessRecord app = getProcessRecordLocked(r.processName,
1719 r.info.applicationInfo.uid);
1720
1721 if (r.startTime == 0) {
1722 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001723 if (mInitialStartTime == 0) {
1724 mInitialStartTime = r.startTime;
1725 }
1726 } else if (mInitialStartTime == 0) {
1727 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 }
1729
1730 if (app != null && app.thread != null) {
1731 try {
1732 realStartActivityLocked(r, app, andResume, checkConfig);
1733 return;
1734 } catch (RemoteException e) {
1735 Log.w(TAG, "Exception when starting activity "
1736 + r.intent.getComponent().flattenToShortString(), e);
1737 }
1738
1739 // If a dead object exception was thrown -- fall through to
1740 // restart the application.
1741 }
1742
1743 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1744 "activity", r.intent.getComponent());
1745 }
1746
1747 private final ProcessRecord startProcessLocked(String processName,
1748 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1749 String hostingType, ComponentName hostingName) {
1750 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1751 // We don't have to do anything more if:
1752 // (1) There is an existing application record; and
1753 // (2) The caller doesn't think it is dead, OR there is no thread
1754 // object attached to it so we know it couldn't have crashed; and
1755 // (3) There is a pid assigned to it, so it is either starting or
1756 // already running.
1757 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1758 + " app=" + app + " knownToBeDead=" + knownToBeDead
1759 + " thread=" + (app != null ? app.thread : null)
1760 + " pid=" + (app != null ? app.pid : -1));
1761 if (app != null &&
1762 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1763 return app;
1764 }
1765
1766 String hostingNameStr = hostingName != null
1767 ? hostingName.flattenToShortString() : null;
1768
1769 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1770 // If we are in the background, then check to see if this process
1771 // is bad. If so, we will just silently fail.
1772 if (mBadProcesses.get(info.processName, info.uid) != null) {
1773 return null;
1774 }
1775 } else {
1776 // When the user is explicitly starting a process, then clear its
1777 // crash count so that we won't make it bad until they see at
1778 // least one crash dialog again, and make the process good again
1779 // if it had been bad.
1780 mProcessCrashTimes.remove(info.processName, info.uid);
1781 if (mBadProcesses.get(info.processName, info.uid) != null) {
1782 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1783 info.processName);
1784 mBadProcesses.remove(info.processName, info.uid);
1785 if (app != null) {
1786 app.bad = false;
1787 }
1788 }
1789 }
1790
1791 if (app == null) {
1792 app = newProcessRecordLocked(null, info, processName);
1793 mProcessNames.put(processName, info.uid, app);
1794 } else {
1795 // If this is a new package in the process, add the package to the list
1796 app.addPackage(info.packageName);
1797 }
1798
1799 // If the system is not ready yet, then hold off on starting this
1800 // process until it is.
1801 if (!mSystemReady
1802 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1803 if (!mProcessesOnHold.contains(app)) {
1804 mProcessesOnHold.add(app);
1805 }
1806 return app;
1807 }
1808
1809 startProcessLocked(app, hostingType, hostingNameStr);
1810 return (app.pid != 0) ? app : null;
1811 }
1812
1813 private final void startProcessLocked(ProcessRecord app,
1814 String hostingType, String hostingNameStr) {
1815 if (app.pid > 0 && app.pid != MY_PID) {
1816 synchronized (mPidsSelfLocked) {
1817 mPidsSelfLocked.remove(app.pid);
1818 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1819 }
1820 app.pid = 0;
1821 }
1822
1823 mProcessesOnHold.remove(app);
1824
1825 updateCpuStats();
1826
1827 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1828 mProcDeaths[0] = 0;
1829
1830 try {
1831 int uid = app.info.uid;
1832 int[] gids = null;
1833 try {
1834 gids = mContext.getPackageManager().getPackageGids(
1835 app.info.packageName);
1836 } catch (PackageManager.NameNotFoundException e) {
1837 Log.w(TAG, "Unable to retrieve gids", e);
1838 }
1839 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1840 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1841 && mTopComponent != null
1842 && app.processName.equals(mTopComponent.getPackageName())) {
1843 uid = 0;
1844 }
1845 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1846 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1847 uid = 0;
1848 }
1849 }
1850 int debugFlags = 0;
1851 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1852 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1853 }
1854 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1855 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1856 }
1857 if ("1".equals(SystemProperties.get("debug.assert"))) {
1858 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1859 }
1860 int pid = Process.start("android.app.ActivityThread",
1861 mSimpleProcessManagement ? app.processName : null, uid, uid,
1862 gids, debugFlags, null);
1863 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1864 synchronized (bs) {
1865 if (bs.isOnBattery()) {
1866 app.batteryStats.incStartsLocked();
1867 }
1868 }
1869
1870 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1871 app.processName, hostingType,
1872 hostingNameStr != null ? hostingNameStr : "");
1873
1874 if (app.persistent) {
1875 Watchdog.getInstance().processStarted(app, app.processName, pid);
1876 }
1877
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001878 StringBuilder buf = mStringBuilder;
1879 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 buf.append("Start proc ");
1881 buf.append(app.processName);
1882 buf.append(" for ");
1883 buf.append(hostingType);
1884 if (hostingNameStr != null) {
1885 buf.append(" ");
1886 buf.append(hostingNameStr);
1887 }
1888 buf.append(": pid=");
1889 buf.append(pid);
1890 buf.append(" uid=");
1891 buf.append(uid);
1892 buf.append(" gids={");
1893 if (gids != null) {
1894 for (int gi=0; gi<gids.length; gi++) {
1895 if (gi != 0) buf.append(", ");
1896 buf.append(gids[gi]);
1897
1898 }
1899 }
1900 buf.append("}");
1901 Log.i(TAG, buf.toString());
1902 if (pid == 0 || pid == MY_PID) {
1903 // Processes are being emulated with threads.
1904 app.pid = MY_PID;
1905 app.removed = false;
1906 mStartingProcesses.add(app);
1907 } else if (pid > 0) {
1908 app.pid = pid;
1909 app.removed = false;
1910 synchronized (mPidsSelfLocked) {
1911 this.mPidsSelfLocked.put(pid, app);
1912 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1913 msg.obj = app;
1914 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1915 }
1916 } else {
1917 app.pid = 0;
1918 RuntimeException e = new RuntimeException(
1919 "Failure starting process " + app.processName
1920 + ": returned pid=" + pid);
1921 Log.e(TAG, e.getMessage(), e);
1922 }
1923 } catch (RuntimeException e) {
1924 // XXX do better error recovery.
1925 app.pid = 0;
1926 Log.e(TAG, "Failure starting process " + app.processName, e);
1927 }
1928 }
1929
1930 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1931 if (mPausingActivity != null) {
1932 RuntimeException e = new RuntimeException();
1933 Log.e(TAG, "Trying to pause when pause is already pending for "
1934 + mPausingActivity, e);
1935 }
1936 HistoryRecord prev = mResumedActivity;
1937 if (prev == null) {
1938 RuntimeException e = new RuntimeException();
1939 Log.e(TAG, "Trying to pause when nothing is resumed", e);
1940 resumeTopActivityLocked(null);
1941 return;
1942 }
1943 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
1944 mResumedActivity = null;
1945 mPausingActivity = prev;
1946 mLastPausedActivity = prev;
1947 prev.state = ActivityState.PAUSING;
1948 prev.task.touchActiveTime();
1949
1950 updateCpuStats();
1951
1952 if (prev.app != null && prev.app.thread != null) {
1953 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
1954 try {
1955 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
1956 System.identityHashCode(prev),
1957 prev.shortComponentName);
1958 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
1959 prev.configChangeFlags);
1960 updateUsageStats(prev, false);
1961 } catch (Exception e) {
1962 // Ignore exception, if process died other code will cleanup.
1963 Log.w(TAG, "Exception thrown during pause", e);
1964 mPausingActivity = null;
1965 mLastPausedActivity = null;
1966 }
1967 } else {
1968 mPausingActivity = null;
1969 mLastPausedActivity = null;
1970 }
1971
1972 // If we are not going to sleep, we want to ensure the device is
1973 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07001974 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 mLaunchingActivity.acquire();
1976 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
1977 // To be safe, don't allow the wake lock to be held for too long.
1978 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1979 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
1980 }
1981 }
1982
1983
1984 if (mPausingActivity != null) {
1985 // Have the window manager pause its key dispatching until the new
1986 // activity has started. If we're pausing the activity just because
1987 // the screen is being turned off and the UI is sleeping, don't interrupt
1988 // key dispatch; the same activity will pick it up again on wakeup.
1989 if (!uiSleeping) {
1990 prev.pauseKeyDispatchingLocked();
1991 } else {
1992 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
1993 }
1994
1995 // Schedule a pause timeout in case the app doesn't respond.
1996 // We don't give it much time because this directly impacts the
1997 // responsiveness seen by the user.
1998 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
1999 msg.obj = prev;
2000 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2001 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2002 } else {
2003 // This activity failed to schedule the
2004 // pause, so just treat it as being paused now.
2005 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2006 resumeTopActivityLocked(null);
2007 }
2008 }
2009
2010 private final void completePauseLocked() {
2011 HistoryRecord prev = mPausingActivity;
2012 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2013
2014 if (prev != null) {
2015 if (prev.finishing) {
2016 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2017 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2018 } else if (prev.app != null) {
2019 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2020 if (prev.waitingVisible) {
2021 prev.waitingVisible = false;
2022 mWaitingVisibleActivities.remove(prev);
2023 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2024 TAG, "Complete pause, no longer waiting: " + prev);
2025 }
2026 if (prev.configDestroy) {
2027 // The previous is being paused because the configuration
2028 // is changing, which means it is actually stopping...
2029 // To juggle the fact that we are also starting a new
2030 // instance right now, we need to first completely stop
2031 // the current instance before starting the new one.
2032 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2033 destroyActivityLocked(prev, true);
2034 } else {
2035 mStoppingActivities.add(prev);
2036 if (mStoppingActivities.size() > 3) {
2037 // If we already have a few activities waiting to stop,
2038 // then give up on things going idle and start clearing
2039 // them out.
2040 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2041 Message msg = Message.obtain();
2042 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2043 mHandler.sendMessage(msg);
2044 }
2045 }
2046 } else {
2047 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2048 prev = null;
2049 }
2050 mPausingActivity = null;
2051 }
2052
Dianne Hackborn55280a92009-05-07 15:53:46 -07002053 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 resumeTopActivityLocked(prev);
2055 } else {
2056 if (mGoingToSleep.isHeld()) {
2057 mGoingToSleep.release();
2058 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002059 if (mShuttingDown) {
2060 notifyAll();
2061 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062 }
2063
2064 if (prev != null) {
2065 prev.resumeKeyDispatchingLocked();
2066 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002067
2068 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2069 long diff = 0;
2070 synchronized (mProcessStatsThread) {
2071 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2072 }
2073 if (diff > 0) {
2074 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2075 synchronized (bsi) {
2076 BatteryStatsImpl.Uid.Proc ps =
2077 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2078 prev.info.packageName);
2079 if (ps != null) {
2080 ps.addForegroundTimeLocked(diff);
2081 }
2082 }
2083 }
2084 }
2085 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002086 }
2087
2088 /**
2089 * Once we know that we have asked an application to put an activity in
2090 * the resumed state (either by launching it or explicitly telling it),
2091 * this function updates the rest of our state to match that fact.
2092 */
2093 private final void completeResumeLocked(HistoryRecord next) {
2094 next.idle = false;
2095 next.results = null;
2096 next.newIntents = null;
2097
2098 // schedule an idle timeout in case the app doesn't do it for us.
2099 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2100 msg.obj = next;
2101 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2102
2103 if (false) {
2104 // The activity was never told to pause, so just keep
2105 // things going as-is. To maintain our own state,
2106 // we need to emulate it coming back and saying it is
2107 // idle.
2108 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2109 msg.obj = next;
2110 mHandler.sendMessage(msg);
2111 }
2112
2113 next.thumbnail = null;
2114 setFocusedActivityLocked(next);
2115 next.resumeKeyDispatchingLocked();
2116 ensureActivitiesVisibleLocked(null, 0);
2117 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002118
2119 // Mark the point when the activity is resuming
2120 // TODO: To be more accurate, the mark should be before the onCreate,
2121 // not after the onResume. But for subsequent starts, onResume is fine.
2122 if (next.app != null) {
2123 synchronized (mProcessStatsThread) {
2124 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2125 }
2126 } else {
2127 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2128 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 }
2130
2131 /**
2132 * Make sure that all activities that need to be visible (that is, they
2133 * currently can be seen by the user) actually are.
2134 */
2135 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2136 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2137 if (DEBUG_VISBILITY) Log.v(
2138 TAG, "ensureActivitiesVisible behind " + top
2139 + " configChanges=0x" + Integer.toHexString(configChanges));
2140
2141 // If the top activity is not fullscreen, then we need to
2142 // make sure any activities under it are now visible.
2143 final int count = mHistory.size();
2144 int i = count-1;
2145 while (mHistory.get(i) != top) {
2146 i--;
2147 }
2148 HistoryRecord r;
2149 boolean behindFullscreen = false;
2150 for (; i>=0; i--) {
2151 r = (HistoryRecord)mHistory.get(i);
2152 if (DEBUG_VISBILITY) Log.v(
2153 TAG, "Make visible? " + r + " finishing=" + r.finishing
2154 + " state=" + r.state);
2155 if (r.finishing) {
2156 continue;
2157 }
2158
2159 final boolean doThisProcess = onlyThisProcess == null
2160 || onlyThisProcess.equals(r.processName);
2161
2162 // First: if this is not the current activity being started, make
2163 // sure it matches the current configuration.
2164 if (r != starting && doThisProcess) {
2165 ensureActivityConfigurationLocked(r, 0);
2166 }
2167
2168 if (r.app == null || r.app.thread == null) {
2169 if (onlyThisProcess == null
2170 || onlyThisProcess.equals(r.processName)) {
2171 // This activity needs to be visible, but isn't even
2172 // running... get it started, but don't resume it
2173 // at this point.
2174 if (DEBUG_VISBILITY) Log.v(
2175 TAG, "Start and freeze screen for " + r);
2176 if (r != starting) {
2177 r.startFreezingScreenLocked(r.app, configChanges);
2178 }
2179 if (!r.visible) {
2180 if (DEBUG_VISBILITY) Log.v(
2181 TAG, "Starting and making visible: " + r);
2182 mWindowManager.setAppVisibility(r, true);
2183 }
2184 if (r != starting) {
2185 startSpecificActivityLocked(r, false, false);
2186 }
2187 }
2188
2189 } else if (r.visible) {
2190 // If this activity is already visible, then there is nothing
2191 // else to do here.
2192 if (DEBUG_VISBILITY) Log.v(
2193 TAG, "Skipping: already visible at " + r);
2194 r.stopFreezingScreenLocked(false);
2195
2196 } else if (onlyThisProcess == null) {
2197 // This activity is not currently visible, but is running.
2198 // Tell it to become visible.
2199 r.visible = true;
2200 if (r.state != ActivityState.RESUMED && r != starting) {
2201 // If this activity is paused, tell it
2202 // to now show its window.
2203 if (DEBUG_VISBILITY) Log.v(
2204 TAG, "Making visible and scheduling visibility: " + r);
2205 try {
2206 mWindowManager.setAppVisibility(r, true);
2207 r.app.thread.scheduleWindowVisibility(r, true);
2208 r.stopFreezingScreenLocked(false);
2209 } catch (Exception e) {
2210 // Just skip on any failure; we'll make it
2211 // visible when it next restarts.
2212 Log.w(TAG, "Exception thrown making visibile: "
2213 + r.intent.getComponent(), e);
2214 }
2215 }
2216 }
2217
2218 // Aggregate current change flags.
2219 configChanges |= r.configChangeFlags;
2220
2221 if (r.fullscreen) {
2222 // At this point, nothing else needs to be shown
2223 if (DEBUG_VISBILITY) Log.v(
2224 TAG, "Stopping: fullscreen at " + r);
2225 behindFullscreen = true;
2226 i--;
2227 break;
2228 }
2229 }
2230
2231 // Now for any activities that aren't visible to the user, make
2232 // sure they no longer are keeping the screen frozen.
2233 while (i >= 0) {
2234 r = (HistoryRecord)mHistory.get(i);
2235 if (DEBUG_VISBILITY) Log.v(
2236 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2237 + " state=" + r.state
2238 + " behindFullscreen=" + behindFullscreen);
2239 if (!r.finishing) {
2240 if (behindFullscreen) {
2241 if (r.visible) {
2242 if (DEBUG_VISBILITY) Log.v(
2243 TAG, "Making invisible: " + r);
2244 r.visible = false;
2245 try {
2246 mWindowManager.setAppVisibility(r, false);
2247 if ((r.state == ActivityState.STOPPING
2248 || r.state == ActivityState.STOPPED)
2249 && r.app != null && r.app.thread != null) {
2250 if (DEBUG_VISBILITY) Log.v(
2251 TAG, "Scheduling invisibility: " + r);
2252 r.app.thread.scheduleWindowVisibility(r, false);
2253 }
2254 } catch (Exception e) {
2255 // Just skip on any failure; we'll make it
2256 // visible when it next restarts.
2257 Log.w(TAG, "Exception thrown making hidden: "
2258 + r.intent.getComponent(), e);
2259 }
2260 } else {
2261 if (DEBUG_VISBILITY) Log.v(
2262 TAG, "Already invisible: " + r);
2263 }
2264 } else if (r.fullscreen) {
2265 if (DEBUG_VISBILITY) Log.v(
2266 TAG, "Now behindFullscreen: " + r);
2267 behindFullscreen = true;
2268 }
2269 }
2270 i--;
2271 }
2272 }
2273
2274 /**
2275 * Version of ensureActivitiesVisible that can easily be called anywhere.
2276 */
2277 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2278 int configChanges) {
2279 HistoryRecord r = topRunningActivityLocked(null);
2280 if (r != null) {
2281 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2282 }
2283 }
2284
2285 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2286 if (resumed) {
2287 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2288 } else {
2289 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2290 }
2291 }
2292
2293 /**
2294 * Ensure that the top activity in the stack is resumed.
2295 *
2296 * @param prev The previously resumed activity, for when in the process
2297 * of pausing; can be null to call from elsewhere.
2298 *
2299 * @return Returns true if something is being resumed, or false if
2300 * nothing happened.
2301 */
2302 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2303 // Find the first activity that is not finishing.
2304 HistoryRecord next = topRunningActivityLocked(null);
2305
2306 // Remember how we'll process this pause/resume situation, and ensure
2307 // that the state is reset however we wind up proceeding.
2308 final boolean userLeaving = mUserLeaving;
2309 mUserLeaving = false;
2310
2311 if (next == null) {
2312 // There are no more activities! Let's just start up the
2313 // Launcher...
2314 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2315 && mTopAction == null) {
2316 // We are running in factory test mode, but unable to find
2317 // the factory test app, so just sit around displaying the
2318 // error message and don't try to start anything.
2319 return false;
2320 }
2321 Intent intent = new Intent(
2322 mTopAction,
2323 mTopData != null ? Uri.parse(mTopData) : null);
2324 intent.setComponent(mTopComponent);
2325 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2326 intent.addCategory(Intent.CATEGORY_HOME);
2327 }
2328 ActivityInfo aInfo =
2329 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002330 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 if (aInfo != null) {
2332 intent.setComponent(new ComponentName(
2333 aInfo.applicationInfo.packageName, aInfo.name));
2334 // Don't do this if the home app is currently being
2335 // instrumented.
2336 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2337 aInfo.applicationInfo.uid);
2338 if (app == null || app.instrumentationClass == null) {
2339 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2340 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002341 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002342 }
2343 }
2344 return true;
2345 }
2346
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002347 next.delayedResume = false;
2348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002349 // If the top activity is the resumed one, nothing to do.
2350 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2351 // Make sure we have executed any pending transitions, since there
2352 // should be nothing left to do at this point.
2353 mWindowManager.executeAppTransition();
2354 return false;
2355 }
2356
2357 // If we are sleeping, and there is no resumed activity, and the top
2358 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002359 if ((mSleeping || mShuttingDown)
2360 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002361 // Make sure we have executed any pending transitions, since there
2362 // should be nothing left to do at this point.
2363 mWindowManager.executeAppTransition();
2364 return false;
2365 }
2366
2367 // The activity may be waiting for stop, but that is no longer
2368 // appropriate for it.
2369 mStoppingActivities.remove(next);
2370 mWaitingVisibleActivities.remove(next);
2371
2372 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2373
2374 // If we are currently pausing an activity, then don't do anything
2375 // until that is done.
2376 if (mPausingActivity != null) {
2377 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2378 return false;
2379 }
2380
2381 // We need to start pausing the current activity so the top one
2382 // can be resumed...
2383 if (mResumedActivity != null) {
2384 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2385 startPausingLocked(userLeaving, false);
2386 return true;
2387 }
2388
2389 if (prev != null && prev != next) {
2390 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2391 prev.waitingVisible = true;
2392 mWaitingVisibleActivities.add(prev);
2393 if (DEBUG_SWITCH) Log.v(
2394 TAG, "Resuming top, waiting visible to hide: " + prev);
2395 } else {
2396 // The next activity is already visible, so hide the previous
2397 // activity's windows right now so we can show the new one ASAP.
2398 // We only do this if the previous is finishing, which should mean
2399 // it is on top of the one being resumed so hiding it quickly
2400 // is good. Otherwise, we want to do the normal route of allowing
2401 // the resumed activity to be shown so we can decide if the
2402 // previous should actually be hidden depending on whether the
2403 // new one is found to be full-screen or not.
2404 if (prev.finishing) {
2405 mWindowManager.setAppVisibility(prev, false);
2406 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2407 + prev + ", waitingVisible="
2408 + (prev != null ? prev.waitingVisible : null)
2409 + ", nowVisible=" + next.nowVisible);
2410 } else {
2411 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2412 + prev + ", waitingVisible="
2413 + (prev != null ? prev.waitingVisible : null)
2414 + ", nowVisible=" + next.nowVisible);
2415 }
2416 }
2417 }
2418
2419 // We are starting up the next activity, so tell the window manager
2420 // that the previous one will be hidden soon. This way it can know
2421 // to ignore it when computing the desired screen orientation.
2422 if (prev != null) {
2423 if (prev.finishing) {
2424 if (DEBUG_TRANSITION) Log.v(TAG,
2425 "Prepare close transition: prev=" + prev);
2426 mWindowManager.prepareAppTransition(prev.task == next.task
2427 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2428 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2429 mWindowManager.setAppWillBeHidden(prev);
2430 mWindowManager.setAppVisibility(prev, false);
2431 } else {
2432 if (DEBUG_TRANSITION) Log.v(TAG,
2433 "Prepare open transition: prev=" + prev);
2434 mWindowManager.prepareAppTransition(prev.task == next.task
2435 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2436 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2437 }
2438 if (false) {
2439 mWindowManager.setAppWillBeHidden(prev);
2440 mWindowManager.setAppVisibility(prev, false);
2441 }
2442 } else if (mHistory.size() > 1) {
2443 if (DEBUG_TRANSITION) Log.v(TAG,
2444 "Prepare open transition: no previous");
2445 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2446 }
2447
2448 if (next.app != null && next.app.thread != null) {
2449 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2450
2451 // This activity is now becoming visible.
2452 mWindowManager.setAppVisibility(next, true);
2453
2454 HistoryRecord lastResumedActivity = mResumedActivity;
2455 ActivityState lastState = next.state;
2456
2457 updateCpuStats();
2458
2459 next.state = ActivityState.RESUMED;
2460 mResumedActivity = next;
2461 next.task.touchActiveTime();
2462 updateLRUListLocked(next.app, true);
2463 updateLRUListLocked(next);
2464
2465 // Have the window manager re-evaluate the orientation of
2466 // the screen based on the new activity order.
2467 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002468 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002469 next.mayFreezeScreenLocked(next.app) ? next : null);
2470 if (config != null) {
2471 next.frozenBeforeDestroy = true;
2472 }
2473 if (!updateConfigurationLocked(config, next)) {
2474 // The configuration update wasn't able to keep the existing
2475 // instance of the activity, and instead started a new one.
2476 // We should be all done, but let's just make sure our activity
2477 // is still at the top and schedule another run if something
2478 // weird happened.
2479 HistoryRecord nextNext = topRunningActivityLocked(null);
2480 if (DEBUG_SWITCH) Log.i(TAG,
2481 "Activity config changed during resume: " + next
2482 + ", new next: " + nextNext);
2483 if (nextNext != next) {
2484 // Do over!
2485 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2486 }
2487 mWindowManager.executeAppTransition();
2488 return true;
2489 }
2490
2491 try {
2492 // Deliver all pending results.
2493 ArrayList a = next.results;
2494 if (a != null) {
2495 final int N = a.size();
2496 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002497 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498 TAG, "Delivering results to " + next
2499 + ": " + a);
2500 next.app.thread.scheduleSendResult(next, a);
2501 }
2502 }
2503
2504 if (next.newIntents != null) {
2505 next.app.thread.scheduleNewIntent(next.newIntents, next);
2506 }
2507
2508 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2509 System.identityHashCode(next),
2510 next.task.taskId, next.shortComponentName);
2511 updateUsageStats(next, true);
2512
2513 next.app.thread.scheduleResumeActivity(next,
2514 isNextTransitionForward());
2515 pauseIfSleepingLocked();
2516
2517 } catch (Exception e) {
2518 // Whoops, need to restart this activity!
2519 next.state = lastState;
2520 mResumedActivity = lastResumedActivity;
2521 if (Config.LOGD) Log.d(TAG,
2522 "Restarting because process died: " + next);
2523 if (!next.hasBeenLaunched) {
2524 next.hasBeenLaunched = true;
2525 } else {
2526 if (SHOW_APP_STARTING_ICON) {
2527 mWindowManager.setAppStartingWindow(
2528 next, next.packageName, next.theme,
2529 next.nonLocalizedLabel,
2530 next.labelRes, next.icon, null, true);
2531 }
2532 }
2533 startSpecificActivityLocked(next, true, false);
2534 return true;
2535 }
2536
2537 // From this point on, if something goes wrong there is no way
2538 // to recover the activity.
2539 try {
2540 next.visible = true;
2541 completeResumeLocked(next);
2542 } catch (Exception e) {
2543 // If any exception gets thrown, toss away this
2544 // activity and try the next one.
2545 Log.w(TAG, "Exception thrown during resume of " + next, e);
2546 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2547 "resume-exception");
2548 return true;
2549 }
2550
2551 // Didn't need to use the icicle, and it is now out of date.
2552 next.icicle = null;
2553 next.haveState = false;
2554 next.stopped = false;
2555
2556 } else {
2557 // Whoops, need to restart this activity!
2558 if (!next.hasBeenLaunched) {
2559 next.hasBeenLaunched = true;
2560 } else {
2561 if (SHOW_APP_STARTING_ICON) {
2562 mWindowManager.setAppStartingWindow(
2563 next, next.packageName, next.theme,
2564 next.nonLocalizedLabel,
2565 next.labelRes, next.icon, null, true);
2566 }
2567 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2568 }
2569 startSpecificActivityLocked(next, true, true);
2570 }
2571
2572 return true;
2573 }
2574
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002575 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2576 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002577 final int NH = mHistory.size();
2578
2579 int addPos = -1;
2580
2581 if (!newTask) {
2582 // If starting in an existing task, find where that is...
2583 HistoryRecord next = null;
2584 boolean startIt = true;
2585 for (int i = NH-1; i >= 0; i--) {
2586 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2587 if (p.finishing) {
2588 continue;
2589 }
2590 if (p.task == r.task) {
2591 // Here it is! Now, if this is not yet visible to the
2592 // user, then just add it without starting; it will
2593 // get started when the user navigates back to it.
2594 addPos = i+1;
2595 if (!startIt) {
2596 mHistory.add(addPos, r);
2597 r.inHistory = true;
2598 r.task.numActivities++;
2599 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2600 r.info.screenOrientation, r.fullscreen);
2601 if (VALIDATE_TOKENS) {
2602 mWindowManager.validateAppTokens(mHistory);
2603 }
2604 return;
2605 }
2606 break;
2607 }
2608 if (p.fullscreen) {
2609 startIt = false;
2610 }
2611 next = p;
2612 }
2613 }
2614
2615 // Place a new activity at top of stack, so it is next to interact
2616 // with the user.
2617 if (addPos < 0) {
2618 addPos = mHistory.size();
2619 }
2620
2621 // If we are not placing the new activity frontmost, we do not want
2622 // to deliver the onUserLeaving callback to the actual frontmost
2623 // activity
2624 if (addPos < NH) {
2625 mUserLeaving = false;
2626 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2627 }
2628
2629 // Slot the activity into the history stack and proceed
2630 mHistory.add(addPos, r);
2631 r.inHistory = true;
2632 r.frontOfTask = newTask;
2633 r.task.numActivities++;
2634 if (NH > 0) {
2635 // We want to show the starting preview window if we are
2636 // switching to a new task, or the next activity's process is
2637 // not currently running.
2638 boolean showStartingIcon = newTask;
2639 ProcessRecord proc = r.app;
2640 if (proc == null) {
2641 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2642 }
2643 if (proc == null || proc.thread == null) {
2644 showStartingIcon = true;
2645 }
2646 if (DEBUG_TRANSITION) Log.v(TAG,
2647 "Prepare open transition: starting " + r);
2648 mWindowManager.prepareAppTransition(newTask
2649 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2650 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2651 mWindowManager.addAppToken(
2652 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2653 boolean doShow = true;
2654 if (newTask) {
2655 // Even though this activity is starting fresh, we still need
2656 // to reset it to make sure we apply affinities to move any
2657 // existing activities from other tasks in to it.
2658 // If the caller has requested that the target task be
2659 // reset, then do so.
2660 if ((r.intent.getFlags()
2661 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2662 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002663 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002664 }
2665 }
2666 if (SHOW_APP_STARTING_ICON && doShow) {
2667 // Figure out if we are transitioning from another activity that is
2668 // "has the same starting icon" as the next one. This allows the
2669 // window manager to keep the previous window it had previously
2670 // created, if it still had one.
2671 HistoryRecord prev = mResumedActivity;
2672 if (prev != null) {
2673 // We don't want to reuse the previous starting preview if:
2674 // (1) The current activity is in a different task.
2675 if (prev.task != r.task) prev = null;
2676 // (2) The current activity is already displayed.
2677 else if (prev.nowVisible) prev = null;
2678 }
2679 mWindowManager.setAppStartingWindow(
2680 r, r.packageName, r.theme, r.nonLocalizedLabel,
2681 r.labelRes, r.icon, prev, showStartingIcon);
2682 }
2683 } else {
2684 // If this is the first activity, don't do any fancy animations,
2685 // because there is nothing for it to animate on top of.
2686 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2687 r.info.screenOrientation, r.fullscreen);
2688 }
2689 if (VALIDATE_TOKENS) {
2690 mWindowManager.validateAppTokens(mHistory);
2691 }
2692
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002693 if (doResume) {
2694 resumeTopActivityLocked(null);
2695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002696 }
2697
2698 /**
2699 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002700 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2701 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 * an instance of that activity in the stack and, if found, finish all
2703 * activities on top of it and return the instance.
2704 *
2705 * @param newR Description of the new activity being started.
2706 * @return Returns the old activity that should be continue to be used,
2707 * or null if none was found.
2708 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002709 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 HistoryRecord newR, boolean doClear) {
2711 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002712
2713 // First find the requested task.
2714 while (i > 0) {
2715 i--;
2716 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2717 if (r.task.taskId == taskId) {
2718 i++;
2719 break;
2720 }
2721 }
2722
2723 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 while (i > 0) {
2725 i--;
2726 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2727 if (r.finishing) {
2728 continue;
2729 }
2730 if (r.task.taskId != taskId) {
2731 return null;
2732 }
2733 if (r.realActivity.equals(newR.realActivity)) {
2734 // Here it is! Now finish everything in front...
2735 HistoryRecord ret = r;
2736 if (doClear) {
2737 while (i < (mHistory.size()-1)) {
2738 i++;
2739 r = (HistoryRecord)mHistory.get(i);
2740 if (r.finishing) {
2741 continue;
2742 }
2743 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2744 null, "clear")) {
2745 i--;
2746 }
2747 }
2748 }
2749
2750 // Finally, if this is a normal launch mode (that is, not
2751 // expecting onNewIntent()), then we will finish the current
2752 // instance of the activity so a new fresh one can be started.
2753 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2754 if (!ret.finishing) {
2755 int index = indexOfTokenLocked(ret, false);
2756 if (index >= 0) {
2757 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2758 null, "clear");
2759 }
2760 return null;
2761 }
2762 }
2763
2764 return ret;
2765 }
2766 }
2767
2768 return null;
2769 }
2770
2771 /**
2772 * Find the activity in the history stack within the given task. Returns
2773 * the index within the history at which it's found, or < 0 if not found.
2774 */
2775 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2776 int i = mHistory.size();
2777 while (i > 0) {
2778 i--;
2779 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2780 if (candidate.task.taskId != task) {
2781 break;
2782 }
2783 if (candidate.realActivity.equals(r.realActivity)) {
2784 return i;
2785 }
2786 }
2787
2788 return -1;
2789 }
2790
2791 /**
2792 * Reorder the history stack so that the activity at the given index is
2793 * brought to the front.
2794 */
2795 private final HistoryRecord moveActivityToFrontLocked(int where) {
2796 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2797 int top = mHistory.size();
2798 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2799 mHistory.add(top, newTop);
2800 oldTop.frontOfTask = false;
2801 newTop.frontOfTask = true;
2802 return newTop;
2803 }
2804
2805 /**
2806 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2807 * method will be called at the proper time.
2808 */
2809 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2810 boolean sent = false;
2811 if (r.state == ActivityState.RESUMED
2812 && r.app != null && r.app.thread != null) {
2813 try {
2814 ArrayList<Intent> ar = new ArrayList<Intent>();
2815 ar.add(new Intent(intent));
2816 r.app.thread.scheduleNewIntent(ar, r);
2817 sent = true;
2818 } catch (Exception e) {
2819 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2820 }
2821 }
2822 if (!sent) {
2823 r.addNewIntentLocked(new Intent(intent));
2824 }
2825 }
2826
2827 private final void logStartActivity(int tag, HistoryRecord r,
2828 TaskRecord task) {
2829 EventLog.writeEvent(tag,
2830 System.identityHashCode(r), task.taskId,
2831 r.shortComponentName, r.intent.getAction(),
2832 r.intent.getType(), r.intent.getDataString(),
2833 r.intent.getFlags());
2834 }
2835
2836 private final int startActivityLocked(IApplicationThread caller,
2837 Intent intent, String resolvedType,
2838 Uri[] grantedUriPermissions,
2839 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2840 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002841 int callingPid, int callingUid, boolean onlyIfNeeded,
2842 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 Log.i(TAG, "Starting activity: " + intent);
2844
2845 HistoryRecord sourceRecord = null;
2846 HistoryRecord resultRecord = null;
2847 if (resultTo != null) {
2848 int index = indexOfTokenLocked(resultTo, false);
The Android Open Source Project10592532009-03-18 17:39:46 -07002849 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2851 if (index >= 0) {
2852 sourceRecord = (HistoryRecord)mHistory.get(index);
2853 if (requestCode >= 0 && !sourceRecord.finishing) {
2854 resultRecord = sourceRecord;
2855 }
2856 }
2857 }
2858
2859 int launchFlags = intent.getFlags();
2860
2861 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2862 && sourceRecord != null) {
2863 // Transfer the result target from the source activity to the new
2864 // one being started, including any failures.
2865 if (requestCode >= 0) {
2866 return START_FORWARD_AND_REQUEST_CONFLICT;
2867 }
2868 resultRecord = sourceRecord.resultTo;
2869 resultWho = sourceRecord.resultWho;
2870 requestCode = sourceRecord.requestCode;
2871 sourceRecord.resultTo = null;
2872 if (resultRecord != null) {
2873 resultRecord.removeResultsLocked(
2874 sourceRecord, resultWho, requestCode);
2875 }
2876 }
2877
2878 int err = START_SUCCESS;
2879
2880 if (intent.getComponent() == null) {
2881 // We couldn't find a class that can handle the given Intent.
2882 // That's the end of that!
2883 err = START_INTENT_NOT_RESOLVED;
2884 }
2885
2886 if (err == START_SUCCESS && aInfo == null) {
2887 // We couldn't find the specific class specified in the Intent.
2888 // Also the end of the line.
2889 err = START_CLASS_NOT_FOUND;
2890 }
2891
2892 ProcessRecord callerApp = null;
2893 if (err == START_SUCCESS && caller != null) {
2894 callerApp = getRecordForAppLocked(caller);
2895 if (callerApp != null) {
2896 callingPid = callerApp.pid;
2897 callingUid = callerApp.info.uid;
2898 } else {
2899 Log.w(TAG, "Unable to find app for caller " + caller
2900 + " (pid=" + callingPid + ") when starting: "
2901 + intent.toString());
2902 err = START_PERMISSION_DENIED;
2903 }
2904 }
2905
2906 if (err != START_SUCCESS) {
2907 if (resultRecord != null) {
2908 sendActivityResultLocked(-1,
2909 resultRecord, resultWho, requestCode,
2910 Activity.RESULT_CANCELED, null);
2911 }
2912 return err;
2913 }
2914
2915 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2916 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2917 if (perm != PackageManager.PERMISSION_GRANTED) {
2918 if (resultRecord != null) {
2919 sendActivityResultLocked(-1,
2920 resultRecord, resultWho, requestCode,
2921 Activity.RESULT_CANCELED, null);
2922 }
2923 String msg = "Permission Denial: starting " + intent.toString()
2924 + " from " + callerApp + " (pid=" + callingPid
2925 + ", uid=" + callingUid + ")"
2926 + " requires " + aInfo.permission;
2927 Log.w(TAG, msg);
2928 throw new SecurityException(msg);
2929 }
2930
2931 if (mWatcher != null) {
2932 boolean abort = false;
2933 try {
2934 // The Intent we give to the watcher has the extra data
2935 // stripped off, since it can contain private information.
2936 Intent watchIntent = intent.cloneFilter();
2937 abort = !mWatcher.activityStarting(watchIntent,
2938 aInfo.applicationInfo.packageName);
2939 } catch (RemoteException e) {
2940 mWatcher = null;
2941 }
2942
2943 if (abort) {
2944 if (resultRecord != null) {
2945 sendActivityResultLocked(-1,
2946 resultRecord, resultWho, requestCode,
2947 Activity.RESULT_CANCELED, null);
2948 }
2949 // We pretend to the caller that it was really started, but
2950 // they will just get a cancel result.
2951 return START_SUCCESS;
2952 }
2953 }
2954
2955 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
2956 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002957 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002958
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002959 if (mResumedActivity == null
2960 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2961 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2962 PendingActivityLaunch pal = new PendingActivityLaunch();
2963 pal.r = r;
2964 pal.sourceRecord = sourceRecord;
2965 pal.grantedUriPermissions = grantedUriPermissions;
2966 pal.grantedMode = grantedMode;
2967 pal.onlyIfNeeded = onlyIfNeeded;
2968 mPendingActivityLaunches.add(pal);
2969 return START_SWITCHES_CANCELED;
2970 }
2971 }
2972
2973 if (mDidAppSwitch) {
2974 // This is the second allowed switch since we stopped switches,
2975 // so now just generally allow switches. Use case: user presses
2976 // home (switches disabled, switch to home, mDidAppSwitch now true);
2977 // user taps a home icon (coming from home so allowed, we hit here
2978 // and now allow anyone to switch again).
2979 mAppSwitchesAllowedTime = 0;
2980 } else {
2981 mDidAppSwitch = true;
2982 }
2983
2984 doPendingActivityLaunchesLocked(false);
2985
2986 return startActivityUncheckedLocked(r, sourceRecord,
2987 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
2988 }
2989
2990 private final void doPendingActivityLaunchesLocked(boolean doResume) {
2991 final int N = mPendingActivityLaunches.size();
2992 if (N <= 0) {
2993 return;
2994 }
2995 for (int i=0; i<N; i++) {
2996 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
2997 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
2998 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
2999 doResume && i == (N-1));
3000 }
3001 mPendingActivityLaunches.clear();
3002 }
3003
3004 private final int startActivityUncheckedLocked(HistoryRecord r,
3005 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3006 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3007 final Intent intent = r.intent;
3008 final int callingUid = r.launchedFromUid;
3009
3010 int launchFlags = intent.getFlags();
3011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003012 // We'll invoke onUserLeaving before onPause only if the launching
3013 // activity did not explicitly state that this is an automated launch.
3014 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3015 if (DEBUG_USER_LEAVING) Log.v(TAG,
3016 "startActivity() => mUserLeaving=" + mUserLeaving);
3017
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003018 // If the caller has asked not to resume at this point, we make note
3019 // of this in the record so that we can skip it when trying to find
3020 // the top running activity.
3021 if (!doResume) {
3022 r.delayedResume = true;
3023 }
3024
3025 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3026 != 0 ? r : null;
3027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003028 // If the onlyIfNeeded flag is set, then we can do this if the activity
3029 // being launched is the same as the one making the call... or, as
3030 // a special case, if we do not know the caller then we count the
3031 // current top activity as the caller.
3032 if (onlyIfNeeded) {
3033 HistoryRecord checkedCaller = sourceRecord;
3034 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003035 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 }
3037 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3038 // Caller is not the same as launcher, so always needed.
3039 onlyIfNeeded = false;
3040 }
3041 }
3042
3043 if (grantedUriPermissions != null && callingUid > 0) {
3044 for (int i=0; i<grantedUriPermissions.length; i++) {
3045 grantUriPermissionLocked(callingUid, r.packageName,
3046 grantedUriPermissions[i], grantedMode, r);
3047 }
3048 }
3049
3050 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3051 intent, r);
3052
3053 if (sourceRecord == null) {
3054 // This activity is not being started from another... in this
3055 // case we -always- start a new task.
3056 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3057 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3058 + intent);
3059 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3060 }
3061 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3062 // The original activity who is starting us is running as a single
3063 // instance... this new activity it is starting must go on its
3064 // own task.
3065 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3066 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3067 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3068 // The activity being started is a single instance... it always
3069 // gets launched into its own task.
3070 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3071 }
3072
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003073 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 // For whatever reason this activity is being launched into a new
3075 // task... yet the caller has requested a result back. Well, that
3076 // is pretty messed up, so instead immediately send back a cancel
3077 // and let the new task continue launched as normal without a
3078 // dependency on its originator.
3079 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3080 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003081 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003082 Activity.RESULT_CANCELED, null);
3083 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003084 }
3085
3086 boolean addingToTask = false;
3087 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3088 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3089 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3090 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3091 // If bring to front is requested, and no result is requested, and
3092 // we can find a task that was started with this same
3093 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003094 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 // See if there is a task to bring to the front. If this is
3096 // a SINGLE_INSTANCE activity, there can be one and only one
3097 // instance of it in the history, and it is always in its own
3098 // unique task, so we do a special search.
3099 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3100 ? findTaskLocked(intent, r.info)
3101 : findActivityLocked(intent, r.info);
3102 if (taskTop != null) {
3103 if (taskTop.task.intent == null) {
3104 // This task was started because of movement of
3105 // the activity based on affinity... now that we
3106 // are actually launching it, we can assign the
3107 // base intent.
3108 taskTop.task.setIntent(intent, r.info);
3109 }
3110 // If the target task is not in the front, then we need
3111 // to bring it to the front... except... well, with
3112 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3113 // to have the same behavior as if a new instance was
3114 // being started, which means not bringing it to the front
3115 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003116 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 if (curTop.task != taskTop.task) {
3118 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3119 boolean callerAtFront = sourceRecord == null
3120 || curTop.task == sourceRecord.task;
3121 if (callerAtFront) {
3122 // We really do want to push this one into the
3123 // user's face, right now.
3124 moveTaskToFrontLocked(taskTop.task);
3125 }
3126 }
3127 // If the caller has requested that the target task be
3128 // reset, then do so.
3129 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3130 taskTop = resetTaskIfNeededLocked(taskTop, r);
3131 }
3132 if (onlyIfNeeded) {
3133 // We don't need to start a new activity, and
3134 // the client said not to do anything if that
3135 // is the case, so this is it! And for paranoia, make
3136 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003137 if (doResume) {
3138 resumeTopActivityLocked(null);
3139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003140 return START_RETURN_INTENT_TO_CALLER;
3141 }
3142 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3143 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3144 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3145 // In this situation we want to remove all activities
3146 // from the task up to the one being started. In most
3147 // cases this means we are resetting the task to its
3148 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003149 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 taskTop.task.taskId, r, true);
3151 if (top != null) {
3152 if (top.frontOfTask) {
3153 // Activity aliases may mean we use different
3154 // intents for the top activity, so make sure
3155 // the task now has the identity of the new
3156 // intent.
3157 top.task.setIntent(r.intent, r.info);
3158 }
3159 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3160 deliverNewIntentLocked(top, r.intent);
3161 } else {
3162 // A special case: we need to
3163 // start the activity because it is not currently
3164 // running, and the caller has asked to clear the
3165 // current task to have this activity at the top.
3166 addingToTask = true;
3167 // Now pretend like this activity is being started
3168 // by the top of its task, so it is put in the
3169 // right place.
3170 sourceRecord = taskTop;
3171 }
3172 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3173 // In this case the top activity on the task is the
3174 // same as the one being launched, so we take that
3175 // as a request to bring the task to the foreground.
3176 // If the top activity in the task is the root
3177 // activity, deliver this new intent to it if it
3178 // desires.
3179 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3180 && taskTop.realActivity.equals(r.realActivity)) {
3181 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3182 if (taskTop.frontOfTask) {
3183 taskTop.task.setIntent(r.intent, r.info);
3184 }
3185 deliverNewIntentLocked(taskTop, r.intent);
3186 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3187 // In this case we are launching the root activity
3188 // of the task, but with a different intent. We
3189 // should start a new instance on top.
3190 addingToTask = true;
3191 sourceRecord = taskTop;
3192 }
3193 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3194 // In this case an activity is being launched in to an
3195 // existing task, without resetting that task. This
3196 // is typically the situation of launching an activity
3197 // from a notification or shortcut. We want to place
3198 // the new activity on top of the current task.
3199 addingToTask = true;
3200 sourceRecord = taskTop;
3201 } else if (!taskTop.task.rootWasReset) {
3202 // In this case we are launching in to an existing task
3203 // that has not yet been started from its front door.
3204 // The current task has been brought to the front.
3205 // Ideally, we'd probably like to place this new task
3206 // at the bottom of its stack, but that's a little hard
3207 // to do with the current organization of the code so
3208 // for now we'll just drop it.
3209 taskTop.task.setIntent(r.intent, r.info);
3210 }
3211 if (!addingToTask) {
3212 // We didn't do anything... but it was needed (a.k.a., client
3213 // don't use that intent!) And for paranoia, make
3214 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003215 if (doResume) {
3216 resumeTopActivityLocked(null);
3217 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003218 return START_TASK_TO_FRONT;
3219 }
3220 }
3221 }
3222 }
3223
3224 //String uri = r.intent.toURI();
3225 //Intent intent2 = new Intent(uri);
3226 //Log.i(TAG, "Given intent: " + r.intent);
3227 //Log.i(TAG, "URI is: " + uri);
3228 //Log.i(TAG, "To intent: " + intent2);
3229
3230 if (r.packageName != null) {
3231 // If the activity being launched is the same as the one currently
3232 // at the top, then we need to check if it should only be launched
3233 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003234 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3235 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236 if (top.realActivity.equals(r.realActivity)) {
3237 if (top.app != null && top.app.thread != null) {
3238 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3239 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3240 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3241 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3242 // For paranoia, make sure we have correctly
3243 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003244 if (doResume) {
3245 resumeTopActivityLocked(null);
3246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247 if (onlyIfNeeded) {
3248 // We don't need to start a new activity, and
3249 // the client said not to do anything if that
3250 // is the case, so this is it!
3251 return START_RETURN_INTENT_TO_CALLER;
3252 }
3253 deliverNewIntentLocked(top, r.intent);
3254 return START_DELIVERED_TO_TOP;
3255 }
3256 }
3257 }
3258 }
3259
3260 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003261 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003263 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 Activity.RESULT_CANCELED, null);
3265 }
3266 return START_CLASS_NOT_FOUND;
3267 }
3268
3269 boolean newTask = false;
3270
3271 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003272 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003273 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3274 // todo: should do better management of integers.
3275 mCurTask++;
3276 if (mCurTask <= 0) {
3277 mCurTask = 1;
3278 }
3279 r.task = new TaskRecord(mCurTask, r.info, intent,
3280 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3281 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3282 + " in new task " + r.task);
3283 newTask = true;
3284 addRecentTask(r.task);
3285
3286 } else if (sourceRecord != null) {
3287 if (!addingToTask &&
3288 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3289 // In this case, we are adding the activity to an existing
3290 // task, but the caller has asked to clear that task if the
3291 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003292 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 sourceRecord.task.taskId, r, true);
3294 if (top != null) {
3295 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3296 deliverNewIntentLocked(top, r.intent);
3297 // For paranoia, make sure we have correctly
3298 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003299 if (doResume) {
3300 resumeTopActivityLocked(null);
3301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003302 return START_DELIVERED_TO_TOP;
3303 }
3304 } else if (!addingToTask &&
3305 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3306 // In this case, we are launching an activity in our own task
3307 // that may already be running somewhere in the history, and
3308 // we want to shuffle it to the front of the stack if so.
3309 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3310 if (where >= 0) {
3311 HistoryRecord top = moveActivityToFrontLocked(where);
3312 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3313 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003314 if (doResume) {
3315 resumeTopActivityLocked(null);
3316 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003317 return START_DELIVERED_TO_TOP;
3318 }
3319 }
3320 // An existing activity is starting this new activity, so we want
3321 // to keep the new one in the same task as the one that is starting
3322 // it.
3323 r.task = sourceRecord.task;
3324 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3325 + " in existing task " + r.task);
3326
3327 } else {
3328 // This not being started from an existing activity, and not part
3329 // of a new task... just put it in the top task, though these days
3330 // this case should never happen.
3331 final int N = mHistory.size();
3332 HistoryRecord prev =
3333 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3334 r.task = prev != null
3335 ? prev.task
3336 : new TaskRecord(mCurTask, r.info, intent,
3337 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3338 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3339 + " in new guessed " + r.task);
3340 }
3341 if (newTask) {
3342 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3343 }
3344 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003345 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 return START_SUCCESS;
3347 }
3348
3349 public final int startActivity(IApplicationThread caller,
3350 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3351 int grantedMode, IBinder resultTo,
3352 String resultWho, int requestCode, boolean onlyIfNeeded,
3353 boolean debug) {
3354 // Refuse possible leaked file descriptors
3355 if (intent != null && intent.hasFileDescriptors()) {
3356 throw new IllegalArgumentException("File descriptors passed in Intent");
3357 }
3358
The Android Open Source Project4df24232009-03-05 14:34:35 -08003359 final boolean componentSpecified = intent.getComponent() != null;
3360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 // Don't modify the client's object!
3362 intent = new Intent(intent);
3363
3364 // Collect information about the target of the Intent.
3365 // Must do this before locking, because resolving the intent
3366 // may require launching a process to run its content provider.
3367 ActivityInfo aInfo;
3368 try {
3369 ResolveInfo rInfo =
3370 ActivityThread.getPackageManager().resolveIntent(
3371 intent, resolvedType,
3372 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003373 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 aInfo = rInfo != null ? rInfo.activityInfo : null;
3375 } catch (RemoteException e) {
3376 aInfo = null;
3377 }
3378
3379 if (aInfo != null) {
3380 // Store the found target back into the intent, because now that
3381 // we have it we never want to do this again. For example, if the
3382 // user navigates back to this point in the history, we should
3383 // always restart the exact same activity.
3384 intent.setComponent(new ComponentName(
3385 aInfo.applicationInfo.packageName, aInfo.name));
3386
3387 // Don't debug things in the system process
3388 if (debug) {
3389 if (!aInfo.processName.equals("system")) {
3390 setDebugApp(aInfo.processName, true, false);
3391 }
3392 }
3393 }
3394
3395 synchronized(this) {
3396 final long origId = Binder.clearCallingIdentity();
3397 int res = startActivityLocked(caller, intent, resolvedType,
3398 grantedUriPermissions, grantedMode, aInfo,
3399 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003400 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003401 Binder.restoreCallingIdentity(origId);
3402 return res;
3403 }
3404 }
3405
3406 public boolean startNextMatchingActivity(IBinder callingActivity,
3407 Intent intent) {
3408 // Refuse possible leaked file descriptors
3409 if (intent != null && intent.hasFileDescriptors() == true) {
3410 throw new IllegalArgumentException("File descriptors passed in Intent");
3411 }
3412
3413 synchronized (this) {
3414 int index = indexOfTokenLocked(callingActivity, false);
3415 if (index < 0) {
3416 return false;
3417 }
3418 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3419 if (r.app == null || r.app.thread == null) {
3420 // The caller is not running... d'oh!
3421 return false;
3422 }
3423 intent = new Intent(intent);
3424 // The caller is not allowed to change the data.
3425 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3426 // And we are resetting to find the next component...
3427 intent.setComponent(null);
3428
3429 ActivityInfo aInfo = null;
3430 try {
3431 List<ResolveInfo> resolves =
3432 ActivityThread.getPackageManager().queryIntentActivities(
3433 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003434 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435
3436 // Look for the original activity in the list...
3437 final int N = resolves != null ? resolves.size() : 0;
3438 for (int i=0; i<N; i++) {
3439 ResolveInfo rInfo = resolves.get(i);
3440 if (rInfo.activityInfo.packageName.equals(r.packageName)
3441 && rInfo.activityInfo.name.equals(r.info.name)) {
3442 // We found the current one... the next matching is
3443 // after it.
3444 i++;
3445 if (i<N) {
3446 aInfo = resolves.get(i).activityInfo;
3447 }
3448 break;
3449 }
3450 }
3451 } catch (RemoteException e) {
3452 }
3453
3454 if (aInfo == null) {
3455 // Nobody who is next!
3456 return false;
3457 }
3458
3459 intent.setComponent(new ComponentName(
3460 aInfo.applicationInfo.packageName, aInfo.name));
3461 intent.setFlags(intent.getFlags()&~(
3462 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3463 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3464 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3465 Intent.FLAG_ACTIVITY_NEW_TASK));
3466
3467 // Okay now we need to start the new activity, replacing the
3468 // currently running activity. This is a little tricky because
3469 // we want to start the new one as if the current one is finished,
3470 // but not finish the current one first so that there is no flicker.
3471 // And thus...
3472 final boolean wasFinishing = r.finishing;
3473 r.finishing = true;
3474
3475 // Propagate reply information over to the new activity.
3476 final HistoryRecord resultTo = r.resultTo;
3477 final String resultWho = r.resultWho;
3478 final int requestCode = r.requestCode;
3479 r.resultTo = null;
3480 if (resultTo != null) {
3481 resultTo.removeResultsLocked(r, resultWho, requestCode);
3482 }
3483
3484 final long origId = Binder.clearCallingIdentity();
3485 // XXX we are not dealing with propagating grantedUriPermissions...
3486 // those are not yet exposed to user code, so there is no need.
3487 int res = startActivityLocked(r.app.thread, intent,
3488 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003489 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 Binder.restoreCallingIdentity(origId);
3491
3492 r.finishing = wasFinishing;
3493 if (res != START_SUCCESS) {
3494 return false;
3495 }
3496 return true;
3497 }
3498 }
3499
3500 final int startActivityInPackage(int uid,
3501 Intent intent, String resolvedType, IBinder resultTo,
3502 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003503 final boolean componentSpecified = intent.getComponent() != null;
3504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505 // Don't modify the client's object!
3506 intent = new Intent(intent);
3507
3508 // Collect information about the target of the Intent.
3509 // Must do this before locking, because resolving the intent
3510 // may require launching a process to run its content provider.
3511 ActivityInfo aInfo;
3512 try {
3513 ResolveInfo rInfo =
3514 ActivityThread.getPackageManager().resolveIntent(
3515 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003516 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003517 aInfo = rInfo != null ? rInfo.activityInfo : null;
3518 } catch (RemoteException e) {
3519 aInfo = null;
3520 }
3521
3522 if (aInfo != null) {
3523 // Store the found target back into the intent, because now that
3524 // we have it we never want to do this again. For example, if the
3525 // user navigates back to this point in the history, we should
3526 // always restart the exact same activity.
3527 intent.setComponent(new ComponentName(
3528 aInfo.applicationInfo.packageName, aInfo.name));
3529 }
3530
3531 synchronized(this) {
3532 return startActivityLocked(null, intent, resolvedType,
3533 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003534 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 }
3536 }
3537
3538 private final void addRecentTask(TaskRecord task) {
3539 // Remove any existing entries that are the same kind of task.
3540 int N = mRecentTasks.size();
3541 for (int i=0; i<N; i++) {
3542 TaskRecord tr = mRecentTasks.get(i);
3543 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3544 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3545 mRecentTasks.remove(i);
3546 i--;
3547 N--;
3548 if (task.intent == null) {
3549 // If the new recent task we are adding is not fully
3550 // specified, then replace it with the existing recent task.
3551 task = tr;
3552 }
3553 }
3554 }
3555 if (N >= MAX_RECENT_TASKS) {
3556 mRecentTasks.remove(N-1);
3557 }
3558 mRecentTasks.add(0, task);
3559 }
3560
3561 public void setRequestedOrientation(IBinder token,
3562 int requestedOrientation) {
3563 synchronized (this) {
3564 int index = indexOfTokenLocked(token, false);
3565 if (index < 0) {
3566 return;
3567 }
3568 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3569 final long origId = Binder.clearCallingIdentity();
3570 mWindowManager.setAppOrientation(r, requestedOrientation);
3571 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003572 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 r.mayFreezeScreenLocked(r.app) ? r : null);
3574 if (config != null) {
3575 r.frozenBeforeDestroy = true;
3576 if (!updateConfigurationLocked(config, r)) {
3577 resumeTopActivityLocked(null);
3578 }
3579 }
3580 Binder.restoreCallingIdentity(origId);
3581 }
3582 }
3583
3584 public int getRequestedOrientation(IBinder token) {
3585 synchronized (this) {
3586 int index = indexOfTokenLocked(token, false);
3587 if (index < 0) {
3588 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3589 }
3590 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3591 return mWindowManager.getAppOrientation(r);
3592 }
3593 }
3594
3595 private final void stopActivityLocked(HistoryRecord r) {
3596 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3597 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3598 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3599 if (!r.finishing) {
3600 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3601 "no-history");
3602 }
3603 } else if (r.app != null && r.app.thread != null) {
3604 if (mFocusedActivity == r) {
3605 setFocusedActivityLocked(topRunningActivityLocked(null));
3606 }
3607 r.resumeKeyDispatchingLocked();
3608 try {
3609 r.stopped = false;
3610 r.state = ActivityState.STOPPING;
3611 if (DEBUG_VISBILITY) Log.v(
3612 TAG, "Stopping visible=" + r.visible + " for " + r);
3613 if (!r.visible) {
3614 mWindowManager.setAppVisibility(r, false);
3615 }
3616 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3617 } catch (Exception e) {
3618 // Maybe just ignore exceptions here... if the process
3619 // has crashed, our death notification will clean things
3620 // up.
3621 Log.w(TAG, "Exception thrown during pause", e);
3622 // Just in case, assume it to be stopped.
3623 r.stopped = true;
3624 r.state = ActivityState.STOPPED;
3625 if (r.configDestroy) {
3626 destroyActivityLocked(r, true);
3627 }
3628 }
3629 }
3630 }
3631
3632 /**
3633 * @return Returns true if the activity is being finished, false if for
3634 * some reason it is being left as-is.
3635 */
3636 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3637 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003638 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 TAG, "Finishing activity: token=" + token
3640 + ", result=" + resultCode + ", data=" + resultData);
3641
3642 int index = indexOfTokenLocked(token, false);
3643 if (index < 0) {
3644 return false;
3645 }
3646 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3647
3648 // Is this the last activity left?
3649 boolean lastActivity = true;
3650 for (int i=mHistory.size()-1; i>=0; i--) {
3651 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3652 if (!p.finishing && p != r) {
3653 lastActivity = false;
3654 break;
3655 }
3656 }
3657
3658 // If this is the last activity, but it is the home activity, then
3659 // just don't finish it.
3660 if (lastActivity) {
3661 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3662 return false;
3663 }
3664 }
3665
3666 finishActivityLocked(r, index, resultCode, resultData, reason);
3667 return true;
3668 }
3669
3670 /**
3671 * @return Returns true if this activity has been removed from the history
3672 * list, or false if it is still in the list and will be removed later.
3673 */
3674 private final boolean finishActivityLocked(HistoryRecord r, int index,
3675 int resultCode, Intent resultData, String reason) {
3676 if (r.finishing) {
3677 Log.w(TAG, "Duplicate finish request for " + r);
3678 return false;
3679 }
3680
3681 r.finishing = true;
3682 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3683 System.identityHashCode(r),
3684 r.task.taskId, r.shortComponentName, reason);
3685 r.task.numActivities--;
3686 if (r.frontOfTask && index < (mHistory.size()-1)) {
3687 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3688 if (next.task == r.task) {
3689 next.frontOfTask = true;
3690 }
3691 }
3692
3693 r.pauseKeyDispatchingLocked();
3694 if (mFocusedActivity == r) {
3695 setFocusedActivityLocked(topRunningActivityLocked(null));
3696 }
3697
3698 // send the result
3699 HistoryRecord resultTo = r.resultTo;
3700 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003701 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3702 + " who=" + r.resultWho + " req=" + r.requestCode
3703 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003704 if (r.info.applicationInfo.uid > 0) {
3705 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3706 r.packageName, resultData, r);
3707 }
3708 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3709 resultData);
3710 r.resultTo = null;
3711 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003712 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713
3714 // Make sure this HistoryRecord is not holding on to other resources,
3715 // because clients have remote IPC references to this object so we
3716 // can't assume that will go away and want to avoid circular IPC refs.
3717 r.results = null;
3718 r.pendingResults = null;
3719 r.newIntents = null;
3720 r.icicle = null;
3721
3722 if (mPendingThumbnails.size() > 0) {
3723 // There are clients waiting to receive thumbnails so, in case
3724 // this is an activity that someone is waiting for, add it
3725 // to the pending list so we can correctly update the clients.
3726 mCancelledThumbnails.add(r);
3727 }
3728
3729 if (mResumedActivity == r) {
3730 boolean endTask = index <= 0
3731 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3732 if (DEBUG_TRANSITION) Log.v(TAG,
3733 "Prepare close transition: finishing " + r);
3734 mWindowManager.prepareAppTransition(endTask
3735 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3736 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3737
3738 // Tell window manager to prepare for this one to be removed.
3739 mWindowManager.setAppVisibility(r, false);
3740
3741 if (mPausingActivity == null) {
3742 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3743 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3744 startPausingLocked(false, false);
3745 }
3746
3747 } else if (r.state != ActivityState.PAUSING) {
3748 // If the activity is PAUSING, we will complete the finish once
3749 // it is done pausing; else we can just directly finish it here.
3750 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3751 return finishCurrentActivityLocked(r, index,
3752 FINISH_AFTER_PAUSE) == null;
3753 } else {
3754 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3755 }
3756
3757 return false;
3758 }
3759
3760 private static final int FINISH_IMMEDIATELY = 0;
3761 private static final int FINISH_AFTER_PAUSE = 1;
3762 private static final int FINISH_AFTER_VISIBLE = 2;
3763
3764 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3765 int mode) {
3766 final int index = indexOfTokenLocked(r, false);
3767 if (index < 0) {
3768 return null;
3769 }
3770
3771 return finishCurrentActivityLocked(r, index, mode);
3772 }
3773
3774 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3775 int index, int mode) {
3776 // First things first: if this activity is currently visible,
3777 // and the resumed activity is not yet visible, then hold off on
3778 // finishing until the resumed one becomes visible.
3779 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3780 if (!mStoppingActivities.contains(r)) {
3781 mStoppingActivities.add(r);
3782 if (mStoppingActivities.size() > 3) {
3783 // If we already have a few activities waiting to stop,
3784 // then give up on things going idle and start clearing
3785 // them out.
3786 Message msg = Message.obtain();
3787 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3788 mHandler.sendMessage(msg);
3789 }
3790 }
3791 r.state = ActivityState.STOPPING;
3792 updateOomAdjLocked();
3793 return r;
3794 }
3795
3796 // make sure the record is cleaned out of other places.
3797 mStoppingActivities.remove(r);
3798 mWaitingVisibleActivities.remove(r);
3799 if (mResumedActivity == r) {
3800 mResumedActivity = null;
3801 }
3802 final ActivityState prevState = r.state;
3803 r.state = ActivityState.FINISHING;
3804
3805 if (mode == FINISH_IMMEDIATELY
3806 || prevState == ActivityState.STOPPED
3807 || prevState == ActivityState.INITIALIZING) {
3808 // If this activity is already stopped, we can just finish
3809 // it right now.
3810 return destroyActivityLocked(r, true) ? null : r;
3811 } else {
3812 // Need to go through the full pause cycle to get this
3813 // activity into the stopped state and then finish it.
3814 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3815 mFinishingActivities.add(r);
3816 resumeTopActivityLocked(null);
3817 }
3818 return r;
3819 }
3820
3821 /**
3822 * This is the internal entry point for handling Activity.finish().
3823 *
3824 * @param token The Binder token referencing the Activity we want to finish.
3825 * @param resultCode Result code, if any, from this Activity.
3826 * @param resultData Result data (Intent), if any, from this Activity.
3827 *
3828 * @result Returns true if the activity successfully finished, or false if it is still running.
3829 */
3830 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3831 // Refuse possible leaked file descriptors
3832 if (resultData != null && resultData.hasFileDescriptors() == true) {
3833 throw new IllegalArgumentException("File descriptors passed in Intent");
3834 }
3835
3836 synchronized(this) {
3837 if (mWatcher != null) {
3838 // Find the first activity that is not finishing.
3839 HistoryRecord next = topRunningActivityLocked(token, 0);
3840 if (next != null) {
3841 // ask watcher if this is allowed
3842 boolean resumeOK = true;
3843 try {
3844 resumeOK = mWatcher.activityResuming(next.packageName);
3845 } catch (RemoteException e) {
3846 mWatcher = null;
3847 }
3848
3849 if (!resumeOK) {
3850 return false;
3851 }
3852 }
3853 }
3854 final long origId = Binder.clearCallingIdentity();
3855 boolean res = requestFinishActivityLocked(token, resultCode,
3856 resultData, "app-request");
3857 Binder.restoreCallingIdentity(origId);
3858 return res;
3859 }
3860 }
3861
3862 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3863 String resultWho, int requestCode, int resultCode, Intent data) {
3864
3865 if (callingUid > 0) {
3866 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3867 data, r);
3868 }
3869
The Android Open Source Project10592532009-03-18 17:39:46 -07003870 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3871 + " : who=" + resultWho + " req=" + requestCode
3872 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003873 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3874 try {
3875 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3876 list.add(new ResultInfo(resultWho, requestCode,
3877 resultCode, data));
3878 r.app.thread.scheduleSendResult(r, list);
3879 return;
3880 } catch (Exception e) {
3881 Log.w(TAG, "Exception thrown sending result to " + r, e);
3882 }
3883 }
3884
3885 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3886 }
3887
3888 public final void finishSubActivity(IBinder token, String resultWho,
3889 int requestCode) {
3890 synchronized(this) {
3891 int index = indexOfTokenLocked(token, false);
3892 if (index < 0) {
3893 return;
3894 }
3895 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3896
3897 final long origId = Binder.clearCallingIdentity();
3898
3899 int i;
3900 for (i=mHistory.size()-1; i>=0; i--) {
3901 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3902 if (r.resultTo == self && r.requestCode == requestCode) {
3903 if ((r.resultWho == null && resultWho == null) ||
3904 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3905 finishActivityLocked(r, i,
3906 Activity.RESULT_CANCELED, null, "request-sub");
3907 }
3908 }
3909 }
3910
3911 Binder.restoreCallingIdentity(origId);
3912 }
3913 }
3914
3915 /**
3916 * Perform clean-up of service connections in an activity record.
3917 */
3918 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3919 // Throw away any services that have been bound by this activity.
3920 if (r.connections != null) {
3921 Iterator<ConnectionRecord> it = r.connections.iterator();
3922 while (it.hasNext()) {
3923 ConnectionRecord c = it.next();
3924 removeConnectionLocked(c, null, r);
3925 }
3926 r.connections = null;
3927 }
3928 }
3929
3930 /**
3931 * Perform the common clean-up of an activity record. This is called both
3932 * as part of destroyActivityLocked() (when destroying the client-side
3933 * representation) and cleaning things up as a result of its hosting
3934 * processing going away, in which case there is no remaining client-side
3935 * state to destroy so only the cleanup here is needed.
3936 */
3937 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
3938 if (mResumedActivity == r) {
3939 mResumedActivity = null;
3940 }
3941 if (mFocusedActivity == r) {
3942 mFocusedActivity = null;
3943 }
3944
3945 r.configDestroy = false;
3946 r.frozenBeforeDestroy = false;
3947
3948 // Make sure this record is no longer in the pending finishes list.
3949 // This could happen, for example, if we are trimming activities
3950 // down to the max limit while they are still waiting to finish.
3951 mFinishingActivities.remove(r);
3952 mWaitingVisibleActivities.remove(r);
3953
3954 // Remove any pending results.
3955 if (r.finishing && r.pendingResults != null) {
3956 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3957 PendingIntentRecord rec = apr.get();
3958 if (rec != null) {
3959 cancelIntentSenderLocked(rec, false);
3960 }
3961 }
3962 r.pendingResults = null;
3963 }
3964
3965 if (cleanServices) {
3966 cleanUpActivityServicesLocked(r);
3967 }
3968
3969 if (mPendingThumbnails.size() > 0) {
3970 // There are clients waiting to receive thumbnails so, in case
3971 // this is an activity that someone is waiting for, add it
3972 // to the pending list so we can correctly update the clients.
3973 mCancelledThumbnails.add(r);
3974 }
3975
3976 // Get rid of any pending idle timeouts.
3977 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3978 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3979 }
3980
3981 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
3982 if (r.state != ActivityState.DESTROYED) {
3983 mHistory.remove(r);
3984 r.inHistory = false;
3985 r.state = ActivityState.DESTROYED;
3986 mWindowManager.removeAppToken(r);
3987 if (VALIDATE_TOKENS) {
3988 mWindowManager.validateAppTokens(mHistory);
3989 }
3990 cleanUpActivityServicesLocked(r);
3991 removeActivityUriPermissionsLocked(r);
3992 }
3993 }
3994
3995 /**
3996 * Destroy the current CLIENT SIDE instance of an activity. This may be
3997 * called both when actually finishing an activity, or when performing
3998 * a configuration switch where we destroy the current client-side object
3999 * but then create a new client-side object for this same HistoryRecord.
4000 */
4001 private final boolean destroyActivityLocked(HistoryRecord r,
4002 boolean removeFromApp) {
4003 if (DEBUG_SWITCH) Log.v(
4004 TAG, "Removing activity: token=" + r
4005 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4006 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4007 System.identityHashCode(r),
4008 r.task.taskId, r.shortComponentName);
4009
4010 boolean removedFromHistory = false;
4011
4012 cleanUpActivityLocked(r, false);
4013
4014 if (r.app != null) {
4015 if (removeFromApp) {
4016 int idx = r.app.activities.indexOf(r);
4017 if (idx >= 0) {
4018 r.app.activities.remove(idx);
4019 }
4020 if (r.persistent) {
4021 decPersistentCountLocked(r.app);
4022 }
4023 }
4024
4025 boolean skipDestroy = false;
4026
4027 try {
4028 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4029 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4030 r.configChangeFlags);
4031 } catch (Exception e) {
4032 // We can just ignore exceptions here... if the process
4033 // has crashed, our death notification will clean things
4034 // up.
4035 //Log.w(TAG, "Exception thrown during finish", e);
4036 if (r.finishing) {
4037 removeActivityFromHistoryLocked(r);
4038 removedFromHistory = true;
4039 skipDestroy = true;
4040 }
4041 }
4042
4043 r.app = null;
4044 r.nowVisible = false;
4045
4046 if (r.finishing && !skipDestroy) {
4047 r.state = ActivityState.DESTROYING;
4048 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4049 msg.obj = r;
4050 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4051 } else {
4052 r.state = ActivityState.DESTROYED;
4053 }
4054 } else {
4055 // remove this record from the history.
4056 if (r.finishing) {
4057 removeActivityFromHistoryLocked(r);
4058 removedFromHistory = true;
4059 } else {
4060 r.state = ActivityState.DESTROYED;
4061 }
4062 }
4063
4064 r.configChangeFlags = 0;
4065
4066 if (!mLRUActivities.remove(r)) {
4067 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4068 }
4069
4070 return removedFromHistory;
4071 }
4072
4073 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4074 ProcessRecord app)
4075 {
4076 int i = list.size();
4077 if (localLOGV) Log.v(
4078 TAG, "Removing app " + app + " from list " + list
4079 + " with " + i + " entries");
4080 while (i > 0) {
4081 i--;
4082 HistoryRecord r = (HistoryRecord)list.get(i);
4083 if (localLOGV) Log.v(
4084 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4085 if (r.app == app) {
4086 if (localLOGV) Log.v(TAG, "Removing this entry!");
4087 list.remove(i);
4088 }
4089 }
4090 }
4091
4092 /**
4093 * Main function for removing an existing process from the activity manager
4094 * as a result of that process going away. Clears out all connections
4095 * to the process.
4096 */
4097 private final void handleAppDiedLocked(ProcessRecord app,
4098 boolean restarting) {
4099 cleanUpApplicationRecordLocked(app, restarting, -1);
4100 if (!restarting) {
4101 mLRUProcesses.remove(app);
4102 }
4103
4104 // Just in case...
4105 if (mPausingActivity != null && mPausingActivity.app == app) {
4106 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4107 mPausingActivity = null;
4108 }
4109 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4110 mLastPausedActivity = null;
4111 }
4112
4113 // Remove this application's activities from active lists.
4114 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4115 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4116 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4117 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4118
4119 boolean atTop = true;
4120 boolean hasVisibleActivities = false;
4121
4122 // Clean out the history list.
4123 int i = mHistory.size();
4124 if (localLOGV) Log.v(
4125 TAG, "Removing app " + app + " from history with " + i + " entries");
4126 while (i > 0) {
4127 i--;
4128 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4129 if (localLOGV) Log.v(
4130 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4131 if (r.app == app) {
4132 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4133 if (localLOGV) Log.v(
4134 TAG, "Removing this entry! frozen=" + r.haveState
4135 + " finishing=" + r.finishing);
4136 mHistory.remove(i);
4137
4138 r.inHistory = false;
4139 mWindowManager.removeAppToken(r);
4140 if (VALIDATE_TOKENS) {
4141 mWindowManager.validateAppTokens(mHistory);
4142 }
4143 removeActivityUriPermissionsLocked(r);
4144
4145 } else {
4146 // We have the current state for this activity, so
4147 // it can be restarted later when needed.
4148 if (localLOGV) Log.v(
4149 TAG, "Keeping entry, setting app to null");
4150 if (r.visible) {
4151 hasVisibleActivities = true;
4152 }
4153 r.app = null;
4154 r.nowVisible = false;
4155 if (!r.haveState) {
4156 r.icicle = null;
4157 }
4158 }
4159
4160 cleanUpActivityLocked(r, true);
4161 r.state = ActivityState.STOPPED;
4162 }
4163 atTop = false;
4164 }
4165
4166 app.activities.clear();
4167
4168 if (app.instrumentationClass != null) {
4169 Log.w(TAG, "Crash of app " + app.processName
4170 + " running instrumentation " + app.instrumentationClass);
4171 Bundle info = new Bundle();
4172 info.putString("shortMsg", "Process crashed.");
4173 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4174 }
4175
4176 if (!restarting) {
4177 if (!resumeTopActivityLocked(null)) {
4178 // If there was nothing to resume, and we are not already
4179 // restarting this process, but there is a visible activity that
4180 // is hosted by the process... then make sure all visible
4181 // activities are running, taking care of restarting this
4182 // process.
4183 if (hasVisibleActivities) {
4184 ensureActivitiesVisibleLocked(null, 0);
4185 }
4186 }
4187 }
4188 }
4189
4190 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4191 IBinder threadBinder = thread.asBinder();
4192
4193 // Find the application record.
4194 int count = mLRUProcesses.size();
4195 int i;
4196 for (i=0; i<count; i++) {
4197 ProcessRecord rec = mLRUProcesses.get(i);
4198 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4199 return i;
4200 }
4201 }
4202 return -1;
4203 }
4204
4205 private final ProcessRecord getRecordForAppLocked(
4206 IApplicationThread thread) {
4207 if (thread == null) {
4208 return null;
4209 }
4210
4211 int appIndex = getLRURecordIndexForAppLocked(thread);
4212 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4213 }
4214
4215 private final void appDiedLocked(ProcessRecord app, int pid,
4216 IApplicationThread thread) {
4217
4218 mProcDeaths[0]++;
4219
4220 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4221 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4222 + ") has died.");
4223 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4224 if (localLOGV) Log.v(
4225 TAG, "Dying app: " + app + ", pid: " + pid
4226 + ", thread: " + thread.asBinder());
4227 boolean doLowMem = app.instrumentationClass == null;
4228 handleAppDiedLocked(app, false);
4229
4230 if (doLowMem) {
4231 // If there are no longer any background processes running,
4232 // and the app that died was not running instrumentation,
4233 // then tell everyone we are now low on memory.
4234 boolean haveBg = false;
4235 int count = mLRUProcesses.size();
4236 int i;
4237 for (i=0; i<count; i++) {
4238 ProcessRecord rec = mLRUProcesses.get(i);
4239 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4240 haveBg = true;
4241 break;
4242 }
4243 }
4244
4245 if (!haveBg) {
4246 Log.i(TAG, "Low Memory: No more background processes.");
4247 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4248 for (i=0; i<count; i++) {
4249 ProcessRecord rec = mLRUProcesses.get(i);
4250 if (rec.thread != null) {
4251 rec.lastRequestedGc = SystemClock.uptimeMillis();
4252 try {
4253 rec.thread.scheduleLowMemory();
4254 } catch (RemoteException e) {
4255 // Don't care if the process is gone.
4256 }
4257 }
4258 }
4259 }
4260 }
4261 } else if (Config.LOGD) {
4262 Log.d(TAG, "Received spurious death notification for thread "
4263 + thread.asBinder());
4264 }
4265 }
4266
4267 final String readFile(String filename) {
4268 try {
4269 FileInputStream fs = new FileInputStream(filename);
4270 byte[] inp = new byte[8192];
4271 int size = fs.read(inp);
4272 fs.close();
4273 return new String(inp, 0, 0, size);
4274 } catch (java.io.IOException e) {
4275 }
4276 return "";
4277 }
4278
4279 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4280 final String annotation) {
4281 if (app.notResponding || app.crashing) {
4282 return;
4283 }
4284
4285 // Log the ANR to the event log.
4286 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4287
4288 // If we are on a secure build and the application is not interesting to the user (it is
4289 // not visible or in the background), just kill it instead of displaying a dialog.
4290 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4291 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4292 Process.killProcess(app.pid);
4293 return;
4294 }
4295
4296 // DeviceMonitor.start();
4297
4298 String processInfo = null;
4299 if (MONITOR_CPU_USAGE) {
4300 updateCpuStatsNow();
4301 synchronized (mProcessStatsThread) {
4302 processInfo = mProcessStats.printCurrentState();
4303 }
4304 }
4305
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004306 StringBuilder info = mStringBuilder;
4307 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004308 info.append("ANR (application not responding) in process: ");
4309 info.append(app.processName);
4310 if (annotation != null) {
4311 info.append("\nAnnotation: ");
4312 info.append(annotation);
4313 }
4314 if (MONITOR_CPU_USAGE) {
4315 info.append("\nCPU usage:\n");
4316 info.append(processInfo);
4317 }
4318 Log.i(TAG, info.toString());
4319
4320 // The application is not responding. Dump as many thread traces as we can.
4321 boolean fileDump = prepareTraceFile(true);
4322 if (!fileDump) {
4323 // Dumping traces to the log, just dump the process that isn't responding so
4324 // we don't overflow the log
4325 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4326 } else {
4327 // Dumping traces to a file so dump all active processes we know about
4328 synchronized (this) {
4329 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4330 ProcessRecord r = mLRUProcesses.get(i);
4331 if (r.thread != null) {
4332 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4333 }
4334 }
4335 }
4336 }
4337
4338 if (mWatcher != null) {
4339 try {
4340 int res = mWatcher.appNotResponding(app.processName,
4341 app.pid, info.toString());
4342 if (res != 0) {
4343 if (res < 0) {
4344 // wait until the SIGQUIT has had a chance to process before killing the
4345 // process.
4346 try {
4347 wait(2000);
4348 } catch (InterruptedException e) {
4349 }
4350
4351 Process.killProcess(app.pid);
4352 return;
4353 }
4354 }
4355 } catch (RemoteException e) {
4356 mWatcher = null;
4357 }
4358 }
4359
4360 makeAppNotRespondingLocked(app,
4361 activity != null ? activity.shortComponentName : null,
4362 annotation != null ? "ANR " + annotation : "ANR",
4363 info.toString(), null);
4364 Message msg = Message.obtain();
4365 HashMap map = new HashMap();
4366 msg.what = SHOW_NOT_RESPONDING_MSG;
4367 msg.obj = map;
4368 map.put("app", app);
4369 if (activity != null) {
4370 map.put("activity", activity);
4371 }
4372
4373 mHandler.sendMessage(msg);
4374 return;
4375 }
4376
4377 /**
4378 * If a stack trace file has been configured, prepare the filesystem
4379 * by creating the directory if it doesn't exist and optionally
4380 * removing the old trace file.
4381 *
4382 * @param removeExisting If set, the existing trace file will be removed.
4383 * @return Returns true if the trace file preparations succeeded
4384 */
4385 public static boolean prepareTraceFile(boolean removeExisting) {
4386 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4387 boolean fileReady = false;
4388 if (!TextUtils.isEmpty(tracesPath)) {
4389 File f = new File(tracesPath);
4390 if (!f.exists()) {
4391 // Ensure the enclosing directory exists
4392 File dir = f.getParentFile();
4393 if (!dir.exists()) {
4394 fileReady = dir.mkdirs();
4395 FileUtils.setPermissions(dir.getAbsolutePath(),
4396 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4397 } else if (dir.isDirectory()) {
4398 fileReady = true;
4399 }
4400 } else if (removeExisting) {
4401 // Remove the previous traces file, so we don't fill the disk.
4402 // The VM will recreate it
4403 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4404 fileReady = f.delete();
4405 }
4406 }
4407
4408 return fileReady;
4409 }
4410
4411
4412 private final void decPersistentCountLocked(ProcessRecord app)
4413 {
4414 app.persistentActivities--;
4415 if (app.persistentActivities > 0) {
4416 // Still more of 'em...
4417 return;
4418 }
4419 if (app.persistent) {
4420 // Ah, but the application itself is persistent. Whatever!
4421 return;
4422 }
4423
4424 // App is no longer persistent... make sure it and the ones
4425 // following it in the LRU list have the correc oom_adj.
4426 updateOomAdjLocked();
4427 }
4428
4429 public void setPersistent(IBinder token, boolean isPersistent) {
4430 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4431 != PackageManager.PERMISSION_GRANTED) {
4432 String msg = "Permission Denial: setPersistent() from pid="
4433 + Binder.getCallingPid()
4434 + ", uid=" + Binder.getCallingUid()
4435 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4436 Log.w(TAG, msg);
4437 throw new SecurityException(msg);
4438 }
4439
4440 synchronized(this) {
4441 int index = indexOfTokenLocked(token, true);
4442 if (index < 0) {
4443 return;
4444 }
4445 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4446 ProcessRecord app = r.app;
4447
4448 if (localLOGV) Log.v(
4449 TAG, "Setting persistence " + isPersistent + ": " + r);
4450
4451 if (isPersistent) {
4452 if (r.persistent) {
4453 // Okay okay, I heard you already!
4454 if (localLOGV) Log.v(TAG, "Already persistent!");
4455 return;
4456 }
4457 r.persistent = true;
4458 app.persistentActivities++;
4459 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4460 if (app.persistentActivities > 1) {
4461 // We aren't the first...
4462 if (localLOGV) Log.v(TAG, "Not the first!");
4463 return;
4464 }
4465 if (app.persistent) {
4466 // This would be redundant.
4467 if (localLOGV) Log.v(TAG, "App is persistent!");
4468 return;
4469 }
4470
4471 // App is now persistent... make sure it and the ones
4472 // following it now have the correct oom_adj.
4473 final long origId = Binder.clearCallingIdentity();
4474 updateOomAdjLocked();
4475 Binder.restoreCallingIdentity(origId);
4476
4477 } else {
4478 if (!r.persistent) {
4479 // Okay okay, I heard you already!
4480 return;
4481 }
4482 r.persistent = false;
4483 final long origId = Binder.clearCallingIdentity();
4484 decPersistentCountLocked(app);
4485 Binder.restoreCallingIdentity(origId);
4486
4487 }
4488 }
4489 }
4490
4491 public boolean clearApplicationUserData(final String packageName,
4492 final IPackageDataObserver observer) {
4493 int uid = Binder.getCallingUid();
4494 int pid = Binder.getCallingPid();
4495 long callingId = Binder.clearCallingIdentity();
4496 try {
4497 IPackageManager pm = ActivityThread.getPackageManager();
4498 int pkgUid = -1;
4499 synchronized(this) {
4500 try {
4501 pkgUid = pm.getPackageUid(packageName);
4502 } catch (RemoteException e) {
4503 }
4504 if (pkgUid == -1) {
4505 Log.w(TAG, "Invalid packageName:" + packageName);
4506 return false;
4507 }
4508 if (uid == pkgUid || checkComponentPermission(
4509 android.Manifest.permission.CLEAR_APP_USER_DATA,
4510 pid, uid, -1)
4511 == PackageManager.PERMISSION_GRANTED) {
4512 restartPackageLocked(packageName, pkgUid);
4513 } else {
4514 throw new SecurityException(pid+" does not have permission:"+
4515 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4516 "for process:"+packageName);
4517 }
4518 }
4519
4520 try {
4521 //clear application user data
4522 pm.clearApplicationUserData(packageName, observer);
4523 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4524 Uri.fromParts("package", packageName, null));
4525 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4526 broadcastIntentLocked(null, null, intent,
4527 null, null, 0, null, null, null,
4528 false, false, MY_PID, Process.SYSTEM_UID);
4529 } catch (RemoteException e) {
4530 }
4531 } finally {
4532 Binder.restoreCallingIdentity(callingId);
4533 }
4534 return true;
4535 }
4536
4537 public void restartPackage(final String packageName) {
4538 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4539 != PackageManager.PERMISSION_GRANTED) {
4540 String msg = "Permission Denial: restartPackage() from pid="
4541 + Binder.getCallingPid()
4542 + ", uid=" + Binder.getCallingUid()
4543 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4544 Log.w(TAG, msg);
4545 throw new SecurityException(msg);
4546 }
4547
4548 long callingId = Binder.clearCallingIdentity();
4549 try {
4550 IPackageManager pm = ActivityThread.getPackageManager();
4551 int pkgUid = -1;
4552 synchronized(this) {
4553 try {
4554 pkgUid = pm.getPackageUid(packageName);
4555 } catch (RemoteException e) {
4556 }
4557 if (pkgUid == -1) {
4558 Log.w(TAG, "Invalid packageName: " + packageName);
4559 return;
4560 }
4561 restartPackageLocked(packageName, pkgUid);
4562 }
4563 } finally {
4564 Binder.restoreCallingIdentity(callingId);
4565 }
4566 }
4567
4568 private void restartPackageLocked(final String packageName, int uid) {
4569 uninstallPackageLocked(packageName, uid, false);
4570 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4571 Uri.fromParts("package", packageName, null));
4572 intent.putExtra(Intent.EXTRA_UID, uid);
4573 broadcastIntentLocked(null, null, intent,
4574 null, null, 0, null, null, null,
4575 false, false, MY_PID, Process.SYSTEM_UID);
4576 }
4577
4578 private final void uninstallPackageLocked(String name, int uid,
4579 boolean callerWillRestart) {
4580 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4581
4582 int i, N;
4583
4584 final String procNamePrefix = name + ":";
4585 if (uid < 0) {
4586 try {
4587 uid = ActivityThread.getPackageManager().getPackageUid(name);
4588 } catch (RemoteException e) {
4589 }
4590 }
4591
4592 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4593 while (badApps.hasNext()) {
4594 SparseArray<Long> ba = badApps.next();
4595 if (ba.get(uid) != null) {
4596 badApps.remove();
4597 }
4598 }
4599
4600 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4601
4602 // Remove all processes this package may have touched: all with the
4603 // same UID (except for the system or root user), and all whose name
4604 // matches the package name.
4605 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4606 final int NA = apps.size();
4607 for (int ia=0; ia<NA; ia++) {
4608 ProcessRecord app = apps.valueAt(ia);
4609 if (app.removed) {
4610 procs.add(app);
4611 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4612 || app.processName.equals(name)
4613 || app.processName.startsWith(procNamePrefix)) {
4614 app.removed = true;
4615 procs.add(app);
4616 }
4617 }
4618 }
4619
4620 N = procs.size();
4621 for (i=0; i<N; i++) {
4622 removeProcessLocked(procs.get(i), callerWillRestart);
4623 }
4624
4625 for (i=mHistory.size()-1; i>=0; i--) {
4626 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4627 if (r.packageName.equals(name)) {
4628 if (Config.LOGD) Log.d(
4629 TAG, " Force finishing activity "
4630 + r.intent.getComponent().flattenToShortString());
4631 if (r.app != null) {
4632 r.app.removed = true;
4633 }
4634 r.app = null;
4635 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4636 }
4637 }
4638
4639 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4640 for (ServiceRecord service : mServices.values()) {
4641 if (service.packageName.equals(name)) {
4642 if (service.app != null) {
4643 service.app.removed = true;
4644 }
4645 service.app = null;
4646 services.add(service);
4647 }
4648 }
4649
4650 N = services.size();
4651 for (i=0; i<N; i++) {
4652 bringDownServiceLocked(services.get(i), true);
4653 }
4654
4655 resumeTopActivityLocked(null);
4656 }
4657
4658 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4659 final String name = app.processName;
4660 final int uid = app.info.uid;
4661 if (Config.LOGD) Log.d(
4662 TAG, "Force removing process " + app + " (" + name
4663 + "/" + uid + ")");
4664
4665 mProcessNames.remove(name, uid);
4666 boolean needRestart = false;
4667 if (app.pid > 0 && app.pid != MY_PID) {
4668 int pid = app.pid;
4669 synchronized (mPidsSelfLocked) {
4670 mPidsSelfLocked.remove(pid);
4671 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4672 }
4673 handleAppDiedLocked(app, true);
4674 mLRUProcesses.remove(app);
4675 Process.killProcess(pid);
4676
4677 if (app.persistent) {
4678 if (!callerWillRestart) {
4679 addAppLocked(app.info);
4680 } else {
4681 needRestart = true;
4682 }
4683 }
4684 } else {
4685 mRemovedProcesses.add(app);
4686 }
4687
4688 return needRestart;
4689 }
4690
4691 private final void processStartTimedOutLocked(ProcessRecord app) {
4692 final int pid = app.pid;
4693 boolean gone = false;
4694 synchronized (mPidsSelfLocked) {
4695 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4696 if (knownApp != null && knownApp.thread == null) {
4697 mPidsSelfLocked.remove(pid);
4698 gone = true;
4699 }
4700 }
4701
4702 if (gone) {
4703 Log.w(TAG, "Process " + app + " failed to attach");
4704 mProcessNames.remove(app.processName, app.info.uid);
4705 Process.killProcess(pid);
4706 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4707 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4708 mPendingBroadcast = null;
4709 scheduleBroadcastsLocked();
4710 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004711 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4712 Log.w(TAG, "Unattached app died before backup, skipping");
4713 try {
4714 IBackupManager bm = IBackupManager.Stub.asInterface(
4715 ServiceManager.getService(Context.BACKUP_SERVICE));
4716 bm.agentDisconnected(app.info.packageName);
4717 } catch (RemoteException e) {
4718 // Can't happen; the backup manager is local
4719 }
4720 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004721 } else {
4722 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4723 }
4724 }
4725
4726 private final boolean attachApplicationLocked(IApplicationThread thread,
4727 int pid) {
4728
4729 // Find the application record that is being attached... either via
4730 // the pid if we are running in multiple processes, or just pull the
4731 // next app record if we are emulating process with anonymous threads.
4732 ProcessRecord app;
4733 if (pid != MY_PID && pid >= 0) {
4734 synchronized (mPidsSelfLocked) {
4735 app = mPidsSelfLocked.get(pid);
4736 }
4737 } else if (mStartingProcesses.size() > 0) {
4738 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004739 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004740 } else {
4741 app = null;
4742 }
4743
4744 if (app == null) {
4745 Log.w(TAG, "No pending application record for pid " + pid
4746 + " (IApplicationThread " + thread + "); dropping process");
4747 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4748 if (pid > 0 && pid != MY_PID) {
4749 Process.killProcess(pid);
4750 } else {
4751 try {
4752 thread.scheduleExit();
4753 } catch (Exception e) {
4754 // Ignore exceptions.
4755 }
4756 }
4757 return false;
4758 }
4759
4760 // If this application record is still attached to a previous
4761 // process, clean it up now.
4762 if (app.thread != null) {
4763 handleAppDiedLocked(app, true);
4764 }
4765
4766 // Tell the process all about itself.
4767
4768 if (localLOGV) Log.v(
4769 TAG, "Binding process pid " + pid + " to record " + app);
4770
4771 String processName = app.processName;
4772 try {
4773 thread.asBinder().linkToDeath(new AppDeathRecipient(
4774 app, pid, thread), 0);
4775 } catch (RemoteException e) {
4776 app.resetPackageList();
4777 startProcessLocked(app, "link fail", processName);
4778 return false;
4779 }
4780
4781 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4782
4783 app.thread = thread;
4784 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004785 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 app.forcingToForeground = null;
4787 app.foregroundServices = false;
4788 app.debugging = false;
4789
4790 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4791
4792 List providers = generateApplicationProvidersLocked(app);
4793
4794 if (localLOGV) Log.v(
4795 TAG, "New app record " + app
4796 + " thread=" + thread.asBinder() + " pid=" + pid);
4797 try {
4798 int testMode = IApplicationThread.DEBUG_OFF;
4799 if (mDebugApp != null && mDebugApp.equals(processName)) {
4800 testMode = mWaitForDebugger
4801 ? IApplicationThread.DEBUG_WAIT
4802 : IApplicationThread.DEBUG_ON;
4803 app.debugging = true;
4804 if (mDebugTransient) {
4805 mDebugApp = mOrigDebugApp;
4806 mWaitForDebugger = mOrigWaitForDebugger;
4807 }
4808 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004809 // If the app is being launched for restore or full backup, set it up specially
4810 boolean isRestrictedBackupMode = false;
4811 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4812 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4813 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4814 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004815 thread.bindApplication(processName, app.instrumentationInfo != null
4816 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004817 app.instrumentationClass, app.instrumentationProfileFile,
4818 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004819 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004820 updateLRUListLocked(app, false);
4821 app.lastRequestedGc = SystemClock.uptimeMillis();
4822 } catch (Exception e) {
4823 // todo: Yikes! What should we do? For now we will try to
4824 // start another process, but that could easily get us in
4825 // an infinite loop of restarting processes...
4826 Log.w(TAG, "Exception thrown during bind!", e);
4827
4828 app.resetPackageList();
4829 startProcessLocked(app, "bind fail", processName);
4830 return false;
4831 }
4832
4833 // Remove this record from the list of starting applications.
4834 mPersistentStartingProcesses.remove(app);
4835 mProcessesOnHold.remove(app);
4836
4837 boolean badApp = false;
4838 boolean didSomething = false;
4839
4840 // See if the top visible activity is waiting to run in this process...
4841 HistoryRecord hr = topRunningActivityLocked(null);
4842 if (hr != null) {
4843 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4844 && processName.equals(hr.processName)) {
4845 try {
4846 if (realStartActivityLocked(hr, app, true, true)) {
4847 didSomething = true;
4848 }
4849 } catch (Exception e) {
4850 Log.w(TAG, "Exception in new application when starting activity "
4851 + hr.intent.getComponent().flattenToShortString(), e);
4852 badApp = true;
4853 }
4854 } else {
4855 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4856 }
4857 }
4858
4859 // Find any services that should be running in this process...
4860 if (!badApp && mPendingServices.size() > 0) {
4861 ServiceRecord sr = null;
4862 try {
4863 for (int i=0; i<mPendingServices.size(); i++) {
4864 sr = mPendingServices.get(i);
4865 if (app.info.uid != sr.appInfo.uid
4866 || !processName.equals(sr.processName)) {
4867 continue;
4868 }
4869
4870 mPendingServices.remove(i);
4871 i--;
4872 realStartServiceLocked(sr, app);
4873 didSomething = true;
4874 }
4875 } catch (Exception e) {
4876 Log.w(TAG, "Exception in new application when starting service "
4877 + sr.shortName, e);
4878 badApp = true;
4879 }
4880 }
4881
4882 // Check if the next broadcast receiver is in this process...
4883 BroadcastRecord br = mPendingBroadcast;
4884 if (!badApp && br != null && br.curApp == app) {
4885 try {
4886 mPendingBroadcast = null;
4887 processCurBroadcastLocked(br, app);
4888 didSomething = true;
4889 } catch (Exception e) {
4890 Log.w(TAG, "Exception in new application when starting receiver "
4891 + br.curComponent.flattenToShortString(), e);
4892 badApp = true;
4893 logBroadcastReceiverDiscard(br);
4894 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4895 br.resultExtras, br.resultAbort, true);
4896 scheduleBroadcastsLocked();
4897 }
4898 }
4899
Christopher Tate181fafa2009-05-14 11:12:14 -07004900 // Check whether the next backup agent is in this process...
4901 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4902 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
4903 try {
4904 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4905 } catch (Exception e) {
4906 Log.w(TAG, "Exception scheduling backup agent creation: ");
4907 e.printStackTrace();
4908 }
4909 }
4910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004911 if (badApp) {
4912 // todo: Also need to kill application to deal with all
4913 // kinds of exceptions.
4914 handleAppDiedLocked(app, false);
4915 return false;
4916 }
4917
4918 if (!didSomething) {
4919 updateOomAdjLocked();
4920 }
4921
4922 return true;
4923 }
4924
4925 public final void attachApplication(IApplicationThread thread) {
4926 synchronized (this) {
4927 int callingPid = Binder.getCallingPid();
4928 final long origId = Binder.clearCallingIdentity();
4929 attachApplicationLocked(thread, callingPid);
4930 Binder.restoreCallingIdentity(origId);
4931 }
4932 }
4933
4934 public final void activityIdle(IBinder token) {
4935 final long origId = Binder.clearCallingIdentity();
4936 activityIdleInternal(token, false);
4937 Binder.restoreCallingIdentity(origId);
4938 }
4939
4940 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
4941 boolean remove) {
4942 int N = mStoppingActivities.size();
4943 if (N <= 0) return null;
4944
4945 ArrayList<HistoryRecord> stops = null;
4946
4947 final boolean nowVisible = mResumedActivity != null
4948 && mResumedActivity.nowVisible
4949 && !mResumedActivity.waitingVisible;
4950 for (int i=0; i<N; i++) {
4951 HistoryRecord s = mStoppingActivities.get(i);
4952 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
4953 + nowVisible + " waitingVisible=" + s.waitingVisible
4954 + " finishing=" + s.finishing);
4955 if (s.waitingVisible && nowVisible) {
4956 mWaitingVisibleActivities.remove(s);
4957 s.waitingVisible = false;
4958 if (s.finishing) {
4959 // If this activity is finishing, it is sitting on top of
4960 // everyone else but we now know it is no longer needed...
4961 // so get rid of it. Otherwise, we need to go through the
4962 // normal flow and hide it once we determine that it is
4963 // hidden by the activities in front of it.
4964 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
4965 mWindowManager.setAppVisibility(s, false);
4966 }
4967 }
4968 if (!s.waitingVisible && remove) {
4969 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
4970 if (stops == null) {
4971 stops = new ArrayList<HistoryRecord>();
4972 }
4973 stops.add(s);
4974 mStoppingActivities.remove(i);
4975 N--;
4976 i--;
4977 }
4978 }
4979
4980 return stops;
4981 }
4982
4983 void enableScreenAfterBoot() {
4984 mWindowManager.enableScreenAfterBoot();
4985 }
4986
4987 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
4988 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
4989
4990 ArrayList<HistoryRecord> stops = null;
4991 ArrayList<HistoryRecord> finishes = null;
4992 ArrayList<HistoryRecord> thumbnails = null;
4993 int NS = 0;
4994 int NF = 0;
4995 int NT = 0;
4996 IApplicationThread sendThumbnail = null;
4997 boolean booting = false;
4998 boolean enableScreen = false;
4999
5000 synchronized (this) {
5001 if (token != null) {
5002 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5003 }
5004
5005 // Get the activity record.
5006 int index = indexOfTokenLocked(token, false);
5007 if (index >= 0) {
5008 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5009
5010 // No longer need to keep the device awake.
5011 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5012 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5013 mLaunchingActivity.release();
5014 }
5015
5016 // We are now idle. If someone is waiting for a thumbnail from
5017 // us, we can now deliver.
5018 r.idle = true;
5019 scheduleAppGcsLocked();
5020 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5021 sendThumbnail = r.app.thread;
5022 r.thumbnailNeeded = false;
5023 }
5024
5025 // If this activity is fullscreen, set up to hide those under it.
5026
5027 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5028 ensureActivitiesVisibleLocked(null, 0);
5029
5030 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5031 if (!mBooted && !fromTimeout) {
5032 mBooted = true;
5033 enableScreen = true;
5034 }
5035 }
5036
5037 // Atomically retrieve all of the other things to do.
5038 stops = processStoppingActivitiesLocked(true);
5039 NS = stops != null ? stops.size() : 0;
5040 if ((NF=mFinishingActivities.size()) > 0) {
5041 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5042 mFinishingActivities.clear();
5043 }
5044 if ((NT=mCancelledThumbnails.size()) > 0) {
5045 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5046 mCancelledThumbnails.clear();
5047 }
5048
5049 booting = mBooting;
5050 mBooting = false;
5051 }
5052
5053 int i;
5054
5055 // Send thumbnail if requested.
5056 if (sendThumbnail != null) {
5057 try {
5058 sendThumbnail.requestThumbnail(token);
5059 } catch (Exception e) {
5060 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5061 sendPendingThumbnail(null, token, null, null, true);
5062 }
5063 }
5064
5065 // Stop any activities that are scheduled to do so but have been
5066 // waiting for the next one to start.
5067 for (i=0; i<NS; i++) {
5068 HistoryRecord r = (HistoryRecord)stops.get(i);
5069 synchronized (this) {
5070 if (r.finishing) {
5071 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5072 } else {
5073 stopActivityLocked(r);
5074 }
5075 }
5076 }
5077
5078 // Finish any activities that are scheduled to do so but have been
5079 // waiting for the next one to start.
5080 for (i=0; i<NF; i++) {
5081 HistoryRecord r = (HistoryRecord)finishes.get(i);
5082 synchronized (this) {
5083 destroyActivityLocked(r, true);
5084 }
5085 }
5086
5087 // Report back to any thumbnail receivers.
5088 for (i=0; i<NT; i++) {
5089 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5090 sendPendingThumbnail(r, null, null, null, true);
5091 }
5092
5093 if (booting) {
5094 // Ensure that any processes we had put on hold are now started
5095 // up.
5096 final int NP = mProcessesOnHold.size();
5097 if (NP > 0) {
5098 ArrayList<ProcessRecord> procs =
5099 new ArrayList<ProcessRecord>(mProcessesOnHold);
5100 for (int ip=0; ip<NP; ip++) {
5101 this.startProcessLocked(procs.get(ip), "on-hold", null);
5102 }
5103 }
5104 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5105 // Tell anyone interested that we are done booting!
5106 synchronized (this) {
5107 broadcastIntentLocked(null, null,
5108 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5109 null, null, 0, null, null,
5110 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5111 false, false, MY_PID, Process.SYSTEM_UID);
5112 }
5113 }
5114 }
5115
5116 trimApplications();
5117 //dump();
5118 //mWindowManager.dump();
5119
5120 if (enableScreen) {
5121 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5122 SystemClock.uptimeMillis());
5123 enableScreenAfterBoot();
5124 }
5125 }
5126
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005127 final void ensureScreenEnabled() {
5128 boolean enableScreen;
5129 synchronized (this) {
5130 enableScreen = !mBooted;
5131 mBooted = true;
5132 }
5133
5134 if (enableScreen) {
5135 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5136 SystemClock.uptimeMillis());
5137 enableScreenAfterBoot();
5138 }
5139 }
5140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005141 public final void activityPaused(IBinder token, Bundle icicle) {
5142 // Refuse possible leaked file descriptors
5143 if (icicle != null && icicle.hasFileDescriptors()) {
5144 throw new IllegalArgumentException("File descriptors passed in Bundle");
5145 }
5146
5147 final long origId = Binder.clearCallingIdentity();
5148 activityPaused(token, icicle, false);
5149 Binder.restoreCallingIdentity(origId);
5150 }
5151
5152 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5153 if (DEBUG_PAUSE) Log.v(
5154 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5155 + ", timeout=" + timeout);
5156
5157 HistoryRecord r = null;
5158
5159 synchronized (this) {
5160 int index = indexOfTokenLocked(token, false);
5161 if (index >= 0) {
5162 r = (HistoryRecord)mHistory.get(index);
5163 if (!timeout) {
5164 r.icicle = icicle;
5165 r.haveState = true;
5166 }
5167 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5168 if (mPausingActivity == r) {
5169 r.state = ActivityState.PAUSED;
5170 completePauseLocked();
5171 } else {
5172 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5173 System.identityHashCode(r), r.shortComponentName,
5174 mPausingActivity != null
5175 ? mPausingActivity.shortComponentName : "(none)");
5176 }
5177 }
5178 }
5179 }
5180
5181 public final void activityStopped(IBinder token, Bitmap thumbnail,
5182 CharSequence description) {
5183 if (localLOGV) Log.v(
5184 TAG, "Activity stopped: token=" + token);
5185
5186 HistoryRecord r = null;
5187
5188 final long origId = Binder.clearCallingIdentity();
5189
5190 synchronized (this) {
5191 int index = indexOfTokenLocked(token, false);
5192 if (index >= 0) {
5193 r = (HistoryRecord)mHistory.get(index);
5194 r.thumbnail = thumbnail;
5195 r.description = description;
5196 r.stopped = true;
5197 r.state = ActivityState.STOPPED;
5198 if (!r.finishing) {
5199 if (r.configDestroy) {
5200 destroyActivityLocked(r, true);
5201 resumeTopActivityLocked(null);
5202 }
5203 }
5204 }
5205 }
5206
5207 if (r != null) {
5208 sendPendingThumbnail(r, null, null, null, false);
5209 }
5210
5211 trimApplications();
5212
5213 Binder.restoreCallingIdentity(origId);
5214 }
5215
5216 public final void activityDestroyed(IBinder token) {
5217 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5218 synchronized (this) {
5219 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5220
5221 int index = indexOfTokenLocked(token, false);
5222 if (index >= 0) {
5223 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5224 if (r.state == ActivityState.DESTROYING) {
5225 final long origId = Binder.clearCallingIdentity();
5226 removeActivityFromHistoryLocked(r);
5227 Binder.restoreCallingIdentity(origId);
5228 }
5229 }
5230 }
5231 }
5232
5233 public String getCallingPackage(IBinder token) {
5234 synchronized (this) {
5235 HistoryRecord r = getCallingRecordLocked(token);
5236 return r != null && r.app != null ? r.app.processName : null;
5237 }
5238 }
5239
5240 public ComponentName getCallingActivity(IBinder token) {
5241 synchronized (this) {
5242 HistoryRecord r = getCallingRecordLocked(token);
5243 return r != null ? r.intent.getComponent() : null;
5244 }
5245 }
5246
5247 private HistoryRecord getCallingRecordLocked(IBinder token) {
5248 int index = indexOfTokenLocked(token, true);
5249 if (index >= 0) {
5250 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5251 if (r != null) {
5252 return r.resultTo;
5253 }
5254 }
5255 return null;
5256 }
5257
5258 public ComponentName getActivityClassForToken(IBinder token) {
5259 synchronized(this) {
5260 int index = indexOfTokenLocked(token, false);
5261 if (index >= 0) {
5262 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5263 return r.intent.getComponent();
5264 }
5265 return null;
5266 }
5267 }
5268
5269 public String getPackageForToken(IBinder token) {
5270 synchronized(this) {
5271 int index = indexOfTokenLocked(token, false);
5272 if (index >= 0) {
5273 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5274 return r.packageName;
5275 }
5276 return null;
5277 }
5278 }
5279
5280 public IIntentSender getIntentSender(int type,
5281 String packageName, IBinder token, String resultWho,
5282 int requestCode, Intent intent, String resolvedType, int flags) {
5283 // Refuse possible leaked file descriptors
5284 if (intent != null && intent.hasFileDescriptors() == true) {
5285 throw new IllegalArgumentException("File descriptors passed in Intent");
5286 }
5287
5288 synchronized(this) {
5289 int callingUid = Binder.getCallingUid();
5290 try {
5291 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5292 Process.supportsProcesses()) {
5293 int uid = ActivityThread.getPackageManager()
5294 .getPackageUid(packageName);
5295 if (uid != Binder.getCallingUid()) {
5296 String msg = "Permission Denial: getIntentSender() from pid="
5297 + Binder.getCallingPid()
5298 + ", uid=" + Binder.getCallingUid()
5299 + ", (need uid=" + uid + ")"
5300 + " is not allowed to send as package " + packageName;
5301 Log.w(TAG, msg);
5302 throw new SecurityException(msg);
5303 }
5304 }
5305 } catch (RemoteException e) {
5306 throw new SecurityException(e);
5307 }
5308 HistoryRecord activity = null;
5309 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5310 int index = indexOfTokenLocked(token, false);
5311 if (index < 0) {
5312 return null;
5313 }
5314 activity = (HistoryRecord)mHistory.get(index);
5315 if (activity.finishing) {
5316 return null;
5317 }
5318 }
5319
5320 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5321 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5322 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5323 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5324 |PendingIntent.FLAG_UPDATE_CURRENT);
5325
5326 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5327 type, packageName, activity, resultWho,
5328 requestCode, intent, resolvedType, flags);
5329 WeakReference<PendingIntentRecord> ref;
5330 ref = mIntentSenderRecords.get(key);
5331 PendingIntentRecord rec = ref != null ? ref.get() : null;
5332 if (rec != null) {
5333 if (!cancelCurrent) {
5334 if (updateCurrent) {
5335 rec.key.requestIntent.replaceExtras(intent);
5336 }
5337 return rec;
5338 }
5339 rec.canceled = true;
5340 mIntentSenderRecords.remove(key);
5341 }
5342 if (noCreate) {
5343 return rec;
5344 }
5345 rec = new PendingIntentRecord(this, key, callingUid);
5346 mIntentSenderRecords.put(key, rec.ref);
5347 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5348 if (activity.pendingResults == null) {
5349 activity.pendingResults
5350 = new HashSet<WeakReference<PendingIntentRecord>>();
5351 }
5352 activity.pendingResults.add(rec.ref);
5353 }
5354 return rec;
5355 }
5356 }
5357
5358 public void cancelIntentSender(IIntentSender sender) {
5359 if (!(sender instanceof PendingIntentRecord)) {
5360 return;
5361 }
5362 synchronized(this) {
5363 PendingIntentRecord rec = (PendingIntentRecord)sender;
5364 try {
5365 int uid = ActivityThread.getPackageManager()
5366 .getPackageUid(rec.key.packageName);
5367 if (uid != Binder.getCallingUid()) {
5368 String msg = "Permission Denial: cancelIntentSender() from pid="
5369 + Binder.getCallingPid()
5370 + ", uid=" + Binder.getCallingUid()
5371 + " is not allowed to cancel packges "
5372 + rec.key.packageName;
5373 Log.w(TAG, msg);
5374 throw new SecurityException(msg);
5375 }
5376 } catch (RemoteException e) {
5377 throw new SecurityException(e);
5378 }
5379 cancelIntentSenderLocked(rec, true);
5380 }
5381 }
5382
5383 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5384 rec.canceled = true;
5385 mIntentSenderRecords.remove(rec.key);
5386 if (cleanActivity && rec.key.activity != null) {
5387 rec.key.activity.pendingResults.remove(rec.ref);
5388 }
5389 }
5390
5391 public String getPackageForIntentSender(IIntentSender pendingResult) {
5392 if (!(pendingResult instanceof PendingIntentRecord)) {
5393 return null;
5394 }
5395 synchronized(this) {
5396 try {
5397 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5398 return res.key.packageName;
5399 } catch (ClassCastException e) {
5400 }
5401 }
5402 return null;
5403 }
5404
5405 public void setProcessLimit(int max) {
5406 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5407 "setProcessLimit()");
5408 mProcessLimit = max;
5409 }
5410
5411 public int getProcessLimit() {
5412 return mProcessLimit;
5413 }
5414
5415 void foregroundTokenDied(ForegroundToken token) {
5416 synchronized (ActivityManagerService.this) {
5417 synchronized (mPidsSelfLocked) {
5418 ForegroundToken cur
5419 = mForegroundProcesses.get(token.pid);
5420 if (cur != token) {
5421 return;
5422 }
5423 mForegroundProcesses.remove(token.pid);
5424 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5425 if (pr == null) {
5426 return;
5427 }
5428 pr.forcingToForeground = null;
5429 pr.foregroundServices = false;
5430 }
5431 updateOomAdjLocked();
5432 }
5433 }
5434
5435 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5436 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5437 "setProcessForeground()");
5438 synchronized(this) {
5439 boolean changed = false;
5440
5441 synchronized (mPidsSelfLocked) {
5442 ProcessRecord pr = mPidsSelfLocked.get(pid);
5443 if (pr == null) {
5444 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5445 return;
5446 }
5447 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5448 if (oldToken != null) {
5449 oldToken.token.unlinkToDeath(oldToken, 0);
5450 mForegroundProcesses.remove(pid);
5451 pr.forcingToForeground = null;
5452 changed = true;
5453 }
5454 if (isForeground && token != null) {
5455 ForegroundToken newToken = new ForegroundToken() {
5456 public void binderDied() {
5457 foregroundTokenDied(this);
5458 }
5459 };
5460 newToken.pid = pid;
5461 newToken.token = token;
5462 try {
5463 token.linkToDeath(newToken, 0);
5464 mForegroundProcesses.put(pid, newToken);
5465 pr.forcingToForeground = token;
5466 changed = true;
5467 } catch (RemoteException e) {
5468 // If the process died while doing this, we will later
5469 // do the cleanup with the process death link.
5470 }
5471 }
5472 }
5473
5474 if (changed) {
5475 updateOomAdjLocked();
5476 }
5477 }
5478 }
5479
5480 // =========================================================
5481 // PERMISSIONS
5482 // =========================================================
5483
5484 static class PermissionController extends IPermissionController.Stub {
5485 ActivityManagerService mActivityManagerService;
5486 PermissionController(ActivityManagerService activityManagerService) {
5487 mActivityManagerService = activityManagerService;
5488 }
5489
5490 public boolean checkPermission(String permission, int pid, int uid) {
5491 return mActivityManagerService.checkPermission(permission, pid,
5492 uid) == PackageManager.PERMISSION_GRANTED;
5493 }
5494 }
5495
5496 /**
5497 * This can be called with or without the global lock held.
5498 */
5499 int checkComponentPermission(String permission, int pid, int uid,
5500 int reqUid) {
5501 // We might be performing an operation on behalf of an indirect binder
5502 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5503 // client identity accordingly before proceeding.
5504 Identity tlsIdentity = sCallerIdentity.get();
5505 if (tlsIdentity != null) {
5506 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5507 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5508 uid = tlsIdentity.uid;
5509 pid = tlsIdentity.pid;
5510 }
5511
5512 // Root, system server and our own process get to do everything.
5513 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5514 !Process.supportsProcesses()) {
5515 return PackageManager.PERMISSION_GRANTED;
5516 }
5517 // If the target requires a specific UID, always fail for others.
5518 if (reqUid >= 0 && uid != reqUid) {
5519 return PackageManager.PERMISSION_DENIED;
5520 }
5521 if (permission == null) {
5522 return PackageManager.PERMISSION_GRANTED;
5523 }
5524 try {
5525 return ActivityThread.getPackageManager()
5526 .checkUidPermission(permission, uid);
5527 } catch (RemoteException e) {
5528 // Should never happen, but if it does... deny!
5529 Log.e(TAG, "PackageManager is dead?!?", e);
5530 }
5531 return PackageManager.PERMISSION_DENIED;
5532 }
5533
5534 /**
5535 * As the only public entry point for permissions checking, this method
5536 * can enforce the semantic that requesting a check on a null global
5537 * permission is automatically denied. (Internally a null permission
5538 * string is used when calling {@link #checkComponentPermission} in cases
5539 * when only uid-based security is needed.)
5540 *
5541 * This can be called with or without the global lock held.
5542 */
5543 public int checkPermission(String permission, int pid, int uid) {
5544 if (permission == null) {
5545 return PackageManager.PERMISSION_DENIED;
5546 }
5547 return checkComponentPermission(permission, pid, uid, -1);
5548 }
5549
5550 /**
5551 * Binder IPC calls go through the public entry point.
5552 * This can be called with or without the global lock held.
5553 */
5554 int checkCallingPermission(String permission) {
5555 return checkPermission(permission,
5556 Binder.getCallingPid(),
5557 Binder.getCallingUid());
5558 }
5559
5560 /**
5561 * This can be called with or without the global lock held.
5562 */
5563 void enforceCallingPermission(String permission, String func) {
5564 if (checkCallingPermission(permission)
5565 == PackageManager.PERMISSION_GRANTED) {
5566 return;
5567 }
5568
5569 String msg = "Permission Denial: " + func + " from pid="
5570 + Binder.getCallingPid()
5571 + ", uid=" + Binder.getCallingUid()
5572 + " requires " + permission;
5573 Log.w(TAG, msg);
5574 throw new SecurityException(msg);
5575 }
5576
5577 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5578 ProviderInfo pi, int uid, int modeFlags) {
5579 try {
5580 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5581 if ((pi.readPermission != null) &&
5582 (pm.checkUidPermission(pi.readPermission, uid)
5583 != PackageManager.PERMISSION_GRANTED)) {
5584 return false;
5585 }
5586 }
5587 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5588 if ((pi.writePermission != null) &&
5589 (pm.checkUidPermission(pi.writePermission, uid)
5590 != PackageManager.PERMISSION_GRANTED)) {
5591 return false;
5592 }
5593 }
5594 return true;
5595 } catch (RemoteException e) {
5596 return false;
5597 }
5598 }
5599
5600 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5601 int modeFlags) {
5602 // Root gets to do everything.
5603 if (uid == 0 || !Process.supportsProcesses()) {
5604 return true;
5605 }
5606 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5607 if (perms == null) return false;
5608 UriPermission perm = perms.get(uri);
5609 if (perm == null) return false;
5610 return (modeFlags&perm.modeFlags) == modeFlags;
5611 }
5612
5613 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5614 // Another redirected-binder-call permissions check as in
5615 // {@link checkComponentPermission}.
5616 Identity tlsIdentity = sCallerIdentity.get();
5617 if (tlsIdentity != null) {
5618 uid = tlsIdentity.uid;
5619 pid = tlsIdentity.pid;
5620 }
5621
5622 // Our own process gets to do everything.
5623 if (pid == MY_PID) {
5624 return PackageManager.PERMISSION_GRANTED;
5625 }
5626 synchronized(this) {
5627 return checkUriPermissionLocked(uri, uid, modeFlags)
5628 ? PackageManager.PERMISSION_GRANTED
5629 : PackageManager.PERMISSION_DENIED;
5630 }
5631 }
5632
5633 private void grantUriPermissionLocked(int callingUid,
5634 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5635 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5636 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5637 if (modeFlags == 0) {
5638 return;
5639 }
5640
5641 final IPackageManager pm = ActivityThread.getPackageManager();
5642
5643 // If this is not a content: uri, we can't do anything with it.
5644 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5645 return;
5646 }
5647
5648 String name = uri.getAuthority();
5649 ProviderInfo pi = null;
5650 ContentProviderRecord cpr
5651 = (ContentProviderRecord)mProvidersByName.get(name);
5652 if (cpr != null) {
5653 pi = cpr.info;
5654 } else {
5655 try {
5656 pi = pm.resolveContentProvider(name,
5657 PackageManager.GET_URI_PERMISSION_PATTERNS);
5658 } catch (RemoteException ex) {
5659 }
5660 }
5661 if (pi == null) {
5662 Log.w(TAG, "No content provider found for: " + name);
5663 return;
5664 }
5665
5666 int targetUid;
5667 try {
5668 targetUid = pm.getPackageUid(targetPkg);
5669 if (targetUid < 0) {
5670 return;
5671 }
5672 } catch (RemoteException ex) {
5673 return;
5674 }
5675
5676 // First... does the target actually need this permission?
5677 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5678 // No need to grant the target this permission.
5679 return;
5680 }
5681
5682 // Second... maybe someone else has already granted the
5683 // permission?
5684 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5685 // No need to grant the target this permission.
5686 return;
5687 }
5688
5689 // Third... is the provider allowing granting of URI permissions?
5690 if (!pi.grantUriPermissions) {
5691 throw new SecurityException("Provider " + pi.packageName
5692 + "/" + pi.name
5693 + " does not allow granting of Uri permissions (uri "
5694 + uri + ")");
5695 }
5696 if (pi.uriPermissionPatterns != null) {
5697 final int N = pi.uriPermissionPatterns.length;
5698 boolean allowed = false;
5699 for (int i=0; i<N; i++) {
5700 if (pi.uriPermissionPatterns[i] != null
5701 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5702 allowed = true;
5703 break;
5704 }
5705 }
5706 if (!allowed) {
5707 throw new SecurityException("Provider " + pi.packageName
5708 + "/" + pi.name
5709 + " does not allow granting of permission to path of Uri "
5710 + uri);
5711 }
5712 }
5713
5714 // Fourth... does the caller itself have permission to access
5715 // this uri?
5716 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5717 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5718 throw new SecurityException("Uid " + callingUid
5719 + " does not have permission to uri " + uri);
5720 }
5721 }
5722
5723 // Okay! So here we are: the caller has the assumed permission
5724 // to the uri, and the target doesn't. Let's now give this to
5725 // the target.
5726
5727 HashMap<Uri, UriPermission> targetUris
5728 = mGrantedUriPermissions.get(targetUid);
5729 if (targetUris == null) {
5730 targetUris = new HashMap<Uri, UriPermission>();
5731 mGrantedUriPermissions.put(targetUid, targetUris);
5732 }
5733
5734 UriPermission perm = targetUris.get(uri);
5735 if (perm == null) {
5736 perm = new UriPermission(targetUid, uri);
5737 targetUris.put(uri, perm);
5738
5739 }
5740 perm.modeFlags |= modeFlags;
5741 if (activity == null) {
5742 perm.globalModeFlags |= modeFlags;
5743 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5744 perm.readActivities.add(activity);
5745 if (activity.readUriPermissions == null) {
5746 activity.readUriPermissions = new HashSet<UriPermission>();
5747 }
5748 activity.readUriPermissions.add(perm);
5749 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5750 perm.writeActivities.add(activity);
5751 if (activity.writeUriPermissions == null) {
5752 activity.writeUriPermissions = new HashSet<UriPermission>();
5753 }
5754 activity.writeUriPermissions.add(perm);
5755 }
5756 }
5757
5758 private void grantUriPermissionFromIntentLocked(int callingUid,
5759 String targetPkg, Intent intent, HistoryRecord activity) {
5760 if (intent == null) {
5761 return;
5762 }
5763 Uri data = intent.getData();
5764 if (data == null) {
5765 return;
5766 }
5767 grantUriPermissionLocked(callingUid, targetPkg, data,
5768 intent.getFlags(), activity);
5769 }
5770
5771 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5772 Uri uri, int modeFlags) {
5773 synchronized(this) {
5774 final ProcessRecord r = getRecordForAppLocked(caller);
5775 if (r == null) {
5776 throw new SecurityException("Unable to find app for caller "
5777 + caller
5778 + " when granting permission to uri " + uri);
5779 }
5780 if (targetPkg == null) {
5781 Log.w(TAG, "grantUriPermission: null target");
5782 return;
5783 }
5784 if (uri == null) {
5785 Log.w(TAG, "grantUriPermission: null uri");
5786 return;
5787 }
5788
5789 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5790 null);
5791 }
5792 }
5793
5794 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5795 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5796 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5797 HashMap<Uri, UriPermission> perms
5798 = mGrantedUriPermissions.get(perm.uid);
5799 if (perms != null) {
5800 perms.remove(perm.uri);
5801 if (perms.size() == 0) {
5802 mGrantedUriPermissions.remove(perm.uid);
5803 }
5804 }
5805 }
5806 }
5807
5808 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5809 if (activity.readUriPermissions != null) {
5810 for (UriPermission perm : activity.readUriPermissions) {
5811 perm.readActivities.remove(activity);
5812 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5813 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5814 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5815 removeUriPermissionIfNeededLocked(perm);
5816 }
5817 }
5818 }
5819 if (activity.writeUriPermissions != null) {
5820 for (UriPermission perm : activity.writeUriPermissions) {
5821 perm.writeActivities.remove(activity);
5822 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5823 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5824 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5825 removeUriPermissionIfNeededLocked(perm);
5826 }
5827 }
5828 }
5829 }
5830
5831 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5832 int modeFlags) {
5833 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5834 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5835 if (modeFlags == 0) {
5836 return;
5837 }
5838
5839 final IPackageManager pm = ActivityThread.getPackageManager();
5840
5841 final String authority = uri.getAuthority();
5842 ProviderInfo pi = null;
5843 ContentProviderRecord cpr
5844 = (ContentProviderRecord)mProvidersByName.get(authority);
5845 if (cpr != null) {
5846 pi = cpr.info;
5847 } else {
5848 try {
5849 pi = pm.resolveContentProvider(authority,
5850 PackageManager.GET_URI_PERMISSION_PATTERNS);
5851 } catch (RemoteException ex) {
5852 }
5853 }
5854 if (pi == null) {
5855 Log.w(TAG, "No content provider found for: " + authority);
5856 return;
5857 }
5858
5859 // Does the caller have this permission on the URI?
5860 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5861 // Right now, if you are not the original owner of the permission,
5862 // you are not allowed to revoke it.
5863 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5864 throw new SecurityException("Uid " + callingUid
5865 + " does not have permission to uri " + uri);
5866 //}
5867 }
5868
5869 // Go through all of the permissions and remove any that match.
5870 final List<String> SEGMENTS = uri.getPathSegments();
5871 if (SEGMENTS != null) {
5872 final int NS = SEGMENTS.size();
5873 int N = mGrantedUriPermissions.size();
5874 for (int i=0; i<N; i++) {
5875 HashMap<Uri, UriPermission> perms
5876 = mGrantedUriPermissions.valueAt(i);
5877 Iterator<UriPermission> it = perms.values().iterator();
5878 toploop:
5879 while (it.hasNext()) {
5880 UriPermission perm = it.next();
5881 Uri targetUri = perm.uri;
5882 if (!authority.equals(targetUri.getAuthority())) {
5883 continue;
5884 }
5885 List<String> targetSegments = targetUri.getPathSegments();
5886 if (targetSegments == null) {
5887 continue;
5888 }
5889 if (targetSegments.size() < NS) {
5890 continue;
5891 }
5892 for (int j=0; j<NS; j++) {
5893 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5894 continue toploop;
5895 }
5896 }
5897 perm.clearModes(modeFlags);
5898 if (perm.modeFlags == 0) {
5899 it.remove();
5900 }
5901 }
5902 if (perms.size() == 0) {
5903 mGrantedUriPermissions.remove(
5904 mGrantedUriPermissions.keyAt(i));
5905 N--;
5906 i--;
5907 }
5908 }
5909 }
5910 }
5911
5912 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5913 int modeFlags) {
5914 synchronized(this) {
5915 final ProcessRecord r = getRecordForAppLocked(caller);
5916 if (r == null) {
5917 throw new SecurityException("Unable to find app for caller "
5918 + caller
5919 + " when revoking permission to uri " + uri);
5920 }
5921 if (uri == null) {
5922 Log.w(TAG, "revokeUriPermission: null uri");
5923 return;
5924 }
5925
5926 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5927 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5928 if (modeFlags == 0) {
5929 return;
5930 }
5931
5932 final IPackageManager pm = ActivityThread.getPackageManager();
5933
5934 final String authority = uri.getAuthority();
5935 ProviderInfo pi = null;
5936 ContentProviderRecord cpr
5937 = (ContentProviderRecord)mProvidersByName.get(authority);
5938 if (cpr != null) {
5939 pi = cpr.info;
5940 } else {
5941 try {
5942 pi = pm.resolveContentProvider(authority,
5943 PackageManager.GET_URI_PERMISSION_PATTERNS);
5944 } catch (RemoteException ex) {
5945 }
5946 }
5947 if (pi == null) {
5948 Log.w(TAG, "No content provider found for: " + authority);
5949 return;
5950 }
5951
5952 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
5953 }
5954 }
5955
5956 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
5957 synchronized (this) {
5958 ProcessRecord app =
5959 who != null ? getRecordForAppLocked(who) : null;
5960 if (app == null) return;
5961
5962 Message msg = Message.obtain();
5963 msg.what = WAIT_FOR_DEBUGGER_MSG;
5964 msg.obj = app;
5965 msg.arg1 = waiting ? 1 : 0;
5966 mHandler.sendMessage(msg);
5967 }
5968 }
5969
5970 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
5971 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08005972 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005973 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08005974 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005975 }
5976
5977 // =========================================================
5978 // TASK MANAGEMENT
5979 // =========================================================
5980
5981 public List getTasks(int maxNum, int flags,
5982 IThumbnailReceiver receiver) {
5983 ArrayList list = new ArrayList();
5984
5985 PendingThumbnailsRecord pending = null;
5986 IApplicationThread topThumbnail = null;
5987 HistoryRecord topRecord = null;
5988
5989 synchronized(this) {
5990 if (localLOGV) Log.v(
5991 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
5992 + ", receiver=" + receiver);
5993
5994 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
5995 != PackageManager.PERMISSION_GRANTED) {
5996 if (receiver != null) {
5997 // If the caller wants to wait for pending thumbnails,
5998 // it ain't gonna get them.
5999 try {
6000 receiver.finished();
6001 } catch (RemoteException ex) {
6002 }
6003 }
6004 String msg = "Permission Denial: getTasks() from pid="
6005 + Binder.getCallingPid()
6006 + ", uid=" + Binder.getCallingUid()
6007 + " requires " + android.Manifest.permission.GET_TASKS;
6008 Log.w(TAG, msg);
6009 throw new SecurityException(msg);
6010 }
6011
6012 int pos = mHistory.size()-1;
6013 HistoryRecord next =
6014 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6015 HistoryRecord top = null;
6016 CharSequence topDescription = null;
6017 TaskRecord curTask = null;
6018 int numActivities = 0;
6019 int numRunning = 0;
6020 while (pos >= 0 && maxNum > 0) {
6021 final HistoryRecord r = next;
6022 pos--;
6023 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6024
6025 // Initialize state for next task if needed.
6026 if (top == null ||
6027 (top.state == ActivityState.INITIALIZING
6028 && top.task == r.task)) {
6029 top = r;
6030 topDescription = r.description;
6031 curTask = r.task;
6032 numActivities = numRunning = 0;
6033 }
6034
6035 // Add 'r' into the current task.
6036 numActivities++;
6037 if (r.app != null && r.app.thread != null) {
6038 numRunning++;
6039 }
6040 if (topDescription == null) {
6041 topDescription = r.description;
6042 }
6043
6044 if (localLOGV) Log.v(
6045 TAG, r.intent.getComponent().flattenToShortString()
6046 + ": task=" + r.task);
6047
6048 // If the next one is a different task, generate a new
6049 // TaskInfo entry for what we have.
6050 if (next == null || next.task != curTask) {
6051 ActivityManager.RunningTaskInfo ci
6052 = new ActivityManager.RunningTaskInfo();
6053 ci.id = curTask.taskId;
6054 ci.baseActivity = r.intent.getComponent();
6055 ci.topActivity = top.intent.getComponent();
6056 ci.thumbnail = top.thumbnail;
6057 ci.description = topDescription;
6058 ci.numActivities = numActivities;
6059 ci.numRunning = numRunning;
6060 //System.out.println(
6061 // "#" + maxNum + ": " + " descr=" + ci.description);
6062 if (ci.thumbnail == null && receiver != null) {
6063 if (localLOGV) Log.v(
6064 TAG, "State=" + top.state + "Idle=" + top.idle
6065 + " app=" + top.app
6066 + " thr=" + (top.app != null ? top.app.thread : null));
6067 if (top.state == ActivityState.RESUMED
6068 || top.state == ActivityState.PAUSING) {
6069 if (top.idle && top.app != null
6070 && top.app.thread != null) {
6071 topRecord = top;
6072 topThumbnail = top.app.thread;
6073 } else {
6074 top.thumbnailNeeded = true;
6075 }
6076 }
6077 if (pending == null) {
6078 pending = new PendingThumbnailsRecord(receiver);
6079 }
6080 pending.pendingRecords.add(top);
6081 }
6082 list.add(ci);
6083 maxNum--;
6084 top = null;
6085 }
6086 }
6087
6088 if (pending != null) {
6089 mPendingThumbnails.add(pending);
6090 }
6091 }
6092
6093 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6094
6095 if (topThumbnail != null) {
6096 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6097 try {
6098 topThumbnail.requestThumbnail(topRecord);
6099 } catch (Exception e) {
6100 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6101 sendPendingThumbnail(null, topRecord, null, null, true);
6102 }
6103 }
6104
6105 if (pending == null && receiver != null) {
6106 // In this case all thumbnails were available and the client
6107 // is being asked to be told when the remaining ones come in...
6108 // which is unusually, since the top-most currently running
6109 // activity should never have a canned thumbnail! Oh well.
6110 try {
6111 receiver.finished();
6112 } catch (RemoteException ex) {
6113 }
6114 }
6115
6116 return list;
6117 }
6118
6119 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6120 int flags) {
6121 synchronized (this) {
6122 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6123 "getRecentTasks()");
6124
6125 final int N = mRecentTasks.size();
6126 ArrayList<ActivityManager.RecentTaskInfo> res
6127 = new ArrayList<ActivityManager.RecentTaskInfo>(
6128 maxNum < N ? maxNum : N);
6129 for (int i=0; i<N && maxNum > 0; i++) {
6130 TaskRecord tr = mRecentTasks.get(i);
6131 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6132 || (tr.intent == null)
6133 || ((tr.intent.getFlags()
6134 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6135 ActivityManager.RecentTaskInfo rti
6136 = new ActivityManager.RecentTaskInfo();
6137 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6138 rti.baseIntent = new Intent(
6139 tr.intent != null ? tr.intent : tr.affinityIntent);
6140 rti.origActivity = tr.origActivity;
6141 res.add(rti);
6142 maxNum--;
6143 }
6144 }
6145 return res;
6146 }
6147 }
6148
6149 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6150 int j;
6151 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6152 TaskRecord jt = startTask;
6153
6154 // First look backwards
6155 for (j=startIndex-1; j>=0; j--) {
6156 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6157 if (r.task != jt) {
6158 jt = r.task;
6159 if (affinity.equals(jt.affinity)) {
6160 return j;
6161 }
6162 }
6163 }
6164
6165 // Now look forwards
6166 final int N = mHistory.size();
6167 jt = startTask;
6168 for (j=startIndex+1; j<N; j++) {
6169 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6170 if (r.task != jt) {
6171 if (affinity.equals(jt.affinity)) {
6172 return j;
6173 }
6174 jt = r.task;
6175 }
6176 }
6177
6178 // Might it be at the top?
6179 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6180 return N-1;
6181 }
6182
6183 return -1;
6184 }
6185
6186 /**
6187 * Perform a reset of the given task, if needed as part of launching it.
6188 * Returns the new HistoryRecord at the top of the task.
6189 */
6190 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6191 HistoryRecord newActivity) {
6192 boolean forceReset = (newActivity.info.flags
6193 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6194 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6195 if ((newActivity.info.flags
6196 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6197 forceReset = true;
6198 }
6199 }
6200
6201 final TaskRecord task = taskTop.task;
6202
6203 // We are going to move through the history list so that we can look
6204 // at each activity 'target' with 'below' either the interesting
6205 // activity immediately below it in the stack or null.
6206 HistoryRecord target = null;
6207 int targetI = 0;
6208 int taskTopI = -1;
6209 int replyChainEnd = -1;
6210 int lastReparentPos = -1;
6211 for (int i=mHistory.size()-1; i>=-1; i--) {
6212 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6213
6214 if (below != null && below.finishing) {
6215 continue;
6216 }
6217 if (target == null) {
6218 target = below;
6219 targetI = i;
6220 // If we were in the middle of a reply chain before this
6221 // task, it doesn't appear like the root of the chain wants
6222 // anything interesting, so drop it.
6223 replyChainEnd = -1;
6224 continue;
6225 }
6226
6227 final int flags = target.info.flags;
6228
6229 final boolean finishOnTaskLaunch =
6230 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6231 final boolean allowTaskReparenting =
6232 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6233
6234 if (target.task == task) {
6235 // We are inside of the task being reset... we'll either
6236 // finish this activity, push it out for another task,
6237 // or leave it as-is. We only do this
6238 // for activities that are not the root of the task (since
6239 // if we finish the root, we may no longer have the task!).
6240 if (taskTopI < 0) {
6241 taskTopI = targetI;
6242 }
6243 if (below != null && below.task == task) {
6244 final boolean clearWhenTaskReset =
6245 (target.intent.getFlags()
6246 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006247 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006248 // If this activity is sending a reply to a previous
6249 // activity, we can't do anything with it now until
6250 // we reach the start of the reply chain.
6251 // XXX note that we are assuming the result is always
6252 // to the previous activity, which is almost always
6253 // the case but we really shouldn't count on.
6254 if (replyChainEnd < 0) {
6255 replyChainEnd = targetI;
6256 }
Ed Heyl73798232009-03-24 21:32:21 -07006257 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006258 && target.taskAffinity != null
6259 && !target.taskAffinity.equals(task.affinity)) {
6260 // If this activity has an affinity for another
6261 // task, then we need to move it out of here. We will
6262 // move it as far out of the way as possible, to the
6263 // bottom of the activity stack. This also keeps it
6264 // correctly ordered with any activities we previously
6265 // moved.
6266 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6267 if (target.taskAffinity != null
6268 && target.taskAffinity.equals(p.task.affinity)) {
6269 // If the activity currently at the bottom has the
6270 // same task affinity as the one we are moving,
6271 // then merge it into the same task.
6272 target.task = p.task;
6273 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6274 + " out to bottom task " + p.task);
6275 } else {
6276 mCurTask++;
6277 if (mCurTask <= 0) {
6278 mCurTask = 1;
6279 }
6280 target.task = new TaskRecord(mCurTask, target.info, null,
6281 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6282 target.task.affinityIntent = target.intent;
6283 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6284 + " out to new task " + target.task);
6285 }
6286 mWindowManager.setAppGroupId(target, task.taskId);
6287 if (replyChainEnd < 0) {
6288 replyChainEnd = targetI;
6289 }
6290 int dstPos = 0;
6291 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6292 p = (HistoryRecord)mHistory.get(srcPos);
6293 if (p.finishing) {
6294 continue;
6295 }
6296 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6297 + " out to target's task " + target.task);
6298 task.numActivities--;
6299 p.task = target.task;
6300 target.task.numActivities++;
6301 mHistory.remove(srcPos);
6302 mHistory.add(dstPos, p);
6303 mWindowManager.moveAppToken(dstPos, p);
6304 mWindowManager.setAppGroupId(p, p.task.taskId);
6305 dstPos++;
6306 if (VALIDATE_TOKENS) {
6307 mWindowManager.validateAppTokens(mHistory);
6308 }
6309 i++;
6310 }
6311 if (taskTop == p) {
6312 taskTop = below;
6313 }
6314 if (taskTopI == replyChainEnd) {
6315 taskTopI = -1;
6316 }
6317 replyChainEnd = -1;
6318 addRecentTask(target.task);
6319 } else if (forceReset || finishOnTaskLaunch
6320 || clearWhenTaskReset) {
6321 // If the activity should just be removed -- either
6322 // because it asks for it, or the task should be
6323 // cleared -- then finish it and anything that is
6324 // part of its reply chain.
6325 if (clearWhenTaskReset) {
6326 // In this case, we want to finish this activity
6327 // and everything above it, so be sneaky and pretend
6328 // like these are all in the reply chain.
6329 replyChainEnd = targetI+1;
6330 while (replyChainEnd < mHistory.size() &&
6331 ((HistoryRecord)mHistory.get(
6332 replyChainEnd)).task == task) {
6333 replyChainEnd++;
6334 }
6335 replyChainEnd--;
6336 } else if (replyChainEnd < 0) {
6337 replyChainEnd = targetI;
6338 }
6339 HistoryRecord p = null;
6340 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6341 p = (HistoryRecord)mHistory.get(srcPos);
6342 if (p.finishing) {
6343 continue;
6344 }
6345 if (finishActivityLocked(p, srcPos,
6346 Activity.RESULT_CANCELED, null, "reset")) {
6347 replyChainEnd--;
6348 srcPos--;
6349 }
6350 }
6351 if (taskTop == p) {
6352 taskTop = below;
6353 }
6354 if (taskTopI == replyChainEnd) {
6355 taskTopI = -1;
6356 }
6357 replyChainEnd = -1;
6358 } else {
6359 // If we were in the middle of a chain, well the
6360 // activity that started it all doesn't want anything
6361 // special, so leave it all as-is.
6362 replyChainEnd = -1;
6363 }
6364 } else {
6365 // Reached the bottom of the task -- any reply chain
6366 // should be left as-is.
6367 replyChainEnd = -1;
6368 }
6369
6370 } else if (target.resultTo != null) {
6371 // If this activity is sending a reply to a previous
6372 // activity, we can't do anything with it now until
6373 // we reach the start of the reply chain.
6374 // XXX note that we are assuming the result is always
6375 // to the previous activity, which is almost always
6376 // the case but we really shouldn't count on.
6377 if (replyChainEnd < 0) {
6378 replyChainEnd = targetI;
6379 }
6380
6381 } else if (taskTopI >= 0 && allowTaskReparenting
6382 && task.affinity != null
6383 && task.affinity.equals(target.taskAffinity)) {
6384 // We are inside of another task... if this activity has
6385 // an affinity for our task, then either remove it if we are
6386 // clearing or move it over to our task. Note that
6387 // we currently punt on the case where we are resetting a
6388 // task that is not at the top but who has activities above
6389 // with an affinity to it... this is really not a normal
6390 // case, and we will need to later pull that task to the front
6391 // and usually at that point we will do the reset and pick
6392 // up those remaining activities. (This only happens if
6393 // someone starts an activity in a new task from an activity
6394 // in a task that is not currently on top.)
6395 if (forceReset || finishOnTaskLaunch) {
6396 if (replyChainEnd < 0) {
6397 replyChainEnd = targetI;
6398 }
6399 HistoryRecord p = null;
6400 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6401 p = (HistoryRecord)mHistory.get(srcPos);
6402 if (p.finishing) {
6403 continue;
6404 }
6405 if (finishActivityLocked(p, srcPos,
6406 Activity.RESULT_CANCELED, null, "reset")) {
6407 taskTopI--;
6408 lastReparentPos--;
6409 replyChainEnd--;
6410 srcPos--;
6411 }
6412 }
6413 replyChainEnd = -1;
6414 } else {
6415 if (replyChainEnd < 0) {
6416 replyChainEnd = targetI;
6417 }
6418 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6419 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6420 if (p.finishing) {
6421 continue;
6422 }
6423 if (lastReparentPos < 0) {
6424 lastReparentPos = taskTopI;
6425 taskTop = p;
6426 } else {
6427 lastReparentPos--;
6428 }
6429 mHistory.remove(srcPos);
6430 p.task.numActivities--;
6431 p.task = task;
6432 mHistory.add(lastReparentPos, p);
6433 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6434 + " in to resetting task " + task);
6435 task.numActivities++;
6436 mWindowManager.moveAppToken(lastReparentPos, p);
6437 mWindowManager.setAppGroupId(p, p.task.taskId);
6438 if (VALIDATE_TOKENS) {
6439 mWindowManager.validateAppTokens(mHistory);
6440 }
6441 }
6442 replyChainEnd = -1;
6443
6444 // Now we've moved it in to place... but what if this is
6445 // a singleTop activity and we have put it on top of another
6446 // instance of the same activity? Then we drop the instance
6447 // below so it remains singleTop.
6448 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6449 for (int j=lastReparentPos-1; j>=0; j--) {
6450 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6451 if (p.finishing) {
6452 continue;
6453 }
6454 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6455 if (finishActivityLocked(p, j,
6456 Activity.RESULT_CANCELED, null, "replace")) {
6457 taskTopI--;
6458 lastReparentPos--;
6459 }
6460 }
6461 }
6462 }
6463 }
6464 }
6465
6466 target = below;
6467 targetI = i;
6468 }
6469
6470 return taskTop;
6471 }
6472
6473 /**
6474 * TODO: Add mWatcher hook
6475 */
6476 public void moveTaskToFront(int task) {
6477 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6478 "moveTaskToFront()");
6479
6480 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006481 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6482 Binder.getCallingUid(), "Task to front")) {
6483 return;
6484 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006485 final long origId = Binder.clearCallingIdentity();
6486 try {
6487 int N = mRecentTasks.size();
6488 for (int i=0; i<N; i++) {
6489 TaskRecord tr = mRecentTasks.get(i);
6490 if (tr.taskId == task) {
6491 moveTaskToFrontLocked(tr);
6492 return;
6493 }
6494 }
6495 for (int i=mHistory.size()-1; i>=0; i--) {
6496 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6497 if (hr.task.taskId == task) {
6498 moveTaskToFrontLocked(hr.task);
6499 return;
6500 }
6501 }
6502 } finally {
6503 Binder.restoreCallingIdentity(origId);
6504 }
6505 }
6506 }
6507
6508 private final void moveTaskToFrontLocked(TaskRecord tr) {
6509 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6510
6511 final int task = tr.taskId;
6512 int top = mHistory.size()-1;
6513
6514 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6515 // nothing to do!
6516 return;
6517 }
6518
6519 if (DEBUG_TRANSITION) Log.v(TAG,
6520 "Prepare to front transition: task=" + tr);
6521 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6522
6523 ArrayList moved = new ArrayList();
6524
6525 // Applying the affinities may have removed entries from the history,
6526 // so get the size again.
6527 top = mHistory.size()-1;
6528 int pos = top;
6529
6530 // Shift all activities with this task up to the top
6531 // of the stack, keeping them in the same internal order.
6532 while (pos >= 0) {
6533 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6534 if (localLOGV) Log.v(
6535 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6536 boolean first = true;
6537 if (r.task.taskId == task) {
6538 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6539 mHistory.remove(pos);
6540 mHistory.add(top, r);
6541 moved.add(0, r);
6542 top--;
6543 if (first) {
6544 addRecentTask(r.task);
6545 first = false;
6546 }
6547 }
6548 pos--;
6549 }
6550
6551 mWindowManager.moveAppTokensToTop(moved);
6552 if (VALIDATE_TOKENS) {
6553 mWindowManager.validateAppTokens(mHistory);
6554 }
6555
6556 finishTaskMove(task);
6557 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6558 }
6559
6560 private final void finishTaskMove(int task) {
6561 resumeTopActivityLocked(null);
6562 }
6563
6564 public void moveTaskToBack(int task) {
6565 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6566 "moveTaskToBack()");
6567
6568 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006569 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6570 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6571 Binder.getCallingUid(), "Task to back")) {
6572 return;
6573 }
6574 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006575 final long origId = Binder.clearCallingIdentity();
6576 moveTaskToBackLocked(task);
6577 Binder.restoreCallingIdentity(origId);
6578 }
6579 }
6580
6581 /**
6582 * Moves an activity, and all of the other activities within the same task, to the bottom
6583 * of the history stack. The activity's order within the task is unchanged.
6584 *
6585 * @param token A reference to the activity we wish to move
6586 * @param nonRoot If false then this only works if the activity is the root
6587 * of a task; if true it will work for any activity in a task.
6588 * @return Returns true if the move completed, false if not.
6589 */
6590 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6591 synchronized(this) {
6592 final long origId = Binder.clearCallingIdentity();
6593 int taskId = getTaskForActivityLocked(token, !nonRoot);
6594 if (taskId >= 0) {
6595 return moveTaskToBackLocked(taskId);
6596 }
6597 Binder.restoreCallingIdentity(origId);
6598 }
6599 return false;
6600 }
6601
6602 /**
6603 * Worker method for rearranging history stack. Implements the function of moving all
6604 * activities for a specific task (gathering them if disjoint) into a single group at the
6605 * bottom of the stack.
6606 *
6607 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6608 * to premeptively cancel the move.
6609 *
6610 * @param task The taskId to collect and move to the bottom.
6611 * @return Returns true if the move completed, false if not.
6612 */
6613 private final boolean moveTaskToBackLocked(int task) {
6614 Log.i(TAG, "moveTaskToBack: " + task);
6615
6616 // If we have a watcher, preflight the move before committing to it. First check
6617 // for *other* available tasks, but if none are available, then try again allowing the
6618 // current task to be selected.
6619 if (mWatcher != null) {
6620 HistoryRecord next = topRunningActivityLocked(null, task);
6621 if (next == null) {
6622 next = topRunningActivityLocked(null, 0);
6623 }
6624 if (next != null) {
6625 // ask watcher if this is allowed
6626 boolean moveOK = true;
6627 try {
6628 moveOK = mWatcher.activityResuming(next.packageName);
6629 } catch (RemoteException e) {
6630 mWatcher = null;
6631 }
6632 if (!moveOK) {
6633 return false;
6634 }
6635 }
6636 }
6637
6638 ArrayList moved = new ArrayList();
6639
6640 if (DEBUG_TRANSITION) Log.v(TAG,
6641 "Prepare to back transition: task=" + task);
6642 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6643
6644 final int N = mHistory.size();
6645 int bottom = 0;
6646 int pos = 0;
6647
6648 // Shift all activities with this task down to the bottom
6649 // of the stack, keeping them in the same internal order.
6650 while (pos < N) {
6651 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6652 if (localLOGV) Log.v(
6653 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6654 if (r.task.taskId == task) {
6655 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6656 mHistory.remove(pos);
6657 mHistory.add(bottom, r);
6658 moved.add(r);
6659 bottom++;
6660 }
6661 pos++;
6662 }
6663
6664 mWindowManager.moveAppTokensToBottom(moved);
6665 if (VALIDATE_TOKENS) {
6666 mWindowManager.validateAppTokens(mHistory);
6667 }
6668
6669 finishTaskMove(task);
6670 return true;
6671 }
6672
6673 public void moveTaskBackwards(int task) {
6674 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6675 "moveTaskBackwards()");
6676
6677 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006678 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6679 Binder.getCallingUid(), "Task backwards")) {
6680 return;
6681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006682 final long origId = Binder.clearCallingIdentity();
6683 moveTaskBackwardsLocked(task);
6684 Binder.restoreCallingIdentity(origId);
6685 }
6686 }
6687
6688 private final void moveTaskBackwardsLocked(int task) {
6689 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6690 }
6691
6692 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6693 synchronized(this) {
6694 return getTaskForActivityLocked(token, onlyRoot);
6695 }
6696 }
6697
6698 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6699 final int N = mHistory.size();
6700 TaskRecord lastTask = null;
6701 for (int i=0; i<N; i++) {
6702 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6703 if (r == token) {
6704 if (!onlyRoot || lastTask != r.task) {
6705 return r.task.taskId;
6706 }
6707 return -1;
6708 }
6709 lastTask = r.task;
6710 }
6711
6712 return -1;
6713 }
6714
6715 /**
6716 * Returns the top activity in any existing task matching the given
6717 * Intent. Returns null if no such task is found.
6718 */
6719 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6720 ComponentName cls = intent.getComponent();
6721 if (info.targetActivity != null) {
6722 cls = new ComponentName(info.packageName, info.targetActivity);
6723 }
6724
6725 TaskRecord cp = null;
6726
6727 final int N = mHistory.size();
6728 for (int i=(N-1); i>=0; i--) {
6729 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6730 if (!r.finishing && r.task != cp
6731 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6732 cp = r.task;
6733 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6734 // + "/aff=" + r.task.affinity + " to new cls="
6735 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6736 if (r.task.affinity != null) {
6737 if (r.task.affinity.equals(info.taskAffinity)) {
6738 //Log.i(TAG, "Found matching affinity!");
6739 return r;
6740 }
6741 } else if (r.task.intent != null
6742 && r.task.intent.getComponent().equals(cls)) {
6743 //Log.i(TAG, "Found matching class!");
6744 //dump();
6745 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6746 return r;
6747 } else if (r.task.affinityIntent != null
6748 && r.task.affinityIntent.getComponent().equals(cls)) {
6749 //Log.i(TAG, "Found matching class!");
6750 //dump();
6751 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6752 return r;
6753 }
6754 }
6755 }
6756
6757 return null;
6758 }
6759
6760 /**
6761 * Returns the first activity (starting from the top of the stack) that
6762 * is the same as the given activity. Returns null if no such activity
6763 * is found.
6764 */
6765 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6766 ComponentName cls = intent.getComponent();
6767 if (info.targetActivity != null) {
6768 cls = new ComponentName(info.packageName, info.targetActivity);
6769 }
6770
6771 final int N = mHistory.size();
6772 for (int i=(N-1); i>=0; i--) {
6773 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6774 if (!r.finishing) {
6775 if (r.intent.getComponent().equals(cls)) {
6776 //Log.i(TAG, "Found matching class!");
6777 //dump();
6778 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6779 return r;
6780 }
6781 }
6782 }
6783
6784 return null;
6785 }
6786
6787 public void finishOtherInstances(IBinder token, ComponentName className) {
6788 synchronized(this) {
6789 final long origId = Binder.clearCallingIdentity();
6790
6791 int N = mHistory.size();
6792 TaskRecord lastTask = null;
6793 for (int i=0; i<N; i++) {
6794 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6795 if (r.realActivity.equals(className)
6796 && r != token && lastTask != r.task) {
6797 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6798 null, "others")) {
6799 i--;
6800 N--;
6801 }
6802 }
6803 lastTask = r.task;
6804 }
6805
6806 Binder.restoreCallingIdentity(origId);
6807 }
6808 }
6809
6810 // =========================================================
6811 // THUMBNAILS
6812 // =========================================================
6813
6814 public void reportThumbnail(IBinder token,
6815 Bitmap thumbnail, CharSequence description) {
6816 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6817 final long origId = Binder.clearCallingIdentity();
6818 sendPendingThumbnail(null, token, thumbnail, description, true);
6819 Binder.restoreCallingIdentity(origId);
6820 }
6821
6822 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6823 Bitmap thumbnail, CharSequence description, boolean always) {
6824 TaskRecord task = null;
6825 ArrayList receivers = null;
6826
6827 //System.out.println("Send pending thumbnail: " + r);
6828
6829 synchronized(this) {
6830 if (r == null) {
6831 int index = indexOfTokenLocked(token, false);
6832 if (index < 0) {
6833 return;
6834 }
6835 r = (HistoryRecord)mHistory.get(index);
6836 }
6837 if (thumbnail == null) {
6838 thumbnail = r.thumbnail;
6839 description = r.description;
6840 }
6841 if (thumbnail == null && !always) {
6842 // If there is no thumbnail, and this entry is not actually
6843 // going away, then abort for now and pick up the next
6844 // thumbnail we get.
6845 return;
6846 }
6847 task = r.task;
6848
6849 int N = mPendingThumbnails.size();
6850 int i=0;
6851 while (i<N) {
6852 PendingThumbnailsRecord pr =
6853 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6854 //System.out.println("Looking in " + pr.pendingRecords);
6855 if (pr.pendingRecords.remove(r)) {
6856 if (receivers == null) {
6857 receivers = new ArrayList();
6858 }
6859 receivers.add(pr);
6860 if (pr.pendingRecords.size() == 0) {
6861 pr.finished = true;
6862 mPendingThumbnails.remove(i);
6863 N--;
6864 continue;
6865 }
6866 }
6867 i++;
6868 }
6869 }
6870
6871 if (receivers != null) {
6872 final int N = receivers.size();
6873 for (int i=0; i<N; i++) {
6874 try {
6875 PendingThumbnailsRecord pr =
6876 (PendingThumbnailsRecord)receivers.get(i);
6877 pr.receiver.newThumbnail(
6878 task != null ? task.taskId : -1, thumbnail, description);
6879 if (pr.finished) {
6880 pr.receiver.finished();
6881 }
6882 } catch (Exception e) {
6883 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6884 }
6885 }
6886 }
6887 }
6888
6889 // =========================================================
6890 // CONTENT PROVIDERS
6891 // =========================================================
6892
6893 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6894 List providers = null;
6895 try {
6896 providers = ActivityThread.getPackageManager().
6897 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006898 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006899 } catch (RemoteException ex) {
6900 }
6901 if (providers != null) {
6902 final int N = providers.size();
6903 for (int i=0; i<N; i++) {
6904 ProviderInfo cpi =
6905 (ProviderInfo)providers.get(i);
6906 ContentProviderRecord cpr =
6907 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6908 if (cpr == null) {
6909 cpr = new ContentProviderRecord(cpi, app.info);
6910 mProvidersByClass.put(cpi.name, cpr);
6911 }
6912 app.pubProviders.put(cpi.name, cpr);
6913 app.addPackage(cpi.applicationInfo.packageName);
6914 }
6915 }
6916 return providers;
6917 }
6918
6919 private final String checkContentProviderPermissionLocked(
6920 ProviderInfo cpi, ProcessRecord r, int mode) {
6921 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6922 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6923 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6924 cpi.exported ? -1 : cpi.applicationInfo.uid)
6925 == PackageManager.PERMISSION_GRANTED
6926 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6927 return null;
6928 }
6929 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6930 cpi.exported ? -1 : cpi.applicationInfo.uid)
6931 == PackageManager.PERMISSION_GRANTED) {
6932 return null;
6933 }
6934 String msg = "Permission Denial: opening provider " + cpi.name
6935 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
6936 + ", uid=" + callingUid + ") requires "
6937 + cpi.readPermission + " or " + cpi.writePermission;
6938 Log.w(TAG, msg);
6939 return msg;
6940 }
6941
6942 private final ContentProviderHolder getContentProviderImpl(
6943 IApplicationThread caller, String name) {
6944 ContentProviderRecord cpr;
6945 ProviderInfo cpi = null;
6946
6947 synchronized(this) {
6948 ProcessRecord r = null;
6949 if (caller != null) {
6950 r = getRecordForAppLocked(caller);
6951 if (r == null) {
6952 throw new SecurityException(
6953 "Unable to find app for caller " + caller
6954 + " (pid=" + Binder.getCallingPid()
6955 + ") when getting content provider " + name);
6956 }
6957 }
6958
6959 // First check if this content provider has been published...
6960 cpr = (ContentProviderRecord)mProvidersByName.get(name);
6961 if (cpr != null) {
6962 cpi = cpr.info;
6963 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6964 return new ContentProviderHolder(cpi,
6965 cpi.readPermission != null
6966 ? cpi.readPermission : cpi.writePermission);
6967 }
6968
6969 if (r != null && cpr.canRunHere(r)) {
6970 // This provider has been published or is in the process
6971 // of being published... but it is also allowed to run
6972 // in the caller's process, so don't make a connection
6973 // and just let the caller instantiate its own instance.
6974 if (cpr.provider != null) {
6975 // don't give caller the provider object, it needs
6976 // to make its own.
6977 cpr = new ContentProviderRecord(cpr);
6978 }
6979 return cpr;
6980 }
6981
6982 final long origId = Binder.clearCallingIdentity();
6983
6984 // In this case the provider is a single instance, so we can
6985 // return it right away.
6986 if (r != null) {
6987 r.conProviders.add(cpr);
6988 cpr.clients.add(r);
6989 } else {
6990 cpr.externals++;
6991 }
6992
6993 if (cpr.app != null) {
6994 updateOomAdjLocked(cpr.app);
6995 }
6996
6997 Binder.restoreCallingIdentity(origId);
6998
6999 } else {
7000 try {
7001 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007002 resolveContentProvider(name,
7003 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007004 } catch (RemoteException ex) {
7005 }
7006 if (cpi == null) {
7007 return null;
7008 }
7009
7010 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7011 return new ContentProviderHolder(cpi,
7012 cpi.readPermission != null
7013 ? cpi.readPermission : cpi.writePermission);
7014 }
7015
7016 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7017 final boolean firstClass = cpr == null;
7018 if (firstClass) {
7019 try {
7020 ApplicationInfo ai =
7021 ActivityThread.getPackageManager().
7022 getApplicationInfo(
7023 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007024 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007025 if (ai == null) {
7026 Log.w(TAG, "No package info for content provider "
7027 + cpi.name);
7028 return null;
7029 }
7030 cpr = new ContentProviderRecord(cpi, ai);
7031 } catch (RemoteException ex) {
7032 // pm is in same process, this will never happen.
7033 }
7034 }
7035
7036 if (r != null && cpr.canRunHere(r)) {
7037 // If this is a multiprocess provider, then just return its
7038 // info and allow the caller to instantiate it. Only do
7039 // this if the provider is the same user as the caller's
7040 // process, or can run as root (so can be in any process).
7041 return cpr;
7042 }
7043
7044 if (false) {
7045 RuntimeException e = new RuntimeException("foo");
7046 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7047 // + " pruid " + ai.uid + "): " + cpi.className, e);
7048 }
7049
7050 // This is single process, and our app is now connecting to it.
7051 // See if we are already in the process of launching this
7052 // provider.
7053 final int N = mLaunchingProviders.size();
7054 int i;
7055 for (i=0; i<N; i++) {
7056 if (mLaunchingProviders.get(i) == cpr) {
7057 break;
7058 }
7059 if (false) {
7060 final ContentProviderRecord rec =
7061 (ContentProviderRecord)mLaunchingProviders.get(i);
7062 if (rec.info.name.equals(cpr.info.name)) {
7063 cpr = rec;
7064 break;
7065 }
7066 }
7067 }
7068
7069 // If the provider is not already being launched, then get it
7070 // started.
7071 if (i >= N) {
7072 final long origId = Binder.clearCallingIdentity();
7073 ProcessRecord proc = startProcessLocked(cpi.processName,
7074 cpr.appInfo, false, 0, "content provider",
7075 new ComponentName(cpi.applicationInfo.packageName,
7076 cpi.name));
7077 if (proc == null) {
7078 Log.w(TAG, "Unable to launch app "
7079 + cpi.applicationInfo.packageName + "/"
7080 + cpi.applicationInfo.uid + " for provider "
7081 + name + ": process is bad");
7082 return null;
7083 }
7084 cpr.launchingApp = proc;
7085 mLaunchingProviders.add(cpr);
7086 Binder.restoreCallingIdentity(origId);
7087 }
7088
7089 // Make sure the provider is published (the same provider class
7090 // may be published under multiple names).
7091 if (firstClass) {
7092 mProvidersByClass.put(cpi.name, cpr);
7093 }
7094 mProvidersByName.put(name, cpr);
7095
7096 if (r != null) {
7097 r.conProviders.add(cpr);
7098 cpr.clients.add(r);
7099 } else {
7100 cpr.externals++;
7101 }
7102 }
7103 }
7104
7105 // Wait for the provider to be published...
7106 synchronized (cpr) {
7107 while (cpr.provider == null) {
7108 if (cpr.launchingApp == null) {
7109 Log.w(TAG, "Unable to launch app "
7110 + cpi.applicationInfo.packageName + "/"
7111 + cpi.applicationInfo.uid + " for provider "
7112 + name + ": launching app became null");
7113 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7114 cpi.applicationInfo.packageName,
7115 cpi.applicationInfo.uid, name);
7116 return null;
7117 }
7118 try {
7119 cpr.wait();
7120 } catch (InterruptedException ex) {
7121 }
7122 }
7123 }
7124 return cpr;
7125 }
7126
7127 public final ContentProviderHolder getContentProvider(
7128 IApplicationThread caller, String name) {
7129 if (caller == null) {
7130 String msg = "null IApplicationThread when getting content provider "
7131 + name;
7132 Log.w(TAG, msg);
7133 throw new SecurityException(msg);
7134 }
7135
7136 return getContentProviderImpl(caller, name);
7137 }
7138
7139 private ContentProviderHolder getContentProviderExternal(String name) {
7140 return getContentProviderImpl(null, name);
7141 }
7142
7143 /**
7144 * Drop a content provider from a ProcessRecord's bookkeeping
7145 * @param cpr
7146 */
7147 public void removeContentProvider(IApplicationThread caller, String name) {
7148 synchronized (this) {
7149 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7150 if(cpr == null) {
7151 //remove from mProvidersByClass
7152 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7153 return;
7154 }
7155 final ProcessRecord r = getRecordForAppLocked(caller);
7156 if (r == null) {
7157 throw new SecurityException(
7158 "Unable to find app for caller " + caller +
7159 " when removing content provider " + name);
7160 }
7161 //update content provider record entry info
7162 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7163 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7164 r.info.processName+" from process "+localCpr.appInfo.processName);
7165 if(localCpr.appInfo.processName == r.info.processName) {
7166 //should not happen. taken care of as a local provider
7167 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7168 return;
7169 } else {
7170 localCpr.clients.remove(r);
7171 r.conProviders.remove(localCpr);
7172 }
7173 updateOomAdjLocked();
7174 }
7175 }
7176
7177 private void removeContentProviderExternal(String name) {
7178 synchronized (this) {
7179 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7180 if(cpr == null) {
7181 //remove from mProvidersByClass
7182 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7183 return;
7184 }
7185
7186 //update content provider record entry info
7187 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7188 localCpr.externals--;
7189 if (localCpr.externals < 0) {
7190 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7191 }
7192 updateOomAdjLocked();
7193 }
7194 }
7195
7196 public final void publishContentProviders(IApplicationThread caller,
7197 List<ContentProviderHolder> providers) {
7198 if (providers == null) {
7199 return;
7200 }
7201
7202 synchronized(this) {
7203 final ProcessRecord r = getRecordForAppLocked(caller);
7204 if (r == null) {
7205 throw new SecurityException(
7206 "Unable to find app for caller " + caller
7207 + " (pid=" + Binder.getCallingPid()
7208 + ") when publishing content providers");
7209 }
7210
7211 final long origId = Binder.clearCallingIdentity();
7212
7213 final int N = providers.size();
7214 for (int i=0; i<N; i++) {
7215 ContentProviderHolder src = providers.get(i);
7216 if (src == null || src.info == null || src.provider == null) {
7217 continue;
7218 }
7219 ContentProviderRecord dst =
7220 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7221 if (dst != null) {
7222 mProvidersByClass.put(dst.info.name, dst);
7223 String names[] = dst.info.authority.split(";");
7224 for (int j = 0; j < names.length; j++) {
7225 mProvidersByName.put(names[j], dst);
7226 }
7227
7228 int NL = mLaunchingProviders.size();
7229 int j;
7230 for (j=0; j<NL; j++) {
7231 if (mLaunchingProviders.get(j) == dst) {
7232 mLaunchingProviders.remove(j);
7233 j--;
7234 NL--;
7235 }
7236 }
7237 synchronized (dst) {
7238 dst.provider = src.provider;
7239 dst.app = r;
7240 dst.notifyAll();
7241 }
7242 updateOomAdjLocked(r);
7243 }
7244 }
7245
7246 Binder.restoreCallingIdentity(origId);
7247 }
7248 }
7249
7250 public static final void installSystemProviders() {
7251 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7252 List providers = mSelf.generateApplicationProvidersLocked(app);
7253 mSystemThread.installSystemProviders(providers);
7254 }
7255
7256 // =========================================================
7257 // GLOBAL MANAGEMENT
7258 // =========================================================
7259
7260 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7261 ApplicationInfo info, String customProcess) {
7262 String proc = customProcess != null ? customProcess : info.processName;
7263 BatteryStatsImpl.Uid.Proc ps = null;
7264 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7265 synchronized (stats) {
7266 ps = stats.getProcessStatsLocked(info.uid, proc);
7267 }
7268 return new ProcessRecord(ps, thread, info, proc);
7269 }
7270
7271 final ProcessRecord addAppLocked(ApplicationInfo info) {
7272 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7273
7274 if (app == null) {
7275 app = newProcessRecordLocked(null, info, null);
7276 mProcessNames.put(info.processName, info.uid, app);
7277 updateLRUListLocked(app, true);
7278 }
7279
7280 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7281 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7282 app.persistent = true;
7283 app.maxAdj = CORE_SERVER_ADJ;
7284 }
7285 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7286 mPersistentStartingProcesses.add(app);
7287 startProcessLocked(app, "added application", app.processName);
7288 }
7289
7290 return app;
7291 }
7292
7293 public void unhandledBack() {
7294 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7295 "unhandledBack()");
7296
7297 synchronized(this) {
7298 int count = mHistory.size();
7299 if (Config.LOGD) Log.d(
7300 TAG, "Performing unhandledBack(): stack size = " + count);
7301 if (count > 1) {
7302 final long origId = Binder.clearCallingIdentity();
7303 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7304 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7305 Binder.restoreCallingIdentity(origId);
7306 }
7307 }
7308 }
7309
7310 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7311 String name = uri.getAuthority();
7312 ContentProviderHolder cph = getContentProviderExternal(name);
7313 ParcelFileDescriptor pfd = null;
7314 if (cph != null) {
7315 // We record the binder invoker's uid in thread-local storage before
7316 // going to the content provider to open the file. Later, in the code
7317 // that handles all permissions checks, we look for this uid and use
7318 // that rather than the Activity Manager's own uid. The effect is that
7319 // we do the check against the caller's permissions even though it looks
7320 // to the content provider like the Activity Manager itself is making
7321 // the request.
7322 sCallerIdentity.set(new Identity(
7323 Binder.getCallingPid(), Binder.getCallingUid()));
7324 try {
7325 pfd = cph.provider.openFile(uri, "r");
7326 } catch (FileNotFoundException e) {
7327 // do nothing; pfd will be returned null
7328 } finally {
7329 // Ensure that whatever happens, we clean up the identity state
7330 sCallerIdentity.remove();
7331 }
7332
7333 // We've got the fd now, so we're done with the provider.
7334 removeContentProviderExternal(name);
7335 } else {
7336 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7337 }
7338 return pfd;
7339 }
7340
7341 public void goingToSleep() {
7342 synchronized(this) {
7343 mSleeping = true;
7344 mWindowManager.setEventDispatching(false);
7345
7346 if (mResumedActivity != null) {
7347 pauseIfSleepingLocked();
7348 } else {
7349 Log.w(TAG, "goingToSleep with no resumed activity!");
7350 }
7351 }
7352 }
7353
Dianne Hackborn55280a92009-05-07 15:53:46 -07007354 public boolean shutdown(int timeout) {
7355 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7356 != PackageManager.PERMISSION_GRANTED) {
7357 throw new SecurityException("Requires permission "
7358 + android.Manifest.permission.SHUTDOWN);
7359 }
7360
7361 boolean timedout = false;
7362
7363 synchronized(this) {
7364 mShuttingDown = true;
7365 mWindowManager.setEventDispatching(false);
7366
7367 if (mResumedActivity != null) {
7368 pauseIfSleepingLocked();
7369 final long endTime = System.currentTimeMillis() + timeout;
7370 while (mResumedActivity != null || mPausingActivity != null) {
7371 long delay = endTime - System.currentTimeMillis();
7372 if (delay <= 0) {
7373 Log.w(TAG, "Activity manager shutdown timed out");
7374 timedout = true;
7375 break;
7376 }
7377 try {
7378 this.wait();
7379 } catch (InterruptedException e) {
7380 }
7381 }
7382 }
7383 }
7384
7385 mUsageStatsService.shutdown();
7386 mBatteryStatsService.shutdown();
7387
7388 return timedout;
7389 }
7390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007391 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007392 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007393 if (!mGoingToSleep.isHeld()) {
7394 mGoingToSleep.acquire();
7395 if (mLaunchingActivity.isHeld()) {
7396 mLaunchingActivity.release();
7397 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7398 }
7399 }
7400
7401 // If we are not currently pausing an activity, get the current
7402 // one to pause. If we are pausing one, we will just let that stuff
7403 // run and release the wake lock when all done.
7404 if (mPausingActivity == null) {
7405 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7406 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7407 startPausingLocked(false, true);
7408 }
7409 }
7410 }
7411
7412 public void wakingUp() {
7413 synchronized(this) {
7414 if (mGoingToSleep.isHeld()) {
7415 mGoingToSleep.release();
7416 }
7417 mWindowManager.setEventDispatching(true);
7418 mSleeping = false;
7419 resumeTopActivityLocked(null);
7420 }
7421 }
7422
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007423 public void stopAppSwitches() {
7424 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7425 != PackageManager.PERMISSION_GRANTED) {
7426 throw new SecurityException("Requires permission "
7427 + android.Manifest.permission.STOP_APP_SWITCHES);
7428 }
7429
7430 synchronized(this) {
7431 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7432 + APP_SWITCH_DELAY_TIME;
7433 mDidAppSwitch = false;
7434 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7435 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7436 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7437 }
7438 }
7439
7440 public void resumeAppSwitches() {
7441 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7442 != PackageManager.PERMISSION_GRANTED) {
7443 throw new SecurityException("Requires permission "
7444 + android.Manifest.permission.STOP_APP_SWITCHES);
7445 }
7446
7447 synchronized(this) {
7448 // Note that we don't execute any pending app switches... we will
7449 // let those wait until either the timeout, or the next start
7450 // activity request.
7451 mAppSwitchesAllowedTime = 0;
7452 }
7453 }
7454
7455 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7456 String name) {
7457 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7458 return true;
7459 }
7460
7461 final int perm = checkComponentPermission(
7462 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7463 callingUid, -1);
7464 if (perm == PackageManager.PERMISSION_GRANTED) {
7465 return true;
7466 }
7467
7468 Log.w(TAG, name + " request from " + callingUid + " stopped");
7469 return false;
7470 }
7471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007472 public void setDebugApp(String packageName, boolean waitForDebugger,
7473 boolean persistent) {
7474 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7475 "setDebugApp()");
7476
7477 // Note that this is not really thread safe if there are multiple
7478 // callers into it at the same time, but that's not a situation we
7479 // care about.
7480 if (persistent) {
7481 final ContentResolver resolver = mContext.getContentResolver();
7482 Settings.System.putString(
7483 resolver, Settings.System.DEBUG_APP,
7484 packageName);
7485 Settings.System.putInt(
7486 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7487 waitForDebugger ? 1 : 0);
7488 }
7489
7490 synchronized (this) {
7491 if (!persistent) {
7492 mOrigDebugApp = mDebugApp;
7493 mOrigWaitForDebugger = mWaitForDebugger;
7494 }
7495 mDebugApp = packageName;
7496 mWaitForDebugger = waitForDebugger;
7497 mDebugTransient = !persistent;
7498 if (packageName != null) {
7499 final long origId = Binder.clearCallingIdentity();
7500 uninstallPackageLocked(packageName, -1, false);
7501 Binder.restoreCallingIdentity(origId);
7502 }
7503 }
7504 }
7505
7506 public void setAlwaysFinish(boolean enabled) {
7507 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7508 "setAlwaysFinish()");
7509
7510 Settings.System.putInt(
7511 mContext.getContentResolver(),
7512 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7513
7514 synchronized (this) {
7515 mAlwaysFinishActivities = enabled;
7516 }
7517 }
7518
7519 public void setActivityWatcher(IActivityWatcher watcher) {
7520 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7521 "setActivityWatcher()");
7522 synchronized (this) {
7523 mWatcher = watcher;
7524 }
7525 }
7526
7527 public final void enterSafeMode() {
7528 synchronized(this) {
7529 // It only makes sense to do this before the system is ready
7530 // and started launching other packages.
7531 if (!mSystemReady) {
7532 try {
7533 ActivityThread.getPackageManager().enterSafeMode();
7534 } catch (RemoteException e) {
7535 }
7536
7537 View v = LayoutInflater.from(mContext).inflate(
7538 com.android.internal.R.layout.safe_mode, null);
7539 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7540 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7541 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7542 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7543 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7544 lp.format = v.getBackground().getOpacity();
7545 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7546 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7547 ((WindowManager)mContext.getSystemService(
7548 Context.WINDOW_SERVICE)).addView(v, lp);
7549 }
7550 }
7551 }
7552
7553 public void noteWakeupAlarm(IIntentSender sender) {
7554 if (!(sender instanceof PendingIntentRecord)) {
7555 return;
7556 }
7557 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7558 synchronized (stats) {
7559 if (mBatteryStatsService.isOnBattery()) {
7560 mBatteryStatsService.enforceCallingPermission();
7561 PendingIntentRecord rec = (PendingIntentRecord)sender;
7562 int MY_UID = Binder.getCallingUid();
7563 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7564 BatteryStatsImpl.Uid.Pkg pkg =
7565 stats.getPackageStatsLocked(uid, rec.key.packageName);
7566 pkg.incWakeupsLocked();
7567 }
7568 }
7569 }
7570
7571 public boolean killPidsForMemory(int[] pids) {
7572 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7573 throw new SecurityException("killPidsForMemory only available to the system");
7574 }
7575
7576 // XXX Note: don't acquire main activity lock here, because the window
7577 // manager calls in with its locks held.
7578
7579 boolean killed = false;
7580 synchronized (mPidsSelfLocked) {
7581 int[] types = new int[pids.length];
7582 int worstType = 0;
7583 for (int i=0; i<pids.length; i++) {
7584 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7585 if (proc != null) {
7586 int type = proc.setAdj;
7587 types[i] = type;
7588 if (type > worstType) {
7589 worstType = type;
7590 }
7591 }
7592 }
7593
7594 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7595 // then constrain it so we will kill all hidden procs.
7596 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7597 worstType = HIDDEN_APP_MIN_ADJ;
7598 }
7599 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7600 for (int i=0; i<pids.length; i++) {
7601 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7602 if (proc == null) {
7603 continue;
7604 }
7605 int adj = proc.setAdj;
7606 if (adj >= worstType) {
7607 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7608 + adj + ")");
7609 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7610 proc.processName, adj);
7611 killed = true;
7612 Process.killProcess(pids[i]);
7613 }
7614 }
7615 }
7616 return killed;
7617 }
7618
7619 public void reportPss(IApplicationThread caller, int pss) {
7620 Watchdog.PssRequestor req;
7621 String name;
7622 ProcessRecord callerApp;
7623 synchronized (this) {
7624 if (caller == null) {
7625 return;
7626 }
7627 callerApp = getRecordForAppLocked(caller);
7628 if (callerApp == null) {
7629 return;
7630 }
7631 callerApp.lastPss = pss;
7632 req = callerApp;
7633 name = callerApp.processName;
7634 }
7635 Watchdog.getInstance().reportPss(req, name, pss);
7636 if (!callerApp.persistent) {
7637 removeRequestedPss(callerApp);
7638 }
7639 }
7640
7641 public void requestPss(Runnable completeCallback) {
7642 ArrayList<ProcessRecord> procs;
7643 synchronized (this) {
7644 mRequestPssCallback = completeCallback;
7645 mRequestPssList.clear();
7646 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7647 ProcessRecord proc = mLRUProcesses.get(i);
7648 if (!proc.persistent) {
7649 mRequestPssList.add(proc);
7650 }
7651 }
7652 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7653 }
7654
7655 int oldPri = Process.getThreadPriority(Process.myTid());
7656 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7657 for (int i=procs.size()-1; i>=0; i--) {
7658 ProcessRecord proc = procs.get(i);
7659 proc.lastPss = 0;
7660 proc.requestPss();
7661 }
7662 Process.setThreadPriority(oldPri);
7663 }
7664
7665 void removeRequestedPss(ProcessRecord proc) {
7666 Runnable callback = null;
7667 synchronized (this) {
7668 if (mRequestPssList.remove(proc)) {
7669 if (mRequestPssList.size() == 0) {
7670 callback = mRequestPssCallback;
7671 mRequestPssCallback = null;
7672 }
7673 }
7674 }
7675
7676 if (callback != null) {
7677 callback.run();
7678 }
7679 }
7680
7681 public void collectPss(Watchdog.PssStats stats) {
7682 stats.mEmptyPss = 0;
7683 stats.mEmptyCount = 0;
7684 stats.mBackgroundPss = 0;
7685 stats.mBackgroundCount = 0;
7686 stats.mServicePss = 0;
7687 stats.mServiceCount = 0;
7688 stats.mVisiblePss = 0;
7689 stats.mVisibleCount = 0;
7690 stats.mForegroundPss = 0;
7691 stats.mForegroundCount = 0;
7692 stats.mNoPssCount = 0;
7693 synchronized (this) {
7694 int i;
7695 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7696 ? mProcDeaths.length : stats.mProcDeaths.length;
7697 int aggr = 0;
7698 for (i=0; i<NPD; i++) {
7699 aggr += mProcDeaths[i];
7700 stats.mProcDeaths[i] = aggr;
7701 }
7702 while (i<stats.mProcDeaths.length) {
7703 stats.mProcDeaths[i] = 0;
7704 i++;
7705 }
7706
7707 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7708 ProcessRecord proc = mLRUProcesses.get(i);
7709 if (proc.persistent) {
7710 continue;
7711 }
7712 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7713 if (proc.lastPss == 0) {
7714 stats.mNoPssCount++;
7715 continue;
7716 }
7717 if (proc.setAdj == EMPTY_APP_ADJ) {
7718 stats.mEmptyPss += proc.lastPss;
7719 stats.mEmptyCount++;
7720 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7721 stats.mEmptyPss += proc.lastPss;
7722 stats.mEmptyCount++;
7723 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7724 stats.mBackgroundPss += proc.lastPss;
7725 stats.mBackgroundCount++;
7726 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7727 stats.mVisiblePss += proc.lastPss;
7728 stats.mVisibleCount++;
7729 } else {
7730 stats.mForegroundPss += proc.lastPss;
7731 stats.mForegroundCount++;
7732 }
7733 }
7734 }
7735 }
7736
7737 public final void startRunning(String pkg, String cls, String action,
7738 String data) {
7739 synchronized(this) {
7740 if (mStartRunning) {
7741 return;
7742 }
7743 mStartRunning = true;
7744 mTopComponent = pkg != null && cls != null
7745 ? new ComponentName(pkg, cls) : null;
7746 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7747 mTopData = data;
7748 if (!mSystemReady) {
7749 return;
7750 }
7751 }
7752
7753 systemReady();
7754 }
7755
7756 private void retrieveSettings() {
7757 final ContentResolver resolver = mContext.getContentResolver();
7758 String debugApp = Settings.System.getString(
7759 resolver, Settings.System.DEBUG_APP);
7760 boolean waitForDebugger = Settings.System.getInt(
7761 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7762 boolean alwaysFinishActivities = Settings.System.getInt(
7763 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7764
7765 Configuration configuration = new Configuration();
7766 Settings.System.getConfiguration(resolver, configuration);
7767
7768 synchronized (this) {
7769 mDebugApp = mOrigDebugApp = debugApp;
7770 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7771 mAlwaysFinishActivities = alwaysFinishActivities;
7772 // This happens before any activities are started, so we can
7773 // change mConfiguration in-place.
7774 mConfiguration.updateFrom(configuration);
7775 }
7776 }
7777
7778 public boolean testIsSystemReady() {
7779 // no need to synchronize(this) just to read & return the value
7780 return mSystemReady;
7781 }
7782
7783 public void systemReady() {
7784 // In the simulator, startRunning will never have been called, which
7785 // normally sets a few crucial variables. Do it here instead.
7786 if (!Process.supportsProcesses()) {
7787 mStartRunning = true;
7788 mTopAction = Intent.ACTION_MAIN;
7789 }
7790
7791 synchronized(this) {
7792 if (mSystemReady) {
7793 return;
7794 }
7795 mSystemReady = true;
7796 if (!mStartRunning) {
7797 return;
7798 }
7799 }
7800
7801 if (Config.LOGD) Log.d(TAG, "Start running!");
7802 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7803 SystemClock.uptimeMillis());
7804
7805 synchronized(this) {
7806 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7807 ResolveInfo ri = mContext.getPackageManager()
7808 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007809 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007810 CharSequence errorMsg = null;
7811 if (ri != null) {
7812 ActivityInfo ai = ri.activityInfo;
7813 ApplicationInfo app = ai.applicationInfo;
7814 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7815 mTopAction = Intent.ACTION_FACTORY_TEST;
7816 mTopData = null;
7817 mTopComponent = new ComponentName(app.packageName,
7818 ai.name);
7819 } else {
7820 errorMsg = mContext.getResources().getText(
7821 com.android.internal.R.string.factorytest_not_system);
7822 }
7823 } else {
7824 errorMsg = mContext.getResources().getText(
7825 com.android.internal.R.string.factorytest_no_action);
7826 }
7827 if (errorMsg != null) {
7828 mTopAction = null;
7829 mTopData = null;
7830 mTopComponent = null;
7831 Message msg = Message.obtain();
7832 msg.what = SHOW_FACTORY_ERROR_MSG;
7833 msg.getData().putCharSequence("msg", errorMsg);
7834 mHandler.sendMessage(msg);
7835 }
7836 }
7837 }
7838
7839 retrieveSettings();
7840
7841 synchronized (this) {
7842 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7843 try {
7844 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007845 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007846 if (apps != null) {
7847 int N = apps.size();
7848 int i;
7849 for (i=0; i<N; i++) {
7850 ApplicationInfo info
7851 = (ApplicationInfo)apps.get(i);
7852 if (info != null &&
7853 !info.packageName.equals("android")) {
7854 addAppLocked(info);
7855 }
7856 }
7857 }
7858 } catch (RemoteException ex) {
7859 // pm is in same process, this will never happen.
7860 }
7861 }
7862
7863 try {
7864 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7865 Message msg = Message.obtain();
7866 msg.what = SHOW_UID_ERROR_MSG;
7867 mHandler.sendMessage(msg);
7868 }
7869 } catch (RemoteException e) {
7870 }
7871
7872 // Start up initial activity.
7873 mBooting = true;
7874 resumeTopActivityLocked(null);
7875 }
7876 }
7877
7878 boolean makeAppCrashingLocked(ProcessRecord app,
7879 String tag, String shortMsg, String longMsg, byte[] crashData) {
7880 app.crashing = true;
7881 app.crashingReport = generateProcessError(app,
7882 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7883 startAppProblemLocked(app);
7884 app.stopFreezingAllLocked();
7885 return handleAppCrashLocked(app);
7886 }
7887
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007888 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7889 IPackageManager pm = ActivityThread.getPackageManager();
7890 try {
7891 // was an installer package name specified when this app was
7892 // installed?
7893 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7894 if (installerPackageName == null) {
7895 return null;
7896 }
7897
7898 // is there an Activity in this package that handles ACTION_APP_ERROR?
7899 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
7900 ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
7901 if (info == null || info.activityInfo == null) {
7902 return null;
7903 }
7904
7905 return new ComponentName(installerPackageName, info.activityInfo.name);
7906 } catch (RemoteException e) {
7907 // will return null and no error report will be delivered
7908 }
7909 return null;
7910 }
7911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007912 void makeAppNotRespondingLocked(ProcessRecord app,
7913 String tag, String shortMsg, String longMsg, byte[] crashData) {
7914 app.notResponding = true;
7915 app.notRespondingReport = generateProcessError(app,
7916 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7917 crashData);
7918 startAppProblemLocked(app);
7919 app.stopFreezingAllLocked();
7920 }
7921
7922 /**
7923 * Generate a process error record, suitable for attachment to a ProcessRecord.
7924 *
7925 * @param app The ProcessRecord in which the error occurred.
7926 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7927 * ActivityManager.AppErrorStateInfo
7928 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7929 * @param shortMsg Short message describing the crash.
7930 * @param longMsg Long message describing the crash.
7931 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7932 *
7933 * @return Returns a fully-formed AppErrorStateInfo record.
7934 */
7935 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
7936 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
7937 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
7938
7939 report.condition = condition;
7940 report.processName = app.processName;
7941 report.pid = app.pid;
7942 report.uid = app.info.uid;
7943 report.tag = tag;
7944 report.shortMsg = shortMsg;
7945 report.longMsg = longMsg;
7946 report.crashData = crashData;
7947
7948 return report;
7949 }
7950
7951 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
7952 boolean crashed) {
7953 synchronized (this) {
7954 app.crashing = false;
7955 app.crashingReport = null;
7956 app.notResponding = false;
7957 app.notRespondingReport = null;
7958 if (app.anrDialog == fromDialog) {
7959 app.anrDialog = null;
7960 }
7961 if (app.waitDialog == fromDialog) {
7962 app.waitDialog = null;
7963 }
7964 if (app.pid > 0 && app.pid != MY_PID) {
7965 if (crashed) {
7966 handleAppCrashLocked(app);
7967 }
7968 Log.i(ActivityManagerService.TAG, "Killing process "
7969 + app.processName
7970 + " (pid=" + app.pid + ") at user's request");
7971 Process.killProcess(app.pid);
7972 }
7973
7974 }
7975 }
7976
7977 boolean handleAppCrashLocked(ProcessRecord app) {
7978 long now = SystemClock.uptimeMillis();
7979
7980 Long crashTime = mProcessCrashTimes.get(app.info.processName,
7981 app.info.uid);
7982 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
7983 // This process loses!
7984 Log.w(TAG, "Process " + app.info.processName
7985 + " has crashed too many times: killing!");
7986 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
7987 app.info.processName, app.info.uid);
7988 killServicesLocked(app, false);
7989 for (int i=mHistory.size()-1; i>=0; i--) {
7990 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7991 if (r.app == app) {
7992 if (Config.LOGD) Log.d(
7993 TAG, " Force finishing activity "
7994 + r.intent.getComponent().flattenToShortString());
7995 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
7996 }
7997 }
7998 if (!app.persistent) {
7999 // We don't want to start this process again until the user
8000 // explicitly does so... but for persistent process, we really
8001 // need to keep it running. If a persistent process is actually
8002 // repeatedly crashing, then badness for everyone.
8003 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8004 app.info.processName);
8005 mBadProcesses.put(app.info.processName, app.info.uid, now);
8006 app.bad = true;
8007 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8008 app.removed = true;
8009 removeProcessLocked(app, false);
8010 return false;
8011 }
8012 }
8013
8014 // Bump up the crash count of any services currently running in the proc.
8015 if (app.services.size() != 0) {
8016 // Any services running in the application need to be placed
8017 // back in the pending list.
8018 Iterator it = app.services.iterator();
8019 while (it.hasNext()) {
8020 ServiceRecord sr = (ServiceRecord)it.next();
8021 sr.crashCount++;
8022 }
8023 }
8024
8025 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8026 return true;
8027 }
8028
8029 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008030 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008031 skipCurrentReceiverLocked(app);
8032 }
8033
8034 void skipCurrentReceiverLocked(ProcessRecord app) {
8035 boolean reschedule = false;
8036 BroadcastRecord r = app.curReceiver;
8037 if (r != null) {
8038 // The current broadcast is waiting for this app's receiver
8039 // to be finished. Looks like that's not going to happen, so
8040 // let the broadcast continue.
8041 logBroadcastReceiverDiscard(r);
8042 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8043 r.resultExtras, r.resultAbort, true);
8044 reschedule = true;
8045 }
8046 r = mPendingBroadcast;
8047 if (r != null && r.curApp == app) {
8048 if (DEBUG_BROADCAST) Log.v(TAG,
8049 "skip & discard pending app " + r);
8050 logBroadcastReceiverDiscard(r);
8051 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8052 r.resultExtras, r.resultAbort, true);
8053 reschedule = true;
8054 }
8055 if (reschedule) {
8056 scheduleBroadcastsLocked();
8057 }
8058 }
8059
8060 public int handleApplicationError(IBinder app, int flags,
8061 String tag, String shortMsg, String longMsg, byte[] crashData) {
8062 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008063 ProcessRecord r = null;
8064 synchronized (this) {
8065 if (app != null) {
8066 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8067 final int NA = apps.size();
8068 for (int ia=0; ia<NA; ia++) {
8069 ProcessRecord p = apps.valueAt(ia);
8070 if (p.thread != null && p.thread.asBinder() == app) {
8071 r = p;
8072 break;
8073 }
8074 }
8075 }
8076 }
8077
8078 if (r != null) {
8079 // The application has crashed. Send the SIGQUIT to the process so
8080 // that it can dump its state.
8081 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8082 //Log.i(TAG, "Current system threads:");
8083 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8084 }
8085
8086 if (mWatcher != null) {
8087 try {
8088 String name = r != null ? r.processName : null;
8089 int pid = r != null ? r.pid : Binder.getCallingPid();
8090 if (!mWatcher.appCrashed(name, pid,
8091 shortMsg, longMsg, crashData)) {
8092 Log.w(TAG, "Force-killing crashed app " + name
8093 + " at watcher's request");
8094 Process.killProcess(pid);
8095 return 0;
8096 }
8097 } catch (RemoteException e) {
8098 mWatcher = null;
8099 }
8100 }
8101
8102 final long origId = Binder.clearCallingIdentity();
8103
8104 // If this process is running instrumentation, finish it.
8105 if (r != null && r.instrumentationClass != null) {
8106 Log.w(TAG, "Error in app " + r.processName
8107 + " running instrumentation " + r.instrumentationClass + ":");
8108 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8109 if (longMsg != null) Log.w(TAG, " " + longMsg);
8110 Bundle info = new Bundle();
8111 info.putString("shortMsg", shortMsg);
8112 info.putString("longMsg", longMsg);
8113 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8114 Binder.restoreCallingIdentity(origId);
8115 return 0;
8116 }
8117
8118 if (r != null) {
8119 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8120 return 0;
8121 }
8122 } else {
8123 Log.w(TAG, "Some application object " + app + " tag " + tag
8124 + " has crashed, but I don't know who it is.");
8125 Log.w(TAG, "ShortMsg:" + shortMsg);
8126 Log.w(TAG, "LongMsg:" + longMsg);
8127 Binder.restoreCallingIdentity(origId);
8128 return 0;
8129 }
8130
8131 Message msg = Message.obtain();
8132 msg.what = SHOW_ERROR_MSG;
8133 HashMap data = new HashMap();
8134 data.put("result", result);
8135 data.put("app", r);
8136 data.put("flags", flags);
8137 data.put("shortMsg", shortMsg);
8138 data.put("longMsg", longMsg);
8139 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8140 // For system processes, submit crash data to the server.
8141 data.put("crashData", crashData);
8142 }
8143 msg.obj = data;
8144 mHandler.sendMessage(msg);
8145
8146 Binder.restoreCallingIdentity(origId);
8147 }
8148
8149 int res = result.get();
8150
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008151 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008152 synchronized (this) {
8153 if (r != null) {
8154 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8155 SystemClock.uptimeMillis());
8156 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008157 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8158 appErrorIntent = createAppErrorIntentLocked(r);
8159 res = AppErrorDialog.FORCE_QUIT;
8160 }
8161 }
8162
8163 if (appErrorIntent != null) {
8164 try {
8165 mContext.startActivity(appErrorIntent);
8166 } catch (ActivityNotFoundException e) {
8167 Log.w(TAG, "bug report receiver dissappeared", e);
8168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008169 }
8170
8171 return res;
8172 }
8173
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008174 Intent createAppErrorIntentLocked(ProcessRecord r) {
8175 ApplicationErrorReport report = createAppErrorReportLocked(r);
8176 if (report == null) {
8177 return null;
8178 }
8179 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8180 result.setComponent(r.errorReportReceiver);
8181 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8182 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8183 return result;
8184 }
8185
8186 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8187 if (r.errorReportReceiver == null) {
8188 return null;
8189 }
8190
8191 if (!r.crashing && !r.notResponding) {
8192 return null;
8193 }
8194
8195 try {
8196 ApplicationErrorReport report = new ApplicationErrorReport();
8197 report.packageName = r.info.packageName;
8198 report.installerPackageName = r.errorReportReceiver.getPackageName();
8199 report.processName = r.processName;
8200
8201 if (r.crashing) {
8202 report.type = ApplicationErrorReport.TYPE_CRASH;
8203 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8204
8205 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8206 r.crashingReport.crashData);
8207 DataInputStream dataStream = new DataInputStream(byteStream);
8208 CrashData crashData = new CrashData(dataStream);
8209 ThrowableData throwData = crashData.getThrowableData();
8210
8211 report.time = crashData.getTime();
8212 report.crashInfo.stackTrace = throwData.toString();
8213
8214 // extract the source of the exception, useful for report
8215 // clustering
8216 while (throwData.getCause() != null) {
8217 throwData = throwData.getCause();
8218 }
8219 StackTraceElementData trace = throwData.getStackTrace()[0];
8220 report.crashInfo.exceptionClassName = throwData.getType();
8221 report.crashInfo.throwFileName = trace.getFileName();
8222 report.crashInfo.throwClassName = trace.getClassName();
8223 report.crashInfo.throwMethodName = trace.getMethodName();
8224 } else if (r.notResponding) {
8225 report.type = ApplicationErrorReport.TYPE_ANR;
8226 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8227
8228 report.anrInfo.activity = r.notRespondingReport.tag;
8229 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8230 report.anrInfo.info = r.notRespondingReport.longMsg;
8231 }
8232
8233 return report;
8234 } catch (IOException e) {
8235 // we don't send it
8236 }
8237
8238 return null;
8239 }
8240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008241 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8242 // assume our apps are happy - lazy create the list
8243 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8244
8245 synchronized (this) {
8246
8247 // iterate across all processes
8248 final int N = mLRUProcesses.size();
8249 for (int i = 0; i < N; i++) {
8250 ProcessRecord app = mLRUProcesses.get(i);
8251 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8252 // This one's in trouble, so we'll generate a report for it
8253 // crashes are higher priority (in case there's a crash *and* an anr)
8254 ActivityManager.ProcessErrorStateInfo report = null;
8255 if (app.crashing) {
8256 report = app.crashingReport;
8257 } else if (app.notResponding) {
8258 report = app.notRespondingReport;
8259 }
8260
8261 if (report != null) {
8262 if (errList == null) {
8263 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8264 }
8265 errList.add(report);
8266 } else {
8267 Log.w(TAG, "Missing app error report, app = " + app.processName +
8268 " crashing = " + app.crashing +
8269 " notResponding = " + app.notResponding);
8270 }
8271 }
8272 }
8273 }
8274
8275 return errList;
8276 }
8277
8278 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8279 // Lazy instantiation of list
8280 List<ActivityManager.RunningAppProcessInfo> runList = null;
8281 synchronized (this) {
8282 // Iterate across all processes
8283 final int N = mLRUProcesses.size();
8284 for (int i = 0; i < N; i++) {
8285 ProcessRecord app = mLRUProcesses.get(i);
8286 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8287 // Generate process state info for running application
8288 ActivityManager.RunningAppProcessInfo currApp =
8289 new ActivityManager.RunningAppProcessInfo(app.processName,
8290 app.pid, app.getPackageList());
8291 int adj = app.curAdj;
8292 if (adj >= CONTENT_PROVIDER_ADJ) {
8293 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8294 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8295 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008296 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8297 } else if (adj >= HOME_APP_ADJ) {
8298 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8299 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008300 } else if (adj >= SECONDARY_SERVER_ADJ) {
8301 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8302 } else if (adj >= VISIBLE_APP_ADJ) {
8303 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8304 } else {
8305 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8306 }
8307 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8308 // + " lru=" + currApp.lru);
8309 if (runList == null) {
8310 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8311 }
8312 runList.add(currApp);
8313 }
8314 }
8315 }
8316 return runList;
8317 }
8318
8319 @Override
8320 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8321 synchronized (this) {
8322 if (checkCallingPermission(android.Manifest.permission.DUMP)
8323 != PackageManager.PERMISSION_GRANTED) {
8324 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8325 + Binder.getCallingPid()
8326 + ", uid=" + Binder.getCallingUid()
8327 + " without permission "
8328 + android.Manifest.permission.DUMP);
8329 return;
8330 }
8331 if (args.length != 0 && "service".equals(args[0])) {
8332 dumpService(fd, pw, args);
8333 return;
8334 }
8335 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008336 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008337 pw.println(" ");
8338 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008339 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008340 if (mWaitingVisibleActivities.size() > 0) {
8341 pw.println(" ");
8342 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008343 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008344 }
8345 if (mStoppingActivities.size() > 0) {
8346 pw.println(" ");
8347 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008348 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008349 }
8350 if (mFinishingActivities.size() > 0) {
8351 pw.println(" ");
8352 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008353 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008354 }
8355
8356 pw.println(" ");
8357 pw.println(" mPausingActivity: " + mPausingActivity);
8358 pw.println(" mResumedActivity: " + mResumedActivity);
8359 pw.println(" mFocusedActivity: " + mFocusedActivity);
8360 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8361
8362 if (mRecentTasks.size() > 0) {
8363 pw.println(" ");
8364 pw.println("Recent tasks in Current Activity Manager State:");
8365
8366 final int N = mRecentTasks.size();
8367 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008368 TaskRecord tr = mRecentTasks.get(i);
8369 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8370 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008371 mRecentTasks.get(i).dump(pw, " ");
8372 }
8373 }
8374
8375 pw.println(" ");
8376 pw.println(" mCurTask: " + mCurTask);
8377
8378 pw.println(" ");
8379 pw.println("Processes in Current Activity Manager State:");
8380
8381 boolean needSep = false;
8382 int numPers = 0;
8383
8384 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8385 final int NA = procs.size();
8386 for (int ia=0; ia<NA; ia++) {
8387 if (!needSep) {
8388 pw.println(" All known processes:");
8389 needSep = true;
8390 }
8391 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008392 pw.print(r.persistent ? " *PERS*" : " *APP*");
8393 pw.print(" UID "); pw.print(procs.keyAt(ia));
8394 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008395 r.dump(pw, " ");
8396 if (r.persistent) {
8397 numPers++;
8398 }
8399 }
8400 }
8401
8402 if (mLRUProcesses.size() > 0) {
8403 if (needSep) pw.println(" ");
8404 needSep = true;
8405 pw.println(" Running processes (most recent first):");
8406 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008407 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008408 needSep = true;
8409 }
8410
8411 synchronized (mPidsSelfLocked) {
8412 if (mPidsSelfLocked.size() > 0) {
8413 if (needSep) pw.println(" ");
8414 needSep = true;
8415 pw.println(" PID mappings:");
8416 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008417 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8418 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008419 }
8420 }
8421 }
8422
8423 if (mForegroundProcesses.size() > 0) {
8424 if (needSep) pw.println(" ");
8425 needSep = true;
8426 pw.println(" Foreground Processes:");
8427 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008428 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8429 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008430 }
8431 }
8432
8433 if (mPersistentStartingProcesses.size() > 0) {
8434 if (needSep) pw.println(" ");
8435 needSep = true;
8436 pw.println(" Persisent processes that are starting:");
8437 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008438 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008439 }
8440
8441 if (mStartingProcesses.size() > 0) {
8442 if (needSep) pw.println(" ");
8443 needSep = true;
8444 pw.println(" Processes that are starting:");
8445 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008446 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008447 }
8448
8449 if (mRemovedProcesses.size() > 0) {
8450 if (needSep) pw.println(" ");
8451 needSep = true;
8452 pw.println(" Processes that are being removed:");
8453 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008454 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008455 }
8456
8457 if (mProcessesOnHold.size() > 0) {
8458 if (needSep) pw.println(" ");
8459 needSep = true;
8460 pw.println(" Processes that are on old until the system is ready:");
8461 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008462 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008463 }
8464
8465 if (mProcessCrashTimes.getMap().size() > 0) {
8466 if (needSep) pw.println(" ");
8467 needSep = true;
8468 pw.println(" Time since processes crashed:");
8469 long now = SystemClock.uptimeMillis();
8470 for (Map.Entry<String, SparseArray<Long>> procs
8471 : mProcessCrashTimes.getMap().entrySet()) {
8472 SparseArray<Long> uids = procs.getValue();
8473 final int N = uids.size();
8474 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008475 pw.print(" Process "); pw.print(procs.getKey());
8476 pw.print(" uid "); pw.print(uids.keyAt(i));
8477 pw.print(": last crashed ");
8478 pw.print((now-uids.valueAt(i)));
8479 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008480 }
8481 }
8482 }
8483
8484 if (mBadProcesses.getMap().size() > 0) {
8485 if (needSep) pw.println(" ");
8486 needSep = true;
8487 pw.println(" Bad processes:");
8488 for (Map.Entry<String, SparseArray<Long>> procs
8489 : mBadProcesses.getMap().entrySet()) {
8490 SparseArray<Long> uids = procs.getValue();
8491 final int N = uids.size();
8492 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008493 pw.print(" Bad process "); pw.print(procs.getKey());
8494 pw.print(" uid "); pw.print(uids.keyAt(i));
8495 pw.print(": crashed at time ");
8496 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008497 }
8498 }
8499 }
8500
8501 pw.println(" ");
8502 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008503 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008504 pw.println(" mConfiguration: " + mConfiguration);
8505 pw.println(" mStartRunning=" + mStartRunning
8506 + " mSystemReady=" + mSystemReady
8507 + " mBooting=" + mBooting
8508 + " mBooted=" + mBooted
8509 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008510 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 pw.println(" mGoingToSleep=" + mGoingToSleep);
8512 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8513 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8514 + " mDebugTransient=" + mDebugTransient
8515 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8516 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8517 + " mWatcher=" + mWatcher);
8518 }
8519 }
8520
8521 /**
8522 * There are three ways to call this:
8523 * - no service specified: dump all the services
8524 * - a flattened component name that matched an existing service was specified as the
8525 * first arg: dump that one service
8526 * - the first arg isn't the flattened component name of an existing service:
8527 * dump all services whose component contains the first arg as a substring
8528 */
8529 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8530 String[] newArgs;
8531 String componentNameString;
8532 ServiceRecord r;
8533 if (args.length == 1) {
8534 componentNameString = null;
8535 newArgs = EMPTY_STRING_ARRAY;
8536 r = null;
8537 } else {
8538 componentNameString = args[1];
8539 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8540 r = componentName != null ? mServices.get(componentName) : null;
8541 newArgs = new String[args.length - 2];
8542 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8543 }
8544
8545 if (r != null) {
8546 dumpService(fd, pw, r, newArgs);
8547 } else {
8548 for (ServiceRecord r1 : mServices.values()) {
8549 if (componentNameString == null
8550 || r1.name.flattenToString().contains(componentNameString)) {
8551 dumpService(fd, pw, r1, newArgs);
8552 }
8553 }
8554 }
8555 }
8556
8557 /**
8558 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8559 * there is a thread associated with the service.
8560 */
8561 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8562 pw.println(" Service " + r.name.flattenToString());
8563 if (r.app != null && r.app.thread != null) {
8564 try {
8565 // flush anything that is already in the PrintWriter since the thread is going
8566 // to write to the file descriptor directly
8567 pw.flush();
8568 r.app.thread.dumpService(fd, r, args);
8569 pw.print("\n");
8570 } catch (RemoteException e) {
8571 pw.println("got a RemoteException while dumping the service");
8572 }
8573 }
8574 }
8575
8576 void dumpBroadcasts(PrintWriter pw) {
8577 synchronized (this) {
8578 if (checkCallingPermission(android.Manifest.permission.DUMP)
8579 != PackageManager.PERMISSION_GRANTED) {
8580 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8581 + Binder.getCallingPid()
8582 + ", uid=" + Binder.getCallingUid()
8583 + " without permission "
8584 + android.Manifest.permission.DUMP);
8585 return;
8586 }
8587 pw.println("Broadcasts in Current Activity Manager State:");
8588
8589 if (mRegisteredReceivers.size() > 0) {
8590 pw.println(" ");
8591 pw.println(" Registered Receivers:");
8592 Iterator it = mRegisteredReceivers.values().iterator();
8593 while (it.hasNext()) {
8594 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008595 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008596 r.dump(pw, " ");
8597 }
8598 }
8599
8600 pw.println(" ");
8601 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008602 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008603
8604 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8605 || mPendingBroadcast != null) {
8606 if (mParallelBroadcasts.size() > 0) {
8607 pw.println(" ");
8608 pw.println(" Active broadcasts:");
8609 }
8610 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8611 pw.println(" Broadcast #" + i + ":");
8612 mParallelBroadcasts.get(i).dump(pw, " ");
8613 }
8614 if (mOrderedBroadcasts.size() > 0) {
8615 pw.println(" ");
8616 pw.println(" Active serialized broadcasts:");
8617 }
8618 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8619 pw.println(" Serialized Broadcast #" + i + ":");
8620 mOrderedBroadcasts.get(i).dump(pw, " ");
8621 }
8622 pw.println(" ");
8623 pw.println(" Pending broadcast:");
8624 if (mPendingBroadcast != null) {
8625 mPendingBroadcast.dump(pw, " ");
8626 } else {
8627 pw.println(" (null)");
8628 }
8629 }
8630
8631 pw.println(" ");
8632 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8633 if (mStickyBroadcasts != null) {
8634 pw.println(" ");
8635 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008636 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008637 for (Map.Entry<String, ArrayList<Intent>> ent
8638 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008639 pw.print(" * Sticky action "); pw.print(ent.getKey());
8640 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008641 ArrayList<Intent> intents = ent.getValue();
8642 final int N = intents.size();
8643 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008644 sb.setLength(0);
8645 sb.append(" Intent: ");
8646 intents.get(i).toShortString(sb, true, false);
8647 pw.println(sb.toString());
8648 Bundle bundle = intents.get(i).getExtras();
8649 if (bundle != null) {
8650 pw.print(" ");
8651 pw.println(bundle.toString());
8652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008653 }
8654 }
8655 }
8656
8657 pw.println(" ");
8658 pw.println(" mHandler:");
8659 mHandler.dump(new PrintWriterPrinter(pw), " ");
8660 }
8661 }
8662
8663 void dumpServices(PrintWriter pw) {
8664 synchronized (this) {
8665 if (checkCallingPermission(android.Manifest.permission.DUMP)
8666 != PackageManager.PERMISSION_GRANTED) {
8667 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8668 + Binder.getCallingPid()
8669 + ", uid=" + Binder.getCallingUid()
8670 + " without permission "
8671 + android.Manifest.permission.DUMP);
8672 return;
8673 }
8674 pw.println("Services in Current Activity Manager State:");
8675
8676 boolean needSep = false;
8677
8678 if (mServices.size() > 0) {
8679 pw.println(" Active services:");
8680 Iterator<ServiceRecord> it = mServices.values().iterator();
8681 while (it.hasNext()) {
8682 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008683 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008684 r.dump(pw, " ");
8685 }
8686 needSep = true;
8687 }
8688
8689 if (mPendingServices.size() > 0) {
8690 if (needSep) pw.println(" ");
8691 pw.println(" Pending services:");
8692 for (int i=0; i<mPendingServices.size(); i++) {
8693 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008694 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008695 r.dump(pw, " ");
8696 }
8697 needSep = true;
8698 }
8699
8700 if (mRestartingServices.size() > 0) {
8701 if (needSep) pw.println(" ");
8702 pw.println(" Restarting services:");
8703 for (int i=0; i<mRestartingServices.size(); i++) {
8704 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008705 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008706 r.dump(pw, " ");
8707 }
8708 needSep = true;
8709 }
8710
8711 if (mStoppingServices.size() > 0) {
8712 if (needSep) pw.println(" ");
8713 pw.println(" Stopping services:");
8714 for (int i=0; i<mStoppingServices.size(); i++) {
8715 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008716 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008717 r.dump(pw, " ");
8718 }
8719 needSep = true;
8720 }
8721
8722 if (mServiceConnections.size() > 0) {
8723 if (needSep) pw.println(" ");
8724 pw.println(" Connection bindings to services:");
8725 Iterator<ConnectionRecord> it
8726 = mServiceConnections.values().iterator();
8727 while (it.hasNext()) {
8728 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008729 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008730 r.dump(pw, " ");
8731 }
8732 }
8733 }
8734 }
8735
8736 void dumpProviders(PrintWriter pw) {
8737 synchronized (this) {
8738 if (checkCallingPermission(android.Manifest.permission.DUMP)
8739 != PackageManager.PERMISSION_GRANTED) {
8740 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8741 + Binder.getCallingPid()
8742 + ", uid=" + Binder.getCallingUid()
8743 + " without permission "
8744 + android.Manifest.permission.DUMP);
8745 return;
8746 }
8747
8748 pw.println("Content Providers in Current Activity Manager State:");
8749
8750 boolean needSep = false;
8751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008752 if (mProvidersByClass.size() > 0) {
8753 if (needSep) pw.println(" ");
8754 pw.println(" Published content providers (by class):");
8755 Iterator it = mProvidersByClass.entrySet().iterator();
8756 while (it.hasNext()) {
8757 Map.Entry e = (Map.Entry)it.next();
8758 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008759 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008760 r.dump(pw, " ");
8761 }
8762 needSep = true;
8763 }
8764
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008765 if (mProvidersByName.size() > 0) {
8766 pw.println(" ");
8767 pw.println(" Authority to provider mappings:");
8768 Iterator it = mProvidersByName.entrySet().iterator();
8769 while (it.hasNext()) {
8770 Map.Entry e = (Map.Entry)it.next();
8771 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8772 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8773 pw.println(r);
8774 }
8775 needSep = true;
8776 }
8777
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008778 if (mLaunchingProviders.size() > 0) {
8779 if (needSep) pw.println(" ");
8780 pw.println(" Launching content providers:");
8781 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008782 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8783 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008784 }
8785 needSep = true;
8786 }
8787
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008788 if (mGrantedUriPermissions.size() > 0) {
8789 pw.println();
8790 pw.println("Granted Uri Permissions:");
8791 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8792 int uid = mGrantedUriPermissions.keyAt(i);
8793 HashMap<Uri, UriPermission> perms
8794 = mGrantedUriPermissions.valueAt(i);
8795 pw.print(" * UID "); pw.print(uid);
8796 pw.println(" holds:");
8797 for (UriPermission perm : perms.values()) {
8798 pw.print(" "); pw.println(perm);
8799 perm.dump(pw, " ");
8800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008801 }
8802 }
8803 }
8804 }
8805
8806 void dumpSenders(PrintWriter pw) {
8807 synchronized (this) {
8808 if (checkCallingPermission(android.Manifest.permission.DUMP)
8809 != PackageManager.PERMISSION_GRANTED) {
8810 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8811 + Binder.getCallingPid()
8812 + ", uid=" + Binder.getCallingUid()
8813 + " without permission "
8814 + android.Manifest.permission.DUMP);
8815 return;
8816 }
8817
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008818 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008819
8820 if (this.mIntentSenderRecords.size() > 0) {
8821 Iterator<WeakReference<PendingIntentRecord>> it
8822 = mIntentSenderRecords.values().iterator();
8823 while (it.hasNext()) {
8824 WeakReference<PendingIntentRecord> ref = it.next();
8825 PendingIntentRecord rec = ref != null ? ref.get(): null;
8826 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008827 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008828 rec.dump(pw, " ");
8829 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008830 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008831 }
8832 }
8833 }
8834 }
8835 }
8836
8837 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008838 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008839 TaskRecord lastTask = null;
8840 for (int i=list.size()-1; i>=0; i--) {
8841 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008842 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008843 if (lastTask != r.task) {
8844 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008845 pw.print(prefix);
8846 pw.print(full ? "* " : " ");
8847 pw.println(lastTask);
8848 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008849 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008851 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008852 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8853 pw.print(" #"); pw.print(i); pw.print(": ");
8854 pw.println(r);
8855 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008856 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008858 }
8859 }
8860
8861 private static final int dumpProcessList(PrintWriter pw, List list,
8862 String prefix, String normalLabel, String persistentLabel,
8863 boolean inclOomAdj) {
8864 int numPers = 0;
8865 for (int i=list.size()-1; i>=0; i--) {
8866 ProcessRecord r = (ProcessRecord)list.get(i);
8867 if (false) {
8868 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8869 + " #" + i + ":");
8870 r.dump(pw, prefix + " ");
8871 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008872 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008873 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008874 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008875 } else {
8876 pw.println(String.format("%s%s #%2d: %s",
8877 prefix, (r.persistent ? persistentLabel : normalLabel),
8878 i, r.toString()));
8879 }
8880 if (r.persistent) {
8881 numPers++;
8882 }
8883 }
8884 return numPers;
8885 }
8886
8887 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8888 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008889 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008890 long uptime = SystemClock.uptimeMillis();
8891 long realtime = SystemClock.elapsedRealtime();
8892
8893 if (isCheckinRequest) {
8894 // short checkin version
8895 pw.println(uptime + "," + realtime);
8896 pw.flush();
8897 } else {
8898 pw.println("Applications Memory Usage (kB):");
8899 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8900 }
8901 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8902 ProcessRecord r = (ProcessRecord)list.get(i);
8903 if (r.thread != null) {
8904 if (!isCheckinRequest) {
8905 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8906 pw.flush();
8907 }
8908 try {
8909 r.thread.asBinder().dump(fd, args);
8910 } catch (RemoteException e) {
8911 if (!isCheckinRequest) {
8912 pw.println("Got RemoteException!");
8913 pw.flush();
8914 }
8915 }
8916 }
8917 }
8918 }
8919
8920 /**
8921 * Searches array of arguments for the specified string
8922 * @param args array of argument strings
8923 * @param value value to search for
8924 * @return true if the value is contained in the array
8925 */
8926 private static boolean scanArgs(String[] args, String value) {
8927 if (args != null) {
8928 for (String arg : args) {
8929 if (value.equals(arg)) {
8930 return true;
8931 }
8932 }
8933 }
8934 return false;
8935 }
8936
8937 private final int indexOfTokenLocked(IBinder token, boolean required) {
8938 int count = mHistory.size();
8939
8940 // convert the token to an entry in the history.
8941 HistoryRecord r = null;
8942 int index = -1;
8943 for (int i=count-1; i>=0; i--) {
8944 Object o = mHistory.get(i);
8945 if (o == token) {
8946 r = (HistoryRecord)o;
8947 index = i;
8948 break;
8949 }
8950 }
8951 if (index < 0 && required) {
8952 RuntimeInit.crash(TAG, new InvalidTokenException(token));
8953 }
8954
8955 return index;
8956 }
8957
8958 static class InvalidTokenException extends Exception {
8959 InvalidTokenException(IBinder token) {
8960 super("Bad activity token: " + token);
8961 }
8962 }
8963
8964 private final void killServicesLocked(ProcessRecord app,
8965 boolean allowRestart) {
8966 // Report disconnected services.
8967 if (false) {
8968 // XXX we are letting the client link to the service for
8969 // death notifications.
8970 if (app.services.size() > 0) {
8971 Iterator it = app.services.iterator();
8972 while (it.hasNext()) {
8973 ServiceRecord r = (ServiceRecord)it.next();
8974 if (r.connections.size() > 0) {
8975 Iterator<ConnectionRecord> jt
8976 = r.connections.values().iterator();
8977 while (jt.hasNext()) {
8978 ConnectionRecord c = jt.next();
8979 if (c.binding.client != app) {
8980 try {
8981 //c.conn.connected(r.className, null);
8982 } catch (Exception e) {
8983 // todo: this should be asynchronous!
8984 Log.w(TAG, "Exception thrown disconnected servce "
8985 + r.shortName
8986 + " from app " + app.processName, e);
8987 }
8988 }
8989 }
8990 }
8991 }
8992 }
8993 }
8994
8995 // Clean up any connections this application has to other services.
8996 if (app.connections.size() > 0) {
8997 Iterator<ConnectionRecord> it = app.connections.iterator();
8998 while (it.hasNext()) {
8999 ConnectionRecord r = it.next();
9000 removeConnectionLocked(r, app, null);
9001 }
9002 }
9003 app.connections.clear();
9004
9005 if (app.services.size() != 0) {
9006 // Any services running in the application need to be placed
9007 // back in the pending list.
9008 Iterator it = app.services.iterator();
9009 while (it.hasNext()) {
9010 ServiceRecord sr = (ServiceRecord)it.next();
9011 synchronized (sr.stats.getBatteryStats()) {
9012 sr.stats.stopLaunchedLocked();
9013 }
9014 sr.app = null;
9015 sr.executeNesting = 0;
9016 mStoppingServices.remove(sr);
9017 if (sr.bindings.size() > 0) {
9018 Iterator<IntentBindRecord> bindings
9019 = sr.bindings.values().iterator();
9020 while (bindings.hasNext()) {
9021 IntentBindRecord b = bindings.next();
9022 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9023 + ": shouldUnbind=" + b.hasBound);
9024 b.binder = null;
9025 b.requested = b.received = b.hasBound = false;
9026 }
9027 }
9028
9029 if (sr.crashCount >= 2) {
9030 Log.w(TAG, "Service crashed " + sr.crashCount
9031 + " times, stopping: " + sr);
9032 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9033 sr.crashCount, sr.shortName, app.pid);
9034 bringDownServiceLocked(sr, true);
9035 } else if (!allowRestart) {
9036 bringDownServiceLocked(sr, true);
9037 } else {
9038 scheduleServiceRestartLocked(sr);
9039 }
9040 }
9041
9042 if (!allowRestart) {
9043 app.services.clear();
9044 }
9045 }
9046
9047 app.executingServices.clear();
9048 }
9049
9050 private final void removeDyingProviderLocked(ProcessRecord proc,
9051 ContentProviderRecord cpr) {
9052 synchronized (cpr) {
9053 cpr.launchingApp = null;
9054 cpr.notifyAll();
9055 }
9056
9057 mProvidersByClass.remove(cpr.info.name);
9058 String names[] = cpr.info.authority.split(";");
9059 for (int j = 0; j < names.length; j++) {
9060 mProvidersByName.remove(names[j]);
9061 }
9062
9063 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9064 while (cit.hasNext()) {
9065 ProcessRecord capp = cit.next();
9066 if (!capp.persistent && capp.thread != null
9067 && capp.pid != 0
9068 && capp.pid != MY_PID) {
9069 Log.i(TAG, "Killing app " + capp.processName
9070 + " (pid " + capp.pid
9071 + ") because provider " + cpr.info.name
9072 + " is in dying process " + proc.processName);
9073 Process.killProcess(capp.pid);
9074 }
9075 }
9076
9077 mLaunchingProviders.remove(cpr);
9078 }
9079
9080 /**
9081 * Main code for cleaning up a process when it has gone away. This is
9082 * called both as a result of the process dying, or directly when stopping
9083 * a process when running in single process mode.
9084 */
9085 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9086 boolean restarting, int index) {
9087 if (index >= 0) {
9088 mLRUProcesses.remove(index);
9089 }
9090
9091 // Dismiss any open dialogs.
9092 if (app.crashDialog != null) {
9093 app.crashDialog.dismiss();
9094 app.crashDialog = null;
9095 }
9096 if (app.anrDialog != null) {
9097 app.anrDialog.dismiss();
9098 app.anrDialog = null;
9099 }
9100 if (app.waitDialog != null) {
9101 app.waitDialog.dismiss();
9102 app.waitDialog = null;
9103 }
9104
9105 app.crashing = false;
9106 app.notResponding = false;
9107
9108 app.resetPackageList();
9109 app.thread = null;
9110 app.forcingToForeground = null;
9111 app.foregroundServices = false;
9112
9113 killServicesLocked(app, true);
9114
9115 boolean restart = false;
9116
9117 int NL = mLaunchingProviders.size();
9118
9119 // Remove published content providers.
9120 if (!app.pubProviders.isEmpty()) {
9121 Iterator it = app.pubProviders.values().iterator();
9122 while (it.hasNext()) {
9123 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9124 cpr.provider = null;
9125 cpr.app = null;
9126
9127 // See if someone is waiting for this provider... in which
9128 // case we don't remove it, but just let it restart.
9129 int i = 0;
9130 if (!app.bad) {
9131 for (; i<NL; i++) {
9132 if (mLaunchingProviders.get(i) == cpr) {
9133 restart = true;
9134 break;
9135 }
9136 }
9137 } else {
9138 i = NL;
9139 }
9140
9141 if (i >= NL) {
9142 removeDyingProviderLocked(app, cpr);
9143 NL = mLaunchingProviders.size();
9144 }
9145 }
9146 app.pubProviders.clear();
9147 }
9148
9149 // Look through the content providers we are waiting to have launched,
9150 // and if any run in this process then either schedule a restart of
9151 // the process or kill the client waiting for it if this process has
9152 // gone bad.
9153 for (int i=0; i<NL; i++) {
9154 ContentProviderRecord cpr = (ContentProviderRecord)
9155 mLaunchingProviders.get(i);
9156 if (cpr.launchingApp == app) {
9157 if (!app.bad) {
9158 restart = true;
9159 } else {
9160 removeDyingProviderLocked(app, cpr);
9161 NL = mLaunchingProviders.size();
9162 }
9163 }
9164 }
9165
9166 // Unregister from connected content providers.
9167 if (!app.conProviders.isEmpty()) {
9168 Iterator it = app.conProviders.iterator();
9169 while (it.hasNext()) {
9170 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9171 cpr.clients.remove(app);
9172 }
9173 app.conProviders.clear();
9174 }
9175
9176 skipCurrentReceiverLocked(app);
9177
9178 // Unregister any receivers.
9179 if (app.receivers.size() > 0) {
9180 Iterator<ReceiverList> it = app.receivers.iterator();
9181 while (it.hasNext()) {
9182 removeReceiverLocked(it.next());
9183 }
9184 app.receivers.clear();
9185 }
9186
Christopher Tate181fafa2009-05-14 11:12:14 -07009187 // If the app is undergoing backup, tell the backup manager about it
9188 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9189 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9190 try {
9191 IBackupManager bm = IBackupManager.Stub.asInterface(
9192 ServiceManager.getService(Context.BACKUP_SERVICE));
9193 bm.agentDisconnected(app.info.packageName);
9194 } catch (RemoteException e) {
9195 // can't happen; backup manager is local
9196 }
9197 }
9198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009199 // If the caller is restarting this app, then leave it in its
9200 // current lists and let the caller take care of it.
9201 if (restarting) {
9202 return;
9203 }
9204
9205 if (!app.persistent) {
9206 if (DEBUG_PROCESSES) Log.v(TAG,
9207 "Removing non-persistent process during cleanup: " + app);
9208 mProcessNames.remove(app.processName, app.info.uid);
9209 } else if (!app.removed) {
9210 // This app is persistent, so we need to keep its record around.
9211 // If it is not already on the pending app list, add it there
9212 // and start a new process for it.
9213 app.thread = null;
9214 app.forcingToForeground = null;
9215 app.foregroundServices = false;
9216 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9217 mPersistentStartingProcesses.add(app);
9218 restart = true;
9219 }
9220 }
9221 mProcessesOnHold.remove(app);
9222
The Android Open Source Project4df24232009-03-05 14:34:35 -08009223 if (app == mHomeProcess) {
9224 mHomeProcess = null;
9225 }
9226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009227 if (restart) {
9228 // We have components that still need to be running in the
9229 // process, so re-launch it.
9230 mProcessNames.put(app.processName, app.info.uid, app);
9231 startProcessLocked(app, "restart", app.processName);
9232 } else if (app.pid > 0 && app.pid != MY_PID) {
9233 // Goodbye!
9234 synchronized (mPidsSelfLocked) {
9235 mPidsSelfLocked.remove(app.pid);
9236 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9237 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009238 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009239 }
9240 }
9241
9242 // =========================================================
9243 // SERVICES
9244 // =========================================================
9245
9246 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9247 ActivityManager.RunningServiceInfo info =
9248 new ActivityManager.RunningServiceInfo();
9249 info.service = r.name;
9250 if (r.app != null) {
9251 info.pid = r.app.pid;
9252 }
9253 info.process = r.processName;
9254 info.foreground = r.isForeground;
9255 info.activeSince = r.createTime;
9256 info.started = r.startRequested;
9257 info.clientCount = r.connections.size();
9258 info.crashCount = r.crashCount;
9259 info.lastActivityTime = r.lastActivity;
9260 return info;
9261 }
9262
9263 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9264 int flags) {
9265 synchronized (this) {
9266 ArrayList<ActivityManager.RunningServiceInfo> res
9267 = new ArrayList<ActivityManager.RunningServiceInfo>();
9268
9269 if (mServices.size() > 0) {
9270 Iterator<ServiceRecord> it = mServices.values().iterator();
9271 while (it.hasNext() && res.size() < maxNum) {
9272 res.add(makeRunningServiceInfoLocked(it.next()));
9273 }
9274 }
9275
9276 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9277 ServiceRecord r = mRestartingServices.get(i);
9278 ActivityManager.RunningServiceInfo info =
9279 makeRunningServiceInfoLocked(r);
9280 info.restarting = r.nextRestartTime;
9281 res.add(info);
9282 }
9283
9284 return res;
9285 }
9286 }
9287
9288 private final ServiceRecord findServiceLocked(ComponentName name,
9289 IBinder token) {
9290 ServiceRecord r = mServices.get(name);
9291 return r == token ? r : null;
9292 }
9293
9294 private final class ServiceLookupResult {
9295 final ServiceRecord record;
9296 final String permission;
9297
9298 ServiceLookupResult(ServiceRecord _record, String _permission) {
9299 record = _record;
9300 permission = _permission;
9301 }
9302 };
9303
9304 private ServiceLookupResult findServiceLocked(Intent service,
9305 String resolvedType) {
9306 ServiceRecord r = null;
9307 if (service.getComponent() != null) {
9308 r = mServices.get(service.getComponent());
9309 }
9310 if (r == null) {
9311 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9312 r = mServicesByIntent.get(filter);
9313 }
9314
9315 if (r == null) {
9316 try {
9317 ResolveInfo rInfo =
9318 ActivityThread.getPackageManager().resolveService(
9319 service, resolvedType, 0);
9320 ServiceInfo sInfo =
9321 rInfo != null ? rInfo.serviceInfo : null;
9322 if (sInfo == null) {
9323 return null;
9324 }
9325
9326 ComponentName name = new ComponentName(
9327 sInfo.applicationInfo.packageName, sInfo.name);
9328 r = mServices.get(name);
9329 } catch (RemoteException ex) {
9330 // pm is in same process, this will never happen.
9331 }
9332 }
9333 if (r != null) {
9334 int callingPid = Binder.getCallingPid();
9335 int callingUid = Binder.getCallingUid();
9336 if (checkComponentPermission(r.permission,
9337 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9338 != PackageManager.PERMISSION_GRANTED) {
9339 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9340 + " from pid=" + callingPid
9341 + ", uid=" + callingUid
9342 + " requires " + r.permission);
9343 return new ServiceLookupResult(null, r.permission);
9344 }
9345 return new ServiceLookupResult(r, null);
9346 }
9347 return null;
9348 }
9349
9350 private class ServiceRestarter implements Runnable {
9351 private ServiceRecord mService;
9352
9353 void setService(ServiceRecord service) {
9354 mService = service;
9355 }
9356
9357 public void run() {
9358 synchronized(ActivityManagerService.this) {
9359 performServiceRestartLocked(mService);
9360 }
9361 }
9362 }
9363
9364 private ServiceLookupResult retrieveServiceLocked(Intent service,
9365 String resolvedType, int callingPid, int callingUid) {
9366 ServiceRecord r = null;
9367 if (service.getComponent() != null) {
9368 r = mServices.get(service.getComponent());
9369 }
9370 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9371 r = mServicesByIntent.get(filter);
9372 if (r == null) {
9373 try {
9374 ResolveInfo rInfo =
9375 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009376 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009377 ServiceInfo sInfo =
9378 rInfo != null ? rInfo.serviceInfo : null;
9379 if (sInfo == null) {
9380 Log.w(TAG, "Unable to start service " + service +
9381 ": not found");
9382 return null;
9383 }
9384
9385 ComponentName name = new ComponentName(
9386 sInfo.applicationInfo.packageName, sInfo.name);
9387 r = mServices.get(name);
9388 if (r == null) {
9389 filter = new Intent.FilterComparison(service.cloneFilter());
9390 ServiceRestarter res = new ServiceRestarter();
9391 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9392 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9393 synchronized (stats) {
9394 ss = stats.getServiceStatsLocked(
9395 sInfo.applicationInfo.uid, sInfo.packageName,
9396 sInfo.name);
9397 }
9398 r = new ServiceRecord(ss, name, filter, sInfo, res);
9399 res.setService(r);
9400 mServices.put(name, r);
9401 mServicesByIntent.put(filter, r);
9402
9403 // Make sure this component isn't in the pending list.
9404 int N = mPendingServices.size();
9405 for (int i=0; i<N; i++) {
9406 ServiceRecord pr = mPendingServices.get(i);
9407 if (pr.name.equals(name)) {
9408 mPendingServices.remove(i);
9409 i--;
9410 N--;
9411 }
9412 }
9413 }
9414 } catch (RemoteException ex) {
9415 // pm is in same process, this will never happen.
9416 }
9417 }
9418 if (r != null) {
9419 if (checkComponentPermission(r.permission,
9420 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9421 != PackageManager.PERMISSION_GRANTED) {
9422 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9423 + " from pid=" + Binder.getCallingPid()
9424 + ", uid=" + Binder.getCallingUid()
9425 + " requires " + r.permission);
9426 return new ServiceLookupResult(null, r.permission);
9427 }
9428 return new ServiceLookupResult(r, null);
9429 }
9430 return null;
9431 }
9432
9433 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9434 long now = SystemClock.uptimeMillis();
9435 if (r.executeNesting == 0 && r.app != null) {
9436 if (r.app.executingServices.size() == 0) {
9437 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9438 msg.obj = r.app;
9439 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9440 }
9441 r.app.executingServices.add(r);
9442 }
9443 r.executeNesting++;
9444 r.executingStart = now;
9445 }
9446
9447 private final void sendServiceArgsLocked(ServiceRecord r,
9448 boolean oomAdjusted) {
9449 final int N = r.startArgs.size();
9450 if (N == 0) {
9451 return;
9452 }
9453
9454 final int BASEID = r.lastStartId - N + 1;
9455 int i = 0;
9456 while (i < N) {
9457 try {
9458 Intent args = r.startArgs.get(i);
9459 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9460 + r.name + " " + r.intent + " args=" + args);
9461 bumpServiceExecutingLocked(r);
9462 if (!oomAdjusted) {
9463 oomAdjusted = true;
9464 updateOomAdjLocked(r.app);
9465 }
9466 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9467 i++;
9468 } catch (Exception e) {
9469 break;
9470 }
9471 }
9472 if (i == N) {
9473 r.startArgs.clear();
9474 } else {
9475 while (i > 0) {
9476 r.startArgs.remove(0);
9477 i--;
9478 }
9479 }
9480 }
9481
9482 private final boolean requestServiceBindingLocked(ServiceRecord r,
9483 IntentBindRecord i, boolean rebind) {
9484 if (r.app == null || r.app.thread == null) {
9485 // If service is not currently running, can't yet bind.
9486 return false;
9487 }
9488 if ((!i.requested || rebind) && i.apps.size() > 0) {
9489 try {
9490 bumpServiceExecutingLocked(r);
9491 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9492 + ": shouldUnbind=" + i.hasBound);
9493 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9494 if (!rebind) {
9495 i.requested = true;
9496 }
9497 i.hasBound = true;
9498 i.doRebind = false;
9499 } catch (RemoteException e) {
9500 return false;
9501 }
9502 }
9503 return true;
9504 }
9505
9506 private final void requestServiceBindingsLocked(ServiceRecord r) {
9507 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9508 while (bindings.hasNext()) {
9509 IntentBindRecord i = bindings.next();
9510 if (!requestServiceBindingLocked(r, i, false)) {
9511 break;
9512 }
9513 }
9514 }
9515
9516 private final void realStartServiceLocked(ServiceRecord r,
9517 ProcessRecord app) throws RemoteException {
9518 if (app.thread == null) {
9519 throw new RemoteException();
9520 }
9521
9522 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009523 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009524
9525 app.services.add(r);
9526 bumpServiceExecutingLocked(r);
9527 updateLRUListLocked(app, true);
9528
9529 boolean created = false;
9530 try {
9531 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9532 + r.name + " " + r.intent);
9533 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9534 System.identityHashCode(r), r.shortName,
9535 r.intent.getIntent().toString(), r.app.pid);
9536 synchronized (r.stats.getBatteryStats()) {
9537 r.stats.startLaunchedLocked();
9538 }
9539 app.thread.scheduleCreateService(r, r.serviceInfo);
9540 created = true;
9541 } finally {
9542 if (!created) {
9543 app.services.remove(r);
9544 scheduleServiceRestartLocked(r);
9545 }
9546 }
9547
9548 requestServiceBindingsLocked(r);
9549 sendServiceArgsLocked(r, true);
9550 }
9551
9552 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9553 r.totalRestartCount++;
9554 if (r.restartDelay == 0) {
9555 r.restartCount++;
9556 r.restartDelay = SERVICE_RESTART_DURATION;
9557 } else {
9558 // If it has been a "reasonably long time" since the service
9559 // was started, then reset our restart duration back to
9560 // the beginning, so we don't infinitely increase the duration
9561 // on a service that just occasionally gets killed (which is
9562 // a normal case, due to process being killed to reclaim memory).
9563 long now = SystemClock.uptimeMillis();
9564 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9565 r.restartCount = 1;
9566 r.restartDelay = SERVICE_RESTART_DURATION;
9567 } else {
9568 r.restartDelay *= 2;
9569 }
9570 }
9571 if (!mRestartingServices.contains(r)) {
9572 mRestartingServices.add(r);
9573 }
9574 mHandler.removeCallbacks(r.restarter);
9575 mHandler.postDelayed(r.restarter, r.restartDelay);
9576 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9577 Log.w(TAG, "Scheduling restart of crashed service "
9578 + r.shortName + " in " + r.restartDelay + "ms");
9579 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9580 r.shortName, r.restartDelay);
9581
9582 Message msg = Message.obtain();
9583 msg.what = SERVICE_ERROR_MSG;
9584 msg.obj = r;
9585 mHandler.sendMessage(msg);
9586 }
9587
9588 final void performServiceRestartLocked(ServiceRecord r) {
9589 if (!mRestartingServices.contains(r)) {
9590 return;
9591 }
9592 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9593 }
9594
9595 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9596 if (r.restartDelay == 0) {
9597 return false;
9598 }
9599 r.resetRestartCounter();
9600 mRestartingServices.remove(r);
9601 mHandler.removeCallbacks(r.restarter);
9602 return true;
9603 }
9604
9605 private final boolean bringUpServiceLocked(ServiceRecord r,
9606 int intentFlags, boolean whileRestarting) {
9607 //Log.i(TAG, "Bring up service:");
9608 //r.dump(" ");
9609
9610 if (r.app != null) {
9611 sendServiceArgsLocked(r, false);
9612 return true;
9613 }
9614
9615 if (!whileRestarting && r.restartDelay > 0) {
9616 // If waiting for a restart, then do nothing.
9617 return true;
9618 }
9619
9620 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9621 + " " + r.intent);
9622
9623 final String appName = r.processName;
9624 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9625 if (app != null && app.thread != null) {
9626 try {
9627 realStartServiceLocked(r, app);
9628 return true;
9629 } catch (RemoteException e) {
9630 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9631 }
9632
9633 // If a dead object exception was thrown -- fall through to
9634 // restart the application.
9635 }
9636
9637 if (!mPendingServices.contains(r)) {
9638 // Not running -- get it started, and enqueue this service record
9639 // to be executed when the app comes up.
9640 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9641 "service", r.name) == null) {
9642 Log.w(TAG, "Unable to launch app "
9643 + r.appInfo.packageName + "/"
9644 + r.appInfo.uid + " for service "
9645 + r.intent.getIntent() + ": process is bad");
9646 bringDownServiceLocked(r, true);
9647 return false;
9648 }
9649 mPendingServices.add(r);
9650 }
9651 return true;
9652 }
9653
9654 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9655 //Log.i(TAG, "Bring down service:");
9656 //r.dump(" ");
9657
9658 // Does it still need to run?
9659 if (!force && r.startRequested) {
9660 return;
9661 }
9662 if (r.connections.size() > 0) {
9663 if (!force) {
9664 // XXX should probably keep a count of the number of auto-create
9665 // connections directly in the service.
9666 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9667 while (it.hasNext()) {
9668 ConnectionRecord cr = it.next();
9669 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9670 return;
9671 }
9672 }
9673 }
9674
9675 // Report to all of the connections that the service is no longer
9676 // available.
9677 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9678 while (it.hasNext()) {
9679 ConnectionRecord c = it.next();
9680 try {
9681 // todo: shouldn't be a synchronous call!
9682 c.conn.connected(r.name, null);
9683 } catch (Exception e) {
9684 Log.w(TAG, "Failure disconnecting service " + r.name +
9685 " to connection " + c.conn.asBinder() +
9686 " (in " + c.binding.client.processName + ")", e);
9687 }
9688 }
9689 }
9690
9691 // Tell the service that it has been unbound.
9692 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9693 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9694 while (it.hasNext()) {
9695 IntentBindRecord ibr = it.next();
9696 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9697 + ": hasBound=" + ibr.hasBound);
9698 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9699 try {
9700 bumpServiceExecutingLocked(r);
9701 updateOomAdjLocked(r.app);
9702 ibr.hasBound = false;
9703 r.app.thread.scheduleUnbindService(r,
9704 ibr.intent.getIntent());
9705 } catch (Exception e) {
9706 Log.w(TAG, "Exception when unbinding service "
9707 + r.shortName, e);
9708 serviceDoneExecutingLocked(r, true);
9709 }
9710 }
9711 }
9712 }
9713
9714 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9715 + " " + r.intent);
9716 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9717 System.identityHashCode(r), r.shortName,
9718 (r.app != null) ? r.app.pid : -1);
9719
9720 mServices.remove(r.name);
9721 mServicesByIntent.remove(r.intent);
9722 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9723 r.totalRestartCount = 0;
9724 unscheduleServiceRestartLocked(r);
9725
9726 // Also make sure it is not on the pending list.
9727 int N = mPendingServices.size();
9728 for (int i=0; i<N; i++) {
9729 if (mPendingServices.get(i) == r) {
9730 mPendingServices.remove(i);
9731 if (DEBUG_SERVICE) Log.v(
9732 TAG, "Removed pending service: " + r.shortName);
9733 i--;
9734 N--;
9735 }
9736 }
9737
9738 if (r.app != null) {
9739 synchronized (r.stats.getBatteryStats()) {
9740 r.stats.stopLaunchedLocked();
9741 }
9742 r.app.services.remove(r);
9743 if (r.app.thread != null) {
9744 updateServiceForegroundLocked(r.app, false);
9745 try {
9746 Log.i(TAG, "Stopping service: " + r.shortName);
9747 bumpServiceExecutingLocked(r);
9748 mStoppingServices.add(r);
9749 updateOomAdjLocked(r.app);
9750 r.app.thread.scheduleStopService(r);
9751 } catch (Exception e) {
9752 Log.w(TAG, "Exception when stopping service "
9753 + r.shortName, e);
9754 serviceDoneExecutingLocked(r, true);
9755 }
9756 } else {
9757 if (DEBUG_SERVICE) Log.v(
9758 TAG, "Removed service that has no process: " + r.shortName);
9759 }
9760 } else {
9761 if (DEBUG_SERVICE) Log.v(
9762 TAG, "Removed service that is not running: " + r.shortName);
9763 }
9764 }
9765
9766 ComponentName startServiceLocked(IApplicationThread caller,
9767 Intent service, String resolvedType,
9768 int callingPid, int callingUid) {
9769 synchronized(this) {
9770 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9771 + " type=" + resolvedType + " args=" + service.getExtras());
9772
9773 if (caller != null) {
9774 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9775 if (callerApp == null) {
9776 throw new SecurityException(
9777 "Unable to find app for caller " + caller
9778 + " (pid=" + Binder.getCallingPid()
9779 + ") when starting service " + service);
9780 }
9781 }
9782
9783 ServiceLookupResult res =
9784 retrieveServiceLocked(service, resolvedType,
9785 callingPid, callingUid);
9786 if (res == null) {
9787 return null;
9788 }
9789 if (res.record == null) {
9790 return new ComponentName("!", res.permission != null
9791 ? res.permission : "private to package");
9792 }
9793 ServiceRecord r = res.record;
9794 if (unscheduleServiceRestartLocked(r)) {
9795 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9796 + r.shortName);
9797 }
9798 r.startRequested = true;
9799 r.startArgs.add(service);
9800 r.lastStartId++;
9801 if (r.lastStartId < 1) {
9802 r.lastStartId = 1;
9803 }
9804 r.lastActivity = SystemClock.uptimeMillis();
9805 synchronized (r.stats.getBatteryStats()) {
9806 r.stats.startRunningLocked();
9807 }
9808 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9809 return new ComponentName("!", "Service process is bad");
9810 }
9811 return r.name;
9812 }
9813 }
9814
9815 public ComponentName startService(IApplicationThread caller, Intent service,
9816 String resolvedType) {
9817 // Refuse possible leaked file descriptors
9818 if (service != null && service.hasFileDescriptors() == true) {
9819 throw new IllegalArgumentException("File descriptors passed in Intent");
9820 }
9821
9822 synchronized(this) {
9823 final int callingPid = Binder.getCallingPid();
9824 final int callingUid = Binder.getCallingUid();
9825 final long origId = Binder.clearCallingIdentity();
9826 ComponentName res = startServiceLocked(caller, service,
9827 resolvedType, callingPid, callingUid);
9828 Binder.restoreCallingIdentity(origId);
9829 return res;
9830 }
9831 }
9832
9833 ComponentName startServiceInPackage(int uid,
9834 Intent service, String resolvedType) {
9835 synchronized(this) {
9836 final long origId = Binder.clearCallingIdentity();
9837 ComponentName res = startServiceLocked(null, service,
9838 resolvedType, -1, uid);
9839 Binder.restoreCallingIdentity(origId);
9840 return res;
9841 }
9842 }
9843
9844 public int stopService(IApplicationThread caller, Intent service,
9845 String resolvedType) {
9846 // Refuse possible leaked file descriptors
9847 if (service != null && service.hasFileDescriptors() == true) {
9848 throw new IllegalArgumentException("File descriptors passed in Intent");
9849 }
9850
9851 synchronized(this) {
9852 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9853 + " type=" + resolvedType);
9854
9855 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9856 if (caller != null && callerApp == null) {
9857 throw new SecurityException(
9858 "Unable to find app for caller " + caller
9859 + " (pid=" + Binder.getCallingPid()
9860 + ") when stopping service " + service);
9861 }
9862
9863 // If this service is active, make sure it is stopped.
9864 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9865 if (r != null) {
9866 if (r.record != null) {
9867 synchronized (r.record.stats.getBatteryStats()) {
9868 r.record.stats.stopRunningLocked();
9869 }
9870 r.record.startRequested = false;
9871 final long origId = Binder.clearCallingIdentity();
9872 bringDownServiceLocked(r.record, false);
9873 Binder.restoreCallingIdentity(origId);
9874 return 1;
9875 }
9876 return -1;
9877 }
9878 }
9879
9880 return 0;
9881 }
9882
9883 public IBinder peekService(Intent service, String resolvedType) {
9884 // Refuse possible leaked file descriptors
9885 if (service != null && service.hasFileDescriptors() == true) {
9886 throw new IllegalArgumentException("File descriptors passed in Intent");
9887 }
9888
9889 IBinder ret = null;
9890
9891 synchronized(this) {
9892 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9893
9894 if (r != null) {
9895 // r.record is null if findServiceLocked() failed the caller permission check
9896 if (r.record == null) {
9897 throw new SecurityException(
9898 "Permission Denial: Accessing service " + r.record.name
9899 + " from pid=" + Binder.getCallingPid()
9900 + ", uid=" + Binder.getCallingUid()
9901 + " requires " + r.permission);
9902 }
9903 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9904 if (ib != null) {
9905 ret = ib.binder;
9906 }
9907 }
9908 }
9909
9910 return ret;
9911 }
9912
9913 public boolean stopServiceToken(ComponentName className, IBinder token,
9914 int startId) {
9915 synchronized(this) {
9916 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9917 + " " + token + " startId=" + startId);
9918 ServiceRecord r = findServiceLocked(className, token);
9919 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9920 synchronized (r.stats.getBatteryStats()) {
9921 r.stats.stopRunningLocked();
9922 r.startRequested = false;
9923 }
9924 final long origId = Binder.clearCallingIdentity();
9925 bringDownServiceLocked(r, false);
9926 Binder.restoreCallingIdentity(origId);
9927 return true;
9928 }
9929 }
9930 return false;
9931 }
9932
9933 public void setServiceForeground(ComponentName className, IBinder token,
9934 boolean isForeground) {
9935 synchronized(this) {
9936 ServiceRecord r = findServiceLocked(className, token);
9937 if (r != null) {
9938 if (r.isForeground != isForeground) {
9939 final long origId = Binder.clearCallingIdentity();
9940 r.isForeground = isForeground;
9941 if (r.app != null) {
9942 updateServiceForegroundLocked(r.app, true);
9943 }
9944 Binder.restoreCallingIdentity(origId);
9945 }
9946 }
9947 }
9948 }
9949
9950 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
9951 boolean anyForeground = false;
9952 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
9953 if (sr.isForeground) {
9954 anyForeground = true;
9955 break;
9956 }
9957 }
9958 if (anyForeground != proc.foregroundServices) {
9959 proc.foregroundServices = anyForeground;
9960 if (oomAdj) {
9961 updateOomAdjLocked();
9962 }
9963 }
9964 }
9965
9966 public int bindService(IApplicationThread caller, IBinder token,
9967 Intent service, String resolvedType,
9968 IServiceConnection connection, int flags) {
9969 // Refuse possible leaked file descriptors
9970 if (service != null && service.hasFileDescriptors() == true) {
9971 throw new IllegalArgumentException("File descriptors passed in Intent");
9972 }
9973
9974 synchronized(this) {
9975 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
9976 + " type=" + resolvedType + " conn=" + connection.asBinder()
9977 + " flags=0x" + Integer.toHexString(flags));
9978 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9979 if (callerApp == null) {
9980 throw new SecurityException(
9981 "Unable to find app for caller " + caller
9982 + " (pid=" + Binder.getCallingPid()
9983 + ") when binding service " + service);
9984 }
9985
9986 HistoryRecord activity = null;
9987 if (token != null) {
9988 int aindex = indexOfTokenLocked(token, false);
9989 if (aindex < 0) {
9990 Log.w(TAG, "Binding with unknown activity: " + token);
9991 return 0;
9992 }
9993 activity = (HistoryRecord)mHistory.get(aindex);
9994 }
9995
9996 ServiceLookupResult res =
9997 retrieveServiceLocked(service, resolvedType,
9998 Binder.getCallingPid(), Binder.getCallingUid());
9999 if (res == null) {
10000 return 0;
10001 }
10002 if (res.record == null) {
10003 return -1;
10004 }
10005 ServiceRecord s = res.record;
10006
10007 final long origId = Binder.clearCallingIdentity();
10008
10009 if (unscheduleServiceRestartLocked(s)) {
10010 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10011 + s.shortName);
10012 }
10013
10014 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10015 ConnectionRecord c = new ConnectionRecord(b, activity,
10016 connection, flags);
10017
10018 IBinder binder = connection.asBinder();
10019 s.connections.put(binder, c);
10020 b.connections.add(c);
10021 if (activity != null) {
10022 if (activity.connections == null) {
10023 activity.connections = new HashSet<ConnectionRecord>();
10024 }
10025 activity.connections.add(c);
10026 }
10027 b.client.connections.add(c);
10028 mServiceConnections.put(binder, c);
10029
10030 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10031 s.lastActivity = SystemClock.uptimeMillis();
10032 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10033 return 0;
10034 }
10035 }
10036
10037 if (s.app != null) {
10038 // This could have made the service more important.
10039 updateOomAdjLocked(s.app);
10040 }
10041
10042 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10043 + ": received=" + b.intent.received
10044 + " apps=" + b.intent.apps.size()
10045 + " doRebind=" + b.intent.doRebind);
10046
10047 if (s.app != null && b.intent.received) {
10048 // Service is already running, so we can immediately
10049 // publish the connection.
10050 try {
10051 c.conn.connected(s.name, b.intent.binder);
10052 } catch (Exception e) {
10053 Log.w(TAG, "Failure sending service " + s.shortName
10054 + " to connection " + c.conn.asBinder()
10055 + " (in " + c.binding.client.processName + ")", e);
10056 }
10057
10058 // If this is the first app connected back to this binding,
10059 // and the service had previously asked to be told when
10060 // rebound, then do so.
10061 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10062 requestServiceBindingLocked(s, b.intent, true);
10063 }
10064 } else if (!b.intent.requested) {
10065 requestServiceBindingLocked(s, b.intent, false);
10066 }
10067
10068 Binder.restoreCallingIdentity(origId);
10069 }
10070
10071 return 1;
10072 }
10073
10074 private void removeConnectionLocked(
10075 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10076 IBinder binder = c.conn.asBinder();
10077 AppBindRecord b = c.binding;
10078 ServiceRecord s = b.service;
10079 s.connections.remove(binder);
10080 b.connections.remove(c);
10081 if (c.activity != null && c.activity != skipAct) {
10082 if (c.activity.connections != null) {
10083 c.activity.connections.remove(c);
10084 }
10085 }
10086 if (b.client != skipApp) {
10087 b.client.connections.remove(c);
10088 }
10089 mServiceConnections.remove(binder);
10090
10091 if (b.connections.size() == 0) {
10092 b.intent.apps.remove(b.client);
10093 }
10094
10095 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10096 + ": shouldUnbind=" + b.intent.hasBound);
10097 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10098 && b.intent.hasBound) {
10099 try {
10100 bumpServiceExecutingLocked(s);
10101 updateOomAdjLocked(s.app);
10102 b.intent.hasBound = false;
10103 // Assume the client doesn't want to know about a rebind;
10104 // we will deal with that later if it asks for one.
10105 b.intent.doRebind = false;
10106 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10107 } catch (Exception e) {
10108 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10109 serviceDoneExecutingLocked(s, true);
10110 }
10111 }
10112
10113 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10114 bringDownServiceLocked(s, false);
10115 }
10116 }
10117
10118 public boolean unbindService(IServiceConnection connection) {
10119 synchronized (this) {
10120 IBinder binder = connection.asBinder();
10121 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10122 ConnectionRecord r = mServiceConnections.get(binder);
10123 if (r == null) {
10124 Log.w(TAG, "Unbind failed: could not find connection for "
10125 + connection.asBinder());
10126 return false;
10127 }
10128
10129 final long origId = Binder.clearCallingIdentity();
10130
10131 removeConnectionLocked(r, null, null);
10132
10133 if (r.binding.service.app != null) {
10134 // This could have made the service less important.
10135 updateOomAdjLocked(r.binding.service.app);
10136 }
10137
10138 Binder.restoreCallingIdentity(origId);
10139 }
10140
10141 return true;
10142 }
10143
10144 public void publishService(IBinder token, Intent intent, IBinder service) {
10145 // Refuse possible leaked file descriptors
10146 if (intent != null && intent.hasFileDescriptors() == true) {
10147 throw new IllegalArgumentException("File descriptors passed in Intent");
10148 }
10149
10150 synchronized(this) {
10151 if (!(token instanceof ServiceRecord)) {
10152 throw new IllegalArgumentException("Invalid service token");
10153 }
10154 ServiceRecord r = (ServiceRecord)token;
10155
10156 final long origId = Binder.clearCallingIdentity();
10157
10158 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10159 + " " + intent + ": " + service);
10160 if (r != null) {
10161 Intent.FilterComparison filter
10162 = new Intent.FilterComparison(intent);
10163 IntentBindRecord b = r.bindings.get(filter);
10164 if (b != null && !b.received) {
10165 b.binder = service;
10166 b.requested = true;
10167 b.received = true;
10168 if (r.connections.size() > 0) {
10169 Iterator<ConnectionRecord> it
10170 = r.connections.values().iterator();
10171 while (it.hasNext()) {
10172 ConnectionRecord c = it.next();
10173 if (!filter.equals(c.binding.intent.intent)) {
10174 if (DEBUG_SERVICE) Log.v(
10175 TAG, "Not publishing to: " + c);
10176 if (DEBUG_SERVICE) Log.v(
10177 TAG, "Bound intent: " + c.binding.intent.intent);
10178 if (DEBUG_SERVICE) Log.v(
10179 TAG, "Published intent: " + intent);
10180 continue;
10181 }
10182 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10183 try {
10184 c.conn.connected(r.name, service);
10185 } catch (Exception e) {
10186 Log.w(TAG, "Failure sending service " + r.name +
10187 " to connection " + c.conn.asBinder() +
10188 " (in " + c.binding.client.processName + ")", e);
10189 }
10190 }
10191 }
10192 }
10193
10194 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10195
10196 Binder.restoreCallingIdentity(origId);
10197 }
10198 }
10199 }
10200
10201 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10202 // Refuse possible leaked file descriptors
10203 if (intent != null && intent.hasFileDescriptors() == true) {
10204 throw new IllegalArgumentException("File descriptors passed in Intent");
10205 }
10206
10207 synchronized(this) {
10208 if (!(token instanceof ServiceRecord)) {
10209 throw new IllegalArgumentException("Invalid service token");
10210 }
10211 ServiceRecord r = (ServiceRecord)token;
10212
10213 final long origId = Binder.clearCallingIdentity();
10214
10215 if (r != null) {
10216 Intent.FilterComparison filter
10217 = new Intent.FilterComparison(intent);
10218 IntentBindRecord b = r.bindings.get(filter);
10219 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10220 + " at " + b + ": apps="
10221 + (b != null ? b.apps.size() : 0));
10222 if (b != null) {
10223 if (b.apps.size() > 0) {
10224 // Applications have already bound since the last
10225 // unbind, so just rebind right here.
10226 requestServiceBindingLocked(r, b, true);
10227 } else {
10228 // Note to tell the service the next time there is
10229 // a new client.
10230 b.doRebind = true;
10231 }
10232 }
10233
10234 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10235
10236 Binder.restoreCallingIdentity(origId);
10237 }
10238 }
10239 }
10240
10241 public void serviceDoneExecuting(IBinder token) {
10242 synchronized(this) {
10243 if (!(token instanceof ServiceRecord)) {
10244 throw new IllegalArgumentException("Invalid service token");
10245 }
10246 ServiceRecord r = (ServiceRecord)token;
10247 boolean inStopping = mStoppingServices.contains(token);
10248 if (r != null) {
10249 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10250 + ": nesting=" + r.executeNesting
10251 + ", inStopping=" + inStopping);
10252 if (r != token) {
10253 Log.w(TAG, "Done executing service " + r.name
10254 + " with incorrect token: given " + token
10255 + ", expected " + r);
10256 return;
10257 }
10258
10259 final long origId = Binder.clearCallingIdentity();
10260 serviceDoneExecutingLocked(r, inStopping);
10261 Binder.restoreCallingIdentity(origId);
10262 } else {
10263 Log.w(TAG, "Done executing unknown service " + r.name
10264 + " with token " + token);
10265 }
10266 }
10267 }
10268
10269 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10270 r.executeNesting--;
10271 if (r.executeNesting <= 0 && r.app != null) {
10272 r.app.executingServices.remove(r);
10273 if (r.app.executingServices.size() == 0) {
10274 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10275 }
10276 if (inStopping) {
10277 mStoppingServices.remove(r);
10278 }
10279 updateOomAdjLocked(r.app);
10280 }
10281 }
10282
10283 void serviceTimeout(ProcessRecord proc) {
10284 synchronized(this) {
10285 if (proc.executingServices.size() == 0 || proc.thread == null) {
10286 return;
10287 }
10288 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10289 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10290 ServiceRecord timeout = null;
10291 long nextTime = 0;
10292 while (it.hasNext()) {
10293 ServiceRecord sr = it.next();
10294 if (sr.executingStart < maxTime) {
10295 timeout = sr;
10296 break;
10297 }
10298 if (sr.executingStart > nextTime) {
10299 nextTime = sr.executingStart;
10300 }
10301 }
10302 if (timeout != null && mLRUProcesses.contains(proc)) {
10303 Log.w(TAG, "Timeout executing service: " + timeout);
10304 appNotRespondingLocked(proc, null, "Executing service "
10305 + timeout.name);
10306 } else {
10307 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10308 msg.obj = proc;
10309 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10310 }
10311 }
10312 }
10313
10314 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010315 // BACKUP AND RESTORE
10316 // =========================================================
10317
10318 // Cause the target app to be launched if necessary and its backup agent
10319 // instantiated. The backup agent will invoke backupAgentCreated() on the
10320 // activity manager to announce its creation.
10321 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10322 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10323 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10324
10325 synchronized(this) {
10326 // !!! TODO: currently no check here that we're already bound
10327 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10328 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10329 synchronized (stats) {
10330 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10331 }
10332
10333 BackupRecord r = new BackupRecord(ss, app, backupMode);
10334 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10335 // startProcessLocked() returns existing proc's record if it's already running
10336 ProcessRecord proc = startProcessLocked(app.processName, app,
10337 false, 0, "backup", hostingName);
10338 if (proc == null) {
10339 Log.e(TAG, "Unable to start backup agent process " + r);
10340 return false;
10341 }
10342
10343 r.app = proc;
10344 mBackupTarget = r;
10345 mBackupAppName = app.packageName;
10346
10347 // If the process is already attached, schedule the creation of the backup agent now.
10348 // If it is not yet live, this will be done when it attaches to the framework.
10349 if (proc.thread != null) {
10350 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10351 try {
10352 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10353 } catch (RemoteException e) {
10354 // !!! TODO: notify the backup manager that we crashed, or rely on
10355 // death notices, or...?
10356 }
10357 } else {
10358 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10359 }
10360 // Invariants: at this point, the target app process exists and the application
10361 // is either already running or in the process of coming up. mBackupTarget and
10362 // mBackupAppName describe the app, so that when it binds back to the AM we
10363 // know that it's scheduled for a backup-agent operation.
10364 }
10365
10366 return true;
10367 }
10368
10369 // A backup agent has just come up
10370 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10371 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10372 + " = " + agent);
10373
10374 synchronized(this) {
10375 if (!agentPackageName.equals(mBackupAppName)) {
10376 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10377 return;
10378 }
10379
10380 try {
10381 IBackupManager bm = IBackupManager.Stub.asInterface(
10382 ServiceManager.getService(Context.BACKUP_SERVICE));
10383 bm.agentConnected(agentPackageName, agent);
10384 } catch (RemoteException e) {
10385 // can't happen; the backup manager service is local
10386 } catch (Exception e) {
10387 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10388 e.printStackTrace();
10389 }
10390 }
10391 }
10392
10393 // done with this agent
10394 public void unbindBackupAgent(ApplicationInfo appInfo) {
10395 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
10396
10397 synchronized(this) {
10398 if (!mBackupAppName.equals(appInfo.packageName)) {
10399 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10400 return;
10401 }
10402
10403 try {
10404 mBackupTarget.app.thread.scheduleDestroyBackupAgent(appInfo);
10405 } catch (Exception e) {
10406 Log.e(TAG, "Exception when unbinding backup agent:");
10407 e.printStackTrace();
10408 }
10409 mBackupTarget = null;
10410 mBackupAppName = null;
10411 }
10412 }
10413 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010414 // BROADCASTS
10415 // =========================================================
10416
10417 private final List getStickies(String action, IntentFilter filter,
10418 List cur) {
10419 final ContentResolver resolver = mContext.getContentResolver();
10420 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10421 if (list == null) {
10422 return cur;
10423 }
10424 int N = list.size();
10425 for (int i=0; i<N; i++) {
10426 Intent intent = list.get(i);
10427 if (filter.match(resolver, intent, true, TAG) >= 0) {
10428 if (cur == null) {
10429 cur = new ArrayList<Intent>();
10430 }
10431 cur.add(intent);
10432 }
10433 }
10434 return cur;
10435 }
10436
10437 private final void scheduleBroadcastsLocked() {
10438 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10439 + mBroadcastsScheduled);
10440
10441 if (mBroadcastsScheduled) {
10442 return;
10443 }
10444 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10445 mBroadcastsScheduled = true;
10446 }
10447
10448 public Intent registerReceiver(IApplicationThread caller,
10449 IIntentReceiver receiver, IntentFilter filter, String permission) {
10450 synchronized(this) {
10451 ProcessRecord callerApp = null;
10452 if (caller != null) {
10453 callerApp = getRecordForAppLocked(caller);
10454 if (callerApp == null) {
10455 throw new SecurityException(
10456 "Unable to find app for caller " + caller
10457 + " (pid=" + Binder.getCallingPid()
10458 + ") when registering receiver " + receiver);
10459 }
10460 }
10461
10462 List allSticky = null;
10463
10464 // Look for any matching sticky broadcasts...
10465 Iterator actions = filter.actionsIterator();
10466 if (actions != null) {
10467 while (actions.hasNext()) {
10468 String action = (String)actions.next();
10469 allSticky = getStickies(action, filter, allSticky);
10470 }
10471 } else {
10472 allSticky = getStickies(null, filter, allSticky);
10473 }
10474
10475 // The first sticky in the list is returned directly back to
10476 // the client.
10477 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10478
10479 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10480 + ": " + sticky);
10481
10482 if (receiver == null) {
10483 return sticky;
10484 }
10485
10486 ReceiverList rl
10487 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10488 if (rl == null) {
10489 rl = new ReceiverList(this, callerApp,
10490 Binder.getCallingPid(),
10491 Binder.getCallingUid(), receiver);
10492 if (rl.app != null) {
10493 rl.app.receivers.add(rl);
10494 } else {
10495 try {
10496 receiver.asBinder().linkToDeath(rl, 0);
10497 } catch (RemoteException e) {
10498 return sticky;
10499 }
10500 rl.linkedToDeath = true;
10501 }
10502 mRegisteredReceivers.put(receiver.asBinder(), rl);
10503 }
10504 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10505 rl.add(bf);
10506 if (!bf.debugCheck()) {
10507 Log.w(TAG, "==> For Dynamic broadast");
10508 }
10509 mReceiverResolver.addFilter(bf);
10510
10511 // Enqueue broadcasts for all existing stickies that match
10512 // this filter.
10513 if (allSticky != null) {
10514 ArrayList receivers = new ArrayList();
10515 receivers.add(bf);
10516
10517 int N = allSticky.size();
10518 for (int i=0; i<N; i++) {
10519 Intent intent = (Intent)allSticky.get(i);
10520 BroadcastRecord r = new BroadcastRecord(intent, null,
10521 null, -1, -1, null, receivers, null, 0, null, null,
10522 false);
10523 if (mParallelBroadcasts.size() == 0) {
10524 scheduleBroadcastsLocked();
10525 }
10526 mParallelBroadcasts.add(r);
10527 }
10528 }
10529
10530 return sticky;
10531 }
10532 }
10533
10534 public void unregisterReceiver(IIntentReceiver receiver) {
10535 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10536
10537 boolean doNext = false;
10538
10539 synchronized(this) {
10540 ReceiverList rl
10541 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10542 if (rl != null) {
10543 if (rl.curBroadcast != null) {
10544 BroadcastRecord r = rl.curBroadcast;
10545 doNext = finishReceiverLocked(
10546 receiver.asBinder(), r.resultCode, r.resultData,
10547 r.resultExtras, r.resultAbort, true);
10548 }
10549
10550 if (rl.app != null) {
10551 rl.app.receivers.remove(rl);
10552 }
10553 removeReceiverLocked(rl);
10554 if (rl.linkedToDeath) {
10555 rl.linkedToDeath = false;
10556 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10557 }
10558 }
10559 }
10560
10561 if (!doNext) {
10562 return;
10563 }
10564
10565 final long origId = Binder.clearCallingIdentity();
10566 processNextBroadcast(false);
10567 trimApplications();
10568 Binder.restoreCallingIdentity(origId);
10569 }
10570
10571 void removeReceiverLocked(ReceiverList rl) {
10572 mRegisteredReceivers.remove(rl.receiver.asBinder());
10573 int N = rl.size();
10574 for (int i=0; i<N; i++) {
10575 mReceiverResolver.removeFilter(rl.get(i));
10576 }
10577 }
10578
10579 private final int broadcastIntentLocked(ProcessRecord callerApp,
10580 String callerPackage, Intent intent, String resolvedType,
10581 IIntentReceiver resultTo, int resultCode, String resultData,
10582 Bundle map, String requiredPermission,
10583 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10584 intent = new Intent(intent);
10585
10586 if (DEBUG_BROADCAST) Log.v(
10587 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10588 + " ordered=" + ordered);
10589 if ((resultTo != null) && !ordered) {
10590 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10591 }
10592
10593 // Handle special intents: if this broadcast is from the package
10594 // manager about a package being removed, we need to remove all of
10595 // its activities from the history stack.
10596 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10597 intent.getAction());
10598 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10599 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10600 || uidRemoved) {
10601 if (checkComponentPermission(
10602 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10603 callingPid, callingUid, -1)
10604 == PackageManager.PERMISSION_GRANTED) {
10605 if (uidRemoved) {
10606 final Bundle intentExtras = intent.getExtras();
10607 final int uid = intentExtras != null
10608 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10609 if (uid >= 0) {
10610 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10611 synchronized (bs) {
10612 bs.removeUidStatsLocked(uid);
10613 }
10614 }
10615 } else {
10616 Uri data = intent.getData();
10617 String ssp;
10618 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10619 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10620 uninstallPackageLocked(ssp,
10621 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10622 }
10623 }
10624 }
10625 } else {
10626 String msg = "Permission Denial: " + intent.getAction()
10627 + " broadcast from " + callerPackage + " (pid=" + callingPid
10628 + ", uid=" + callingUid + ")"
10629 + " requires "
10630 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10631 Log.w(TAG, msg);
10632 throw new SecurityException(msg);
10633 }
10634 }
10635
10636 /*
10637 * If this is the time zone changed action, queue up a message that will reset the timezone
10638 * of all currently running processes. This message will get queued up before the broadcast
10639 * happens.
10640 */
10641 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10642 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10643 }
10644
10645 // Add to the sticky list if requested.
10646 if (sticky) {
10647 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10648 callingPid, callingUid)
10649 != PackageManager.PERMISSION_GRANTED) {
10650 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10651 + callingPid + ", uid=" + callingUid
10652 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10653 Log.w(TAG, msg);
10654 throw new SecurityException(msg);
10655 }
10656 if (requiredPermission != null) {
10657 Log.w(TAG, "Can't broadcast sticky intent " + intent
10658 + " and enforce permission " + requiredPermission);
10659 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10660 }
10661 if (intent.getComponent() != null) {
10662 throw new SecurityException(
10663 "Sticky broadcasts can't target a specific component");
10664 }
10665 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10666 if (list == null) {
10667 list = new ArrayList<Intent>();
10668 mStickyBroadcasts.put(intent.getAction(), list);
10669 }
10670 int N = list.size();
10671 int i;
10672 for (i=0; i<N; i++) {
10673 if (intent.filterEquals(list.get(i))) {
10674 // This sticky already exists, replace it.
10675 list.set(i, new Intent(intent));
10676 break;
10677 }
10678 }
10679 if (i >= N) {
10680 list.add(new Intent(intent));
10681 }
10682 }
10683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010684 // Figure out who all will receive this broadcast.
10685 List receivers = null;
10686 List<BroadcastFilter> registeredReceivers = null;
10687 try {
10688 if (intent.getComponent() != null) {
10689 // Broadcast is going to one specific receiver class...
10690 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010691 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010692 if (ai != null) {
10693 receivers = new ArrayList();
10694 ResolveInfo ri = new ResolveInfo();
10695 ri.activityInfo = ai;
10696 receivers.add(ri);
10697 }
10698 } else {
10699 // Need to resolve the intent to interested receivers...
10700 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10701 == 0) {
10702 receivers =
10703 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010704 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010705 }
Mihai Preda074edef2009-05-18 17:13:31 +020010706 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010707 }
10708 } catch (RemoteException ex) {
10709 // pm is in same process, this will never happen.
10710 }
10711
10712 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10713 if (!ordered && NR > 0) {
10714 // If we are not serializing this broadcast, then send the
10715 // registered receivers separately so they don't wait for the
10716 // components to be launched.
10717 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10718 callerPackage, callingPid, callingUid, requiredPermission,
10719 registeredReceivers, resultTo, resultCode, resultData, map,
10720 ordered);
10721 if (DEBUG_BROADCAST) Log.v(
10722 TAG, "Enqueueing parallel broadcast " + r
10723 + ": prev had " + mParallelBroadcasts.size());
10724 mParallelBroadcasts.add(r);
10725 scheduleBroadcastsLocked();
10726 registeredReceivers = null;
10727 NR = 0;
10728 }
10729
10730 // Merge into one list.
10731 int ir = 0;
10732 if (receivers != null) {
10733 // A special case for PACKAGE_ADDED: do not allow the package
10734 // being added to see this broadcast. This prevents them from
10735 // using this as a back door to get run as soon as they are
10736 // installed. Maybe in the future we want to have a special install
10737 // broadcast or such for apps, but we'd like to deliberately make
10738 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010739 boolean skip = false;
10740 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010741 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010742 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10743 skip = true;
10744 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10745 skip = true;
10746 }
10747 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010748 ? intent.getData().getSchemeSpecificPart()
10749 : null;
10750 if (skipPackage != null && receivers != null) {
10751 int NT = receivers.size();
10752 for (int it=0; it<NT; it++) {
10753 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10754 if (curt.activityInfo.packageName.equals(skipPackage)) {
10755 receivers.remove(it);
10756 it--;
10757 NT--;
10758 }
10759 }
10760 }
10761
10762 int NT = receivers != null ? receivers.size() : 0;
10763 int it = 0;
10764 ResolveInfo curt = null;
10765 BroadcastFilter curr = null;
10766 while (it < NT && ir < NR) {
10767 if (curt == null) {
10768 curt = (ResolveInfo)receivers.get(it);
10769 }
10770 if (curr == null) {
10771 curr = registeredReceivers.get(ir);
10772 }
10773 if (curr.getPriority() >= curt.priority) {
10774 // Insert this broadcast record into the final list.
10775 receivers.add(it, curr);
10776 ir++;
10777 curr = null;
10778 it++;
10779 NT++;
10780 } else {
10781 // Skip to the next ResolveInfo in the final list.
10782 it++;
10783 curt = null;
10784 }
10785 }
10786 }
10787 while (ir < NR) {
10788 if (receivers == null) {
10789 receivers = new ArrayList();
10790 }
10791 receivers.add(registeredReceivers.get(ir));
10792 ir++;
10793 }
10794
10795 if ((receivers != null && receivers.size() > 0)
10796 || resultTo != null) {
10797 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10798 callerPackage, callingPid, callingUid, requiredPermission,
10799 receivers, resultTo, resultCode, resultData, map, ordered);
10800 if (DEBUG_BROADCAST) Log.v(
10801 TAG, "Enqueueing ordered broadcast " + r
10802 + ": prev had " + mOrderedBroadcasts.size());
10803 if (DEBUG_BROADCAST) {
10804 int seq = r.intent.getIntExtra("seq", -1);
10805 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10806 }
10807 mOrderedBroadcasts.add(r);
10808 scheduleBroadcastsLocked();
10809 }
10810
10811 return BROADCAST_SUCCESS;
10812 }
10813
10814 public final int broadcastIntent(IApplicationThread caller,
10815 Intent intent, String resolvedType, IIntentReceiver resultTo,
10816 int resultCode, String resultData, Bundle map,
10817 String requiredPermission, boolean serialized, boolean sticky) {
10818 // Refuse possible leaked file descriptors
10819 if (intent != null && intent.hasFileDescriptors() == true) {
10820 throw new IllegalArgumentException("File descriptors passed in Intent");
10821 }
10822
10823 synchronized(this) {
10824 if (!mSystemReady) {
10825 // if the caller really truly claims to know what they're doing, go
10826 // ahead and allow the broadcast without launching any receivers
10827 int flags = intent.getFlags();
10828 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10829 intent = new Intent(intent);
10830 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10831 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10832 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10833 + " before boot completion");
10834 throw new IllegalStateException("Cannot broadcast before boot completed");
10835 }
10836 }
10837
10838 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10839 final int callingPid = Binder.getCallingPid();
10840 final int callingUid = Binder.getCallingUid();
10841 final long origId = Binder.clearCallingIdentity();
10842 int res = broadcastIntentLocked(callerApp,
10843 callerApp != null ? callerApp.info.packageName : null,
10844 intent, resolvedType, resultTo,
10845 resultCode, resultData, map, requiredPermission, serialized,
10846 sticky, callingPid, callingUid);
10847 Binder.restoreCallingIdentity(origId);
10848 return res;
10849 }
10850 }
10851
10852 int broadcastIntentInPackage(String packageName, int uid,
10853 Intent intent, String resolvedType, IIntentReceiver resultTo,
10854 int resultCode, String resultData, Bundle map,
10855 String requiredPermission, boolean serialized, boolean sticky) {
10856 synchronized(this) {
10857 final long origId = Binder.clearCallingIdentity();
10858 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10859 resultTo, resultCode, resultData, map, requiredPermission,
10860 serialized, sticky, -1, uid);
10861 Binder.restoreCallingIdentity(origId);
10862 return res;
10863 }
10864 }
10865
10866 public final void unbroadcastIntent(IApplicationThread caller,
10867 Intent intent) {
10868 // Refuse possible leaked file descriptors
10869 if (intent != null && intent.hasFileDescriptors() == true) {
10870 throw new IllegalArgumentException("File descriptors passed in Intent");
10871 }
10872
10873 synchronized(this) {
10874 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10875 != PackageManager.PERMISSION_GRANTED) {
10876 String msg = "Permission Denial: unbroadcastIntent() from pid="
10877 + Binder.getCallingPid()
10878 + ", uid=" + Binder.getCallingUid()
10879 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10880 Log.w(TAG, msg);
10881 throw new SecurityException(msg);
10882 }
10883 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10884 if (list != null) {
10885 int N = list.size();
10886 int i;
10887 for (i=0; i<N; i++) {
10888 if (intent.filterEquals(list.get(i))) {
10889 list.remove(i);
10890 break;
10891 }
10892 }
10893 }
10894 }
10895 }
10896
10897 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10898 String resultData, Bundle resultExtras, boolean resultAbort,
10899 boolean explicit) {
10900 if (mOrderedBroadcasts.size() == 0) {
10901 if (explicit) {
10902 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10903 }
10904 return false;
10905 }
10906 BroadcastRecord r = mOrderedBroadcasts.get(0);
10907 if (r.receiver == null) {
10908 if (explicit) {
10909 Log.w(TAG, "finishReceiver called but none active");
10910 }
10911 return false;
10912 }
10913 if (r.receiver != receiver) {
10914 Log.w(TAG, "finishReceiver called but active receiver is different");
10915 return false;
10916 }
10917 int state = r.state;
10918 r.state = r.IDLE;
10919 if (state == r.IDLE) {
10920 if (explicit) {
10921 Log.w(TAG, "finishReceiver called but state is IDLE");
10922 }
10923 }
10924 r.receiver = null;
10925 r.intent.setComponent(null);
10926 if (r.curApp != null) {
10927 r.curApp.curReceiver = null;
10928 }
10929 if (r.curFilter != null) {
10930 r.curFilter.receiverList.curBroadcast = null;
10931 }
10932 r.curFilter = null;
10933 r.curApp = null;
10934 r.curComponent = null;
10935 r.curReceiver = null;
10936 mPendingBroadcast = null;
10937
10938 r.resultCode = resultCode;
10939 r.resultData = resultData;
10940 r.resultExtras = resultExtras;
10941 r.resultAbort = resultAbort;
10942
10943 // We will process the next receiver right now if this is finishing
10944 // an app receiver (which is always asynchronous) or after we have
10945 // come back from calling a receiver.
10946 return state == BroadcastRecord.APP_RECEIVE
10947 || state == BroadcastRecord.CALL_DONE_RECEIVE;
10948 }
10949
10950 public void finishReceiver(IBinder who, int resultCode, String resultData,
10951 Bundle resultExtras, boolean resultAbort) {
10952 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
10953
10954 // Refuse possible leaked file descriptors
10955 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
10956 throw new IllegalArgumentException("File descriptors passed in Bundle");
10957 }
10958
10959 boolean doNext;
10960
10961 final long origId = Binder.clearCallingIdentity();
10962
10963 synchronized(this) {
10964 doNext = finishReceiverLocked(
10965 who, resultCode, resultData, resultExtras, resultAbort, true);
10966 }
10967
10968 if (doNext) {
10969 processNextBroadcast(false);
10970 }
10971 trimApplications();
10972
10973 Binder.restoreCallingIdentity(origId);
10974 }
10975
10976 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
10977 if (r.nextReceiver > 0) {
10978 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10979 if (curReceiver instanceof BroadcastFilter) {
10980 BroadcastFilter bf = (BroadcastFilter) curReceiver;
10981 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
10982 System.identityHashCode(r),
10983 r.intent.getAction(),
10984 r.nextReceiver - 1,
10985 System.identityHashCode(bf));
10986 } else {
10987 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10988 System.identityHashCode(r),
10989 r.intent.getAction(),
10990 r.nextReceiver - 1,
10991 ((ResolveInfo)curReceiver).toString());
10992 }
10993 } else {
10994 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
10995 + r);
10996 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
10997 System.identityHashCode(r),
10998 r.intent.getAction(),
10999 r.nextReceiver,
11000 "NONE");
11001 }
11002 }
11003
11004 private final void broadcastTimeout() {
11005 synchronized (this) {
11006 if (mOrderedBroadcasts.size() == 0) {
11007 return;
11008 }
11009 long now = SystemClock.uptimeMillis();
11010 BroadcastRecord r = mOrderedBroadcasts.get(0);
11011 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11012 if (DEBUG_BROADCAST) Log.v(TAG,
11013 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11014 + (r.startTime + BROADCAST_TIMEOUT));
11015 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11016 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11017 return;
11018 }
11019
11020 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11021 r.startTime = now;
11022 r.anrCount++;
11023
11024 // Current receiver has passed its expiration date.
11025 if (r.nextReceiver <= 0) {
11026 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11027 return;
11028 }
11029
11030 ProcessRecord app = null;
11031
11032 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11033 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11034 logBroadcastReceiverDiscard(r);
11035 if (curReceiver instanceof BroadcastFilter) {
11036 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11037 if (bf.receiverList.pid != 0
11038 && bf.receiverList.pid != MY_PID) {
11039 synchronized (this.mPidsSelfLocked) {
11040 app = this.mPidsSelfLocked.get(
11041 bf.receiverList.pid);
11042 }
11043 }
11044 } else {
11045 app = r.curApp;
11046 }
11047
11048 if (app != null) {
11049 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11050 }
11051
11052 if (mPendingBroadcast == r) {
11053 mPendingBroadcast = null;
11054 }
11055
11056 // Move on to the next receiver.
11057 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11058 r.resultExtras, r.resultAbort, true);
11059 scheduleBroadcastsLocked();
11060 }
11061 }
11062
11063 private final void processCurBroadcastLocked(BroadcastRecord r,
11064 ProcessRecord app) throws RemoteException {
11065 if (app.thread == null) {
11066 throw new RemoteException();
11067 }
11068 r.receiver = app.thread.asBinder();
11069 r.curApp = app;
11070 app.curReceiver = r;
11071 updateLRUListLocked(app, true);
11072
11073 // Tell the application to launch this receiver.
11074 r.intent.setComponent(r.curComponent);
11075
11076 boolean started = false;
11077 try {
11078 if (DEBUG_BROADCAST) Log.v(TAG,
11079 "Delivering to component " + r.curComponent
11080 + ": " + r);
11081 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11082 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11083 started = true;
11084 } finally {
11085 if (!started) {
11086 r.receiver = null;
11087 r.curApp = null;
11088 app.curReceiver = null;
11089 }
11090 }
11091
11092 }
11093
11094 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11095 Intent intent, int resultCode, String data,
11096 Bundle extras, boolean ordered) throws RemoteException {
11097 if (app != null && app.thread != null) {
11098 // If we have an app thread, do the call through that so it is
11099 // correctly ordered with other one-way calls.
11100 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11101 data, extras, ordered);
11102 } else {
11103 receiver.performReceive(intent, resultCode, data, extras, ordered);
11104 }
11105 }
11106
11107 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11108 BroadcastFilter filter, boolean ordered) {
11109 boolean skip = false;
11110 if (filter.requiredPermission != null) {
11111 int perm = checkComponentPermission(filter.requiredPermission,
11112 r.callingPid, r.callingUid, -1);
11113 if (perm != PackageManager.PERMISSION_GRANTED) {
11114 Log.w(TAG, "Permission Denial: broadcasting "
11115 + r.intent.toString()
11116 + " from " + r.callerPackage + " (pid="
11117 + r.callingPid + ", uid=" + r.callingUid + ")"
11118 + " requires " + filter.requiredPermission
11119 + " due to registered receiver " + filter);
11120 skip = true;
11121 }
11122 }
11123 if (r.requiredPermission != null) {
11124 int perm = checkComponentPermission(r.requiredPermission,
11125 filter.receiverList.pid, filter.receiverList.uid, -1);
11126 if (perm != PackageManager.PERMISSION_GRANTED) {
11127 Log.w(TAG, "Permission Denial: receiving "
11128 + r.intent.toString()
11129 + " to " + filter.receiverList.app
11130 + " (pid=" + filter.receiverList.pid
11131 + ", uid=" + filter.receiverList.uid + ")"
11132 + " requires " + r.requiredPermission
11133 + " due to sender " + r.callerPackage
11134 + " (uid " + r.callingUid + ")");
11135 skip = true;
11136 }
11137 }
11138
11139 if (!skip) {
11140 // If this is not being sent as an ordered broadcast, then we
11141 // don't want to touch the fields that keep track of the current
11142 // state of ordered broadcasts.
11143 if (ordered) {
11144 r.receiver = filter.receiverList.receiver.asBinder();
11145 r.curFilter = filter;
11146 filter.receiverList.curBroadcast = r;
11147 r.state = BroadcastRecord.CALL_IN_RECEIVE;
11148 }
11149 try {
11150 if (DEBUG_BROADCAST) {
11151 int seq = r.intent.getIntExtra("seq", -1);
11152 Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
11153 + " app=" + filter.receiverList.app);
11154 }
11155 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11156 new Intent(r.intent), r.resultCode,
11157 r.resultData, r.resultExtras, r.ordered);
11158 if (ordered) {
11159 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11160 }
11161 } catch (RemoteException e) {
11162 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11163 if (ordered) {
11164 r.receiver = null;
11165 r.curFilter = null;
11166 filter.receiverList.curBroadcast = null;
11167 }
11168 }
11169 }
11170 }
11171
11172 private final void processNextBroadcast(boolean fromMsg) {
11173 synchronized(this) {
11174 BroadcastRecord r;
11175
11176 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11177 + mParallelBroadcasts.size() + " broadcasts, "
11178 + mOrderedBroadcasts.size() + " serialized broadcasts");
11179
11180 updateCpuStats();
11181
11182 if (fromMsg) {
11183 mBroadcastsScheduled = false;
11184 }
11185
11186 // First, deliver any non-serialized broadcasts right away.
11187 while (mParallelBroadcasts.size() > 0) {
11188 r = mParallelBroadcasts.remove(0);
11189 final int N = r.receivers.size();
11190 for (int i=0; i<N; i++) {
11191 Object target = r.receivers.get(i);
11192 if (DEBUG_BROADCAST) Log.v(TAG,
11193 "Delivering non-serialized to registered "
11194 + target + ": " + r);
11195 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11196 }
11197 }
11198
11199 // Now take care of the next serialized one...
11200
11201 // If we are waiting for a process to come up to handle the next
11202 // broadcast, then do nothing at this point. Just in case, we
11203 // check that the process we're waiting for still exists.
11204 if (mPendingBroadcast != null) {
11205 Log.i(TAG, "processNextBroadcast: waiting for "
11206 + mPendingBroadcast.curApp);
11207
11208 boolean isDead;
11209 synchronized (mPidsSelfLocked) {
11210 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11211 }
11212 if (!isDead) {
11213 // It's still alive, so keep waiting
11214 return;
11215 } else {
11216 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11217 + " died before responding to broadcast");
11218 mPendingBroadcast = null;
11219 }
11220 }
11221
11222 do {
11223 if (mOrderedBroadcasts.size() == 0) {
11224 // No more broadcasts pending, so all done!
11225 scheduleAppGcsLocked();
11226 return;
11227 }
11228 r = mOrderedBroadcasts.get(0);
11229 boolean forceReceive = false;
11230
11231 // Ensure that even if something goes awry with the timeout
11232 // detection, we catch "hung" broadcasts here, discard them,
11233 // and continue to make progress.
11234 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11235 long now = SystemClock.uptimeMillis();
11236 if (r.dispatchTime > 0) {
11237 if ((numReceivers > 0) &&
11238 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11239 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11240 + " now=" + now
11241 + " dispatchTime=" + r.dispatchTime
11242 + " startTime=" + r.startTime
11243 + " intent=" + r.intent
11244 + " numReceivers=" + numReceivers
11245 + " nextReceiver=" + r.nextReceiver
11246 + " state=" + r.state);
11247 broadcastTimeout(); // forcibly finish this broadcast
11248 forceReceive = true;
11249 r.state = BroadcastRecord.IDLE;
11250 }
11251 }
11252
11253 if (r.state != BroadcastRecord.IDLE) {
11254 if (DEBUG_BROADCAST) Log.d(TAG,
11255 "processNextBroadcast() called when not idle (state="
11256 + r.state + ")");
11257 return;
11258 }
11259
11260 if (r.receivers == null || r.nextReceiver >= numReceivers
11261 || r.resultAbort || forceReceive) {
11262 // No more receivers for this broadcast! Send the final
11263 // result if requested...
11264 if (r.resultTo != null) {
11265 try {
11266 if (DEBUG_BROADCAST) {
11267 int seq = r.intent.getIntExtra("seq", -1);
11268 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11269 + " seq=" + seq + " app=" + r.callerApp);
11270 }
11271 performReceive(r.callerApp, r.resultTo,
11272 new Intent(r.intent), r.resultCode,
11273 r.resultData, r.resultExtras, false);
11274 } catch (RemoteException e) {
11275 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11276 }
11277 }
11278
11279 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11280 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11281
11282 // ... and on to the next...
11283 mOrderedBroadcasts.remove(0);
11284 r = null;
11285 continue;
11286 }
11287 } while (r == null);
11288
11289 // Get the next receiver...
11290 int recIdx = r.nextReceiver++;
11291
11292 // Keep track of when this receiver started, and make sure there
11293 // is a timeout message pending to kill it if need be.
11294 r.startTime = SystemClock.uptimeMillis();
11295 if (recIdx == 0) {
11296 r.dispatchTime = r.startTime;
11297
11298 if (DEBUG_BROADCAST) Log.v(TAG,
11299 "Submitting BROADCAST_TIMEOUT_MSG for "
11300 + (r.startTime + BROADCAST_TIMEOUT));
11301 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11302 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11303 }
11304
11305 Object nextReceiver = r.receivers.get(recIdx);
11306 if (nextReceiver instanceof BroadcastFilter) {
11307 // Simple case: this is a registered receiver who gets
11308 // a direct call.
11309 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11310 if (DEBUG_BROADCAST) Log.v(TAG,
11311 "Delivering serialized to registered "
11312 + filter + ": " + r);
11313 deliverToRegisteredReceiver(r, filter, r.ordered);
11314 if (r.receiver == null || !r.ordered) {
11315 // The receiver has already finished, so schedule to
11316 // process the next one.
11317 r.state = BroadcastRecord.IDLE;
11318 scheduleBroadcastsLocked();
11319 }
11320 return;
11321 }
11322
11323 // Hard case: need to instantiate the receiver, possibly
11324 // starting its application process to host it.
11325
11326 ResolveInfo info =
11327 (ResolveInfo)nextReceiver;
11328
11329 boolean skip = false;
11330 int perm = checkComponentPermission(info.activityInfo.permission,
11331 r.callingPid, r.callingUid,
11332 info.activityInfo.exported
11333 ? -1 : info.activityInfo.applicationInfo.uid);
11334 if (perm != PackageManager.PERMISSION_GRANTED) {
11335 Log.w(TAG, "Permission Denial: broadcasting "
11336 + r.intent.toString()
11337 + " from " + r.callerPackage + " (pid=" + r.callingPid
11338 + ", uid=" + r.callingUid + ")"
11339 + " requires " + info.activityInfo.permission
11340 + " due to receiver " + info.activityInfo.packageName
11341 + "/" + info.activityInfo.name);
11342 skip = true;
11343 }
11344 if (r.callingUid != Process.SYSTEM_UID &&
11345 r.requiredPermission != null) {
11346 try {
11347 perm = ActivityThread.getPackageManager().
11348 checkPermission(r.requiredPermission,
11349 info.activityInfo.applicationInfo.packageName);
11350 } catch (RemoteException e) {
11351 perm = PackageManager.PERMISSION_DENIED;
11352 }
11353 if (perm != PackageManager.PERMISSION_GRANTED) {
11354 Log.w(TAG, "Permission Denial: receiving "
11355 + r.intent + " to "
11356 + info.activityInfo.applicationInfo.packageName
11357 + " requires " + r.requiredPermission
11358 + " due to sender " + r.callerPackage
11359 + " (uid " + r.callingUid + ")");
11360 skip = true;
11361 }
11362 }
11363 if (r.curApp != null && r.curApp.crashing) {
11364 // If the target process is crashing, just skip it.
11365 skip = true;
11366 }
11367
11368 if (skip) {
11369 r.receiver = null;
11370 r.curFilter = null;
11371 r.state = BroadcastRecord.IDLE;
11372 scheduleBroadcastsLocked();
11373 return;
11374 }
11375
11376 r.state = BroadcastRecord.APP_RECEIVE;
11377 String targetProcess = info.activityInfo.processName;
11378 r.curComponent = new ComponentName(
11379 info.activityInfo.applicationInfo.packageName,
11380 info.activityInfo.name);
11381 r.curReceiver = info.activityInfo;
11382
11383 // Is this receiver's application already running?
11384 ProcessRecord app = getProcessRecordLocked(targetProcess,
11385 info.activityInfo.applicationInfo.uid);
11386 if (app != null && app.thread != null) {
11387 try {
11388 processCurBroadcastLocked(r, app);
11389 return;
11390 } catch (RemoteException e) {
11391 Log.w(TAG, "Exception when sending broadcast to "
11392 + r.curComponent, e);
11393 }
11394
11395 // If a dead object exception was thrown -- fall through to
11396 // restart the application.
11397 }
11398
11399 // Not running -- get it started, and enqueue this history record
11400 // to be executed when the app comes up.
11401 if ((r.curApp=startProcessLocked(targetProcess,
11402 info.activityInfo.applicationInfo, true,
11403 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11404 "broadcast", r.curComponent)) == null) {
11405 // Ah, this recipient is unavailable. Finish it if necessary,
11406 // and mark the broadcast record as ready for the next.
11407 Log.w(TAG, "Unable to launch app "
11408 + info.activityInfo.applicationInfo.packageName + "/"
11409 + info.activityInfo.applicationInfo.uid + " for broadcast "
11410 + r.intent + ": process is bad");
11411 logBroadcastReceiverDiscard(r);
11412 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11413 r.resultExtras, r.resultAbort, true);
11414 scheduleBroadcastsLocked();
11415 r.state = BroadcastRecord.IDLE;
11416 return;
11417 }
11418
11419 mPendingBroadcast = r;
11420 }
11421 }
11422
11423 // =========================================================
11424 // INSTRUMENTATION
11425 // =========================================================
11426
11427 public boolean startInstrumentation(ComponentName className,
11428 String profileFile, int flags, Bundle arguments,
11429 IInstrumentationWatcher watcher) {
11430 // Refuse possible leaked file descriptors
11431 if (arguments != null && arguments.hasFileDescriptors()) {
11432 throw new IllegalArgumentException("File descriptors passed in Bundle");
11433 }
11434
11435 synchronized(this) {
11436 InstrumentationInfo ii = null;
11437 ApplicationInfo ai = null;
11438 try {
11439 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011440 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011441 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011442 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011443 } catch (PackageManager.NameNotFoundException e) {
11444 }
11445 if (ii == null) {
11446 reportStartInstrumentationFailure(watcher, className,
11447 "Unable to find instrumentation info for: " + className);
11448 return false;
11449 }
11450 if (ai == null) {
11451 reportStartInstrumentationFailure(watcher, className,
11452 "Unable to find instrumentation target package: " + ii.targetPackage);
11453 return false;
11454 }
11455
11456 int match = mContext.getPackageManager().checkSignatures(
11457 ii.targetPackage, ii.packageName);
11458 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11459 String msg = "Permission Denial: starting instrumentation "
11460 + className + " from pid="
11461 + Binder.getCallingPid()
11462 + ", uid=" + Binder.getCallingPid()
11463 + " not allowed because package " + ii.packageName
11464 + " does not have a signature matching the target "
11465 + ii.targetPackage;
11466 reportStartInstrumentationFailure(watcher, className, msg);
11467 throw new SecurityException(msg);
11468 }
11469
11470 final long origId = Binder.clearCallingIdentity();
11471 uninstallPackageLocked(ii.targetPackage, -1, true);
11472 ProcessRecord app = addAppLocked(ai);
11473 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011474 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011475 app.instrumentationProfileFile = profileFile;
11476 app.instrumentationArguments = arguments;
11477 app.instrumentationWatcher = watcher;
11478 app.instrumentationResultClass = className;
11479 Binder.restoreCallingIdentity(origId);
11480 }
11481
11482 return true;
11483 }
11484
11485 /**
11486 * Report errors that occur while attempting to start Instrumentation. Always writes the
11487 * error to the logs, but if somebody is watching, send the report there too. This enables
11488 * the "am" command to report errors with more information.
11489 *
11490 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11491 * @param cn The component name of the instrumentation.
11492 * @param report The error report.
11493 */
11494 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11495 ComponentName cn, String report) {
11496 Log.w(TAG, report);
11497 try {
11498 if (watcher != null) {
11499 Bundle results = new Bundle();
11500 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11501 results.putString("Error", report);
11502 watcher.instrumentationStatus(cn, -1, results);
11503 }
11504 } catch (RemoteException e) {
11505 Log.w(TAG, e);
11506 }
11507 }
11508
11509 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11510 if (app.instrumentationWatcher != null) {
11511 try {
11512 // NOTE: IInstrumentationWatcher *must* be oneway here
11513 app.instrumentationWatcher.instrumentationFinished(
11514 app.instrumentationClass,
11515 resultCode,
11516 results);
11517 } catch (RemoteException e) {
11518 }
11519 }
11520 app.instrumentationWatcher = null;
11521 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011522 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011523 app.instrumentationProfileFile = null;
11524 app.instrumentationArguments = null;
11525
11526 uninstallPackageLocked(app.processName, -1, false);
11527 }
11528
11529 public void finishInstrumentation(IApplicationThread target,
11530 int resultCode, Bundle results) {
11531 // Refuse possible leaked file descriptors
11532 if (results != null && results.hasFileDescriptors()) {
11533 throw new IllegalArgumentException("File descriptors passed in Intent");
11534 }
11535
11536 synchronized(this) {
11537 ProcessRecord app = getRecordForAppLocked(target);
11538 if (app == null) {
11539 Log.w(TAG, "finishInstrumentation: no app for " + target);
11540 return;
11541 }
11542 final long origId = Binder.clearCallingIdentity();
11543 finishInstrumentationLocked(app, resultCode, results);
11544 Binder.restoreCallingIdentity(origId);
11545 }
11546 }
11547
11548 // =========================================================
11549 // CONFIGURATION
11550 // =========================================================
11551
11552 public ConfigurationInfo getDeviceConfigurationInfo() {
11553 ConfigurationInfo config = new ConfigurationInfo();
11554 synchronized (this) {
11555 config.reqTouchScreen = mConfiguration.touchscreen;
11556 config.reqKeyboardType = mConfiguration.keyboard;
11557 config.reqNavigation = mConfiguration.navigation;
11558 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11559 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11560 }
11561 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11562 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11563 }
11564 }
11565 return config;
11566 }
11567
11568 public Configuration getConfiguration() {
11569 Configuration ci;
11570 synchronized(this) {
11571 ci = new Configuration(mConfiguration);
11572 }
11573 return ci;
11574 }
11575
11576 public void updateConfiguration(Configuration values) {
11577 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11578 "updateConfiguration()");
11579
11580 synchronized(this) {
11581 if (values == null && mWindowManager != null) {
11582 // sentinel: fetch the current configuration from the window manager
11583 values = mWindowManager.computeNewConfiguration();
11584 }
11585
11586 final long origId = Binder.clearCallingIdentity();
11587 updateConfigurationLocked(values, null);
11588 Binder.restoreCallingIdentity(origId);
11589 }
11590 }
11591
11592 /**
11593 * Do either or both things: (1) change the current configuration, and (2)
11594 * make sure the given activity is running with the (now) current
11595 * configuration. Returns true if the activity has been left running, or
11596 * false if <var>starting</var> is being destroyed to match the new
11597 * configuration.
11598 */
11599 public boolean updateConfigurationLocked(Configuration values,
11600 HistoryRecord starting) {
11601 int changes = 0;
11602
11603 boolean kept = true;
11604
11605 if (values != null) {
11606 Configuration newConfig = new Configuration(mConfiguration);
11607 changes = newConfig.updateFrom(values);
11608 if (changes != 0) {
11609 if (DEBUG_SWITCH) {
11610 Log.i(TAG, "Updating configuration to: " + values);
11611 }
11612
11613 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11614
11615 if (values.locale != null) {
11616 saveLocaleLocked(values.locale,
11617 !values.locale.equals(mConfiguration.locale),
11618 values.userSetLocale);
11619 }
11620
11621 mConfiguration = newConfig;
11622
11623 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11624 msg.obj = new Configuration(mConfiguration);
11625 mHandler.sendMessage(msg);
11626
11627 final int N = mLRUProcesses.size();
11628 for (int i=0; i<N; i++) {
11629 ProcessRecord app = mLRUProcesses.get(i);
11630 try {
11631 if (app.thread != null) {
11632 app.thread.scheduleConfigurationChanged(mConfiguration);
11633 }
11634 } catch (Exception e) {
11635 }
11636 }
11637 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11638 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11639 null, false, false, MY_PID, Process.SYSTEM_UID);
11640 }
11641 }
11642
11643 if (changes != 0 && starting == null) {
11644 // If the configuration changed, and the caller is not already
11645 // in the process of starting an activity, then find the top
11646 // activity to check if its configuration needs to change.
11647 starting = topRunningActivityLocked(null);
11648 }
11649
11650 if (starting != null) {
11651 kept = ensureActivityConfigurationLocked(starting, changes);
11652 if (kept) {
11653 // If this didn't result in the starting activity being
11654 // destroyed, then we need to make sure at this point that all
11655 // other activities are made visible.
11656 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11657 + ", ensuring others are correct.");
11658 ensureActivitiesVisibleLocked(starting, changes);
11659 }
11660 }
11661
11662 return kept;
11663 }
11664
11665 private final boolean relaunchActivityLocked(HistoryRecord r,
11666 int changes, boolean andResume) {
11667 List<ResultInfo> results = null;
11668 List<Intent> newIntents = null;
11669 if (andResume) {
11670 results = r.results;
11671 newIntents = r.newIntents;
11672 }
11673 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11674 + " with results=" + results + " newIntents=" + newIntents
11675 + " andResume=" + andResume);
11676 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11677 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11678 r.task.taskId, r.shortComponentName);
11679
11680 r.startFreezingScreenLocked(r.app, 0);
11681
11682 try {
11683 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11684 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11685 changes, !andResume);
11686 // Note: don't need to call pauseIfSleepingLocked() here, because
11687 // the caller will only pass in 'andResume' if this activity is
11688 // currently resumed, which implies we aren't sleeping.
11689 } catch (RemoteException e) {
11690 return false;
11691 }
11692
11693 if (andResume) {
11694 r.results = null;
11695 r.newIntents = null;
11696 }
11697
11698 return true;
11699 }
11700
11701 /**
11702 * Make sure the given activity matches the current configuration. Returns
11703 * false if the activity had to be destroyed. Returns true if the
11704 * configuration is the same, or the activity will remain running as-is
11705 * for whatever reason. Ensures the HistoryRecord is updated with the
11706 * correct configuration and all other bookkeeping is handled.
11707 */
11708 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11709 int globalChanges) {
11710 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11711
11712 // Short circuit: if the two configurations are the exact same
11713 // object (the common case), then there is nothing to do.
11714 Configuration newConfig = mConfiguration;
11715 if (r.configuration == newConfig) {
11716 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11717 return true;
11718 }
11719
11720 // We don't worry about activities that are finishing.
11721 if (r.finishing) {
11722 if (DEBUG_SWITCH) Log.i(TAG,
11723 "Configuration doesn't matter in finishing " + r);
11724 r.stopFreezingScreenLocked(false);
11725 return true;
11726 }
11727
11728 // Okay we now are going to make this activity have the new config.
11729 // But then we need to figure out how it needs to deal with that.
11730 Configuration oldConfig = r.configuration;
11731 r.configuration = newConfig;
11732
11733 // If the activity isn't currently running, just leave the new
11734 // configuration and it will pick that up next time it starts.
11735 if (r.app == null || r.app.thread == null) {
11736 if (DEBUG_SWITCH) Log.i(TAG,
11737 "Configuration doesn't matter not running " + r);
11738 r.stopFreezingScreenLocked(false);
11739 return true;
11740 }
11741
11742 // If the activity isn't persistent, there is a chance we will
11743 // need to restart it.
11744 if (!r.persistent) {
11745
11746 // Figure out what has changed between the two configurations.
11747 int changes = oldConfig.diff(newConfig);
11748 if (DEBUG_SWITCH) {
11749 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11750 + Integer.toHexString(changes) + ", handles=0x"
11751 + Integer.toHexString(r.info.configChanges));
11752 }
11753 if ((changes&(~r.info.configChanges)) != 0) {
11754 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11755 r.configChangeFlags |= changes;
11756 r.startFreezingScreenLocked(r.app, globalChanges);
11757 if (r.app == null || r.app.thread == null) {
11758 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11759 destroyActivityLocked(r, true);
11760 } else if (r.state == ActivityState.PAUSING) {
11761 // A little annoying: we are waiting for this activity to
11762 // finish pausing. Let's not do anything now, but just
11763 // flag that it needs to be restarted when done pausing.
11764 r.configDestroy = true;
11765 return true;
11766 } else if (r.state == ActivityState.RESUMED) {
11767 // Try to optimize this case: the configuration is changing
11768 // and we need to restart the top, resumed activity.
11769 // Instead of doing the normal handshaking, just say
11770 // "restart!".
11771 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11772 relaunchActivityLocked(r, r.configChangeFlags, true);
11773 r.configChangeFlags = 0;
11774 } else {
11775 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11776 relaunchActivityLocked(r, r.configChangeFlags, false);
11777 r.configChangeFlags = 0;
11778 }
11779
11780 // All done... tell the caller we weren't able to keep this
11781 // activity around.
11782 return false;
11783 }
11784 }
11785
11786 // Default case: the activity can handle this new configuration, so
11787 // hand it over. Note that we don't need to give it the new
11788 // configuration, since we always send configuration changes to all
11789 // process when they happen so it can just use whatever configuration
11790 // it last got.
11791 if (r.app != null && r.app.thread != null) {
11792 try {
11793 r.app.thread.scheduleActivityConfigurationChanged(r);
11794 } catch (RemoteException e) {
11795 // If process died, whatever.
11796 }
11797 }
11798 r.stopFreezingScreenLocked(false);
11799
11800 return true;
11801 }
11802
11803 /**
11804 * Save the locale. You must be inside a synchronized (this) block.
11805 */
11806 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11807 if(isDiff) {
11808 SystemProperties.set("user.language", l.getLanguage());
11809 SystemProperties.set("user.region", l.getCountry());
11810 }
11811
11812 if(isPersist) {
11813 SystemProperties.set("persist.sys.language", l.getLanguage());
11814 SystemProperties.set("persist.sys.country", l.getCountry());
11815 SystemProperties.set("persist.sys.localevar", l.getVariant());
11816 }
11817 }
11818
11819 // =========================================================
11820 // LIFETIME MANAGEMENT
11821 // =========================================================
11822
11823 private final int computeOomAdjLocked(
11824 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11825 if (mAdjSeq == app.adjSeq) {
11826 // This adjustment has already been computed.
11827 return app.curAdj;
11828 }
11829
11830 if (app.thread == null) {
11831 app.adjSeq = mAdjSeq;
11832 return (app.curAdj=EMPTY_APP_ADJ);
11833 }
11834
11835 app.isForeground = false;
11836
The Android Open Source Project4df24232009-03-05 14:34:35 -080011837 // Determine the importance of the process, starting with most
11838 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011839 int adj;
11840 int N;
11841 if (app == TOP_APP || app.instrumentationClass != null
11842 || app.persistentActivities > 0) {
11843 // The last app on the list is the foreground app.
11844 adj = FOREGROUND_APP_ADJ;
11845 app.isForeground = true;
11846 } else if (app.curReceiver != null ||
11847 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11848 // An app that is currently receiving a broadcast also
11849 // counts as being in the foreground.
11850 adj = FOREGROUND_APP_ADJ;
11851 } else if (app.executingServices.size() > 0) {
11852 // An app that is currently executing a service callback also
11853 // counts as being in the foreground.
11854 adj = FOREGROUND_APP_ADJ;
11855 } else if (app.foregroundServices || app.forcingToForeground != null) {
11856 // The user is aware of this app, so make it visible.
11857 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011858 } else if (app == mHomeProcess) {
11859 // This process is hosting what we currently consider to be the
11860 // home app, so we don't want to let it go into the background.
11861 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011862 } else if ((N=app.activities.size()) != 0) {
11863 // This app is in the background with paused activities.
11864 adj = hiddenAdj;
11865 for (int j=0; j<N; j++) {
11866 if (((HistoryRecord)app.activities.get(j)).visible) {
11867 // This app has a visible activity!
11868 adj = VISIBLE_APP_ADJ;
11869 break;
11870 }
11871 }
11872 } else {
11873 // A very not-needed process.
11874 adj = EMPTY_APP_ADJ;
11875 }
11876
The Android Open Source Project4df24232009-03-05 14:34:35 -080011877 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011878 // there are applications dependent on our services or providers, but
11879 // this gives us a baseline and makes sure we don't get into an
11880 // infinite recursion.
11881 app.adjSeq = mAdjSeq;
11882 app.curRawAdj = adj;
11883 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11884
11885 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11886 // If this process has active services running in it, we would
11887 // like to avoid killing it unless it would prevent the current
11888 // application from running.
11889 if (adj > hiddenAdj) {
11890 adj = hiddenAdj;
11891 }
11892 final long now = SystemClock.uptimeMillis();
11893 // This process is more important if the top activity is
11894 // bound to the service.
11895 Iterator jt = app.services.iterator();
11896 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11897 ServiceRecord s = (ServiceRecord)jt.next();
11898 if (s.startRequested) {
11899 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
11900 // This service has seen some activity within
11901 // recent memory, so we will keep its process ahead
11902 // of the background processes.
11903 if (adj > SECONDARY_SERVER_ADJ) {
11904 adj = SECONDARY_SERVER_ADJ;
11905 }
11906 } else {
11907 // This service has been inactive for too long, just
11908 // put it with the rest of the background processes.
11909 if (adj > hiddenAdj) {
11910 adj = hiddenAdj;
11911 }
11912 }
11913 }
11914 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
11915 Iterator<ConnectionRecord> kt
11916 = s.connections.values().iterator();
11917 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11918 // XXX should compute this based on the max of
11919 // all connected clients.
11920 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011921 if (cr.binding.client == app) {
11922 // Binding to ourself is not interesting.
11923 continue;
11924 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011925 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
11926 ProcessRecord client = cr.binding.client;
11927 int myHiddenAdj = hiddenAdj;
11928 if (myHiddenAdj > client.hiddenAdj) {
11929 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
11930 myHiddenAdj = client.hiddenAdj;
11931 } else {
11932 myHiddenAdj = VISIBLE_APP_ADJ;
11933 }
11934 }
11935 int clientAdj = computeOomAdjLocked(
11936 client, myHiddenAdj, TOP_APP);
11937 if (adj > clientAdj) {
11938 adj = clientAdj > VISIBLE_APP_ADJ
11939 ? clientAdj : VISIBLE_APP_ADJ;
11940 }
11941 }
11942 HistoryRecord a = cr.activity;
11943 //if (a != null) {
11944 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
11945 //}
11946 if (a != null && adj > FOREGROUND_APP_ADJ &&
11947 (a.state == ActivityState.RESUMED
11948 || a.state == ActivityState.PAUSING)) {
11949 adj = FOREGROUND_APP_ADJ;
11950 }
11951 }
11952 }
11953 }
11954 }
11955
11956 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11957 // If this process has published any content providers, then
11958 // its adjustment makes it at least as important as any of the
11959 // processes using those providers, and no less important than
11960 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
11961 if (adj > CONTENT_PROVIDER_ADJ) {
11962 adj = CONTENT_PROVIDER_ADJ;
11963 }
11964 Iterator jt = app.pubProviders.values().iterator();
11965 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11966 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
11967 if (cpr.clients.size() != 0) {
11968 Iterator<ProcessRecord> kt = cpr.clients.iterator();
11969 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11970 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011971 if (client == app) {
11972 // Being our own client is not interesting.
11973 continue;
11974 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011975 int myHiddenAdj = hiddenAdj;
11976 if (myHiddenAdj > client.hiddenAdj) {
11977 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
11978 myHiddenAdj = client.hiddenAdj;
11979 } else {
11980 myHiddenAdj = FOREGROUND_APP_ADJ;
11981 }
11982 }
11983 int clientAdj = computeOomAdjLocked(
11984 client, myHiddenAdj, TOP_APP);
11985 if (adj > clientAdj) {
11986 adj = clientAdj > FOREGROUND_APP_ADJ
11987 ? clientAdj : FOREGROUND_APP_ADJ;
11988 }
11989 }
11990 }
11991 // If the provider has external (non-framework) process
11992 // dependencies, ensure that its adjustment is at least
11993 // FOREGROUND_APP_ADJ.
11994 if (cpr.externals != 0) {
11995 if (adj > FOREGROUND_APP_ADJ) {
11996 adj = FOREGROUND_APP_ADJ;
11997 }
11998 }
11999 }
12000 }
12001
12002 app.curRawAdj = adj;
12003
12004 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12005 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12006 if (adj > app.maxAdj) {
12007 adj = app.maxAdj;
12008 }
12009
12010 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012011 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12012 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12013 : Process.THREAD_GROUP_DEFAULT;
12014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012015 return adj;
12016 }
12017
12018 /**
12019 * Ask a given process to GC right now.
12020 */
12021 final void performAppGcLocked(ProcessRecord app) {
12022 try {
12023 app.lastRequestedGc = SystemClock.uptimeMillis();
12024 if (app.thread != null) {
12025 app.thread.processInBackground();
12026 }
12027 } catch (Exception e) {
12028 // whatever.
12029 }
12030 }
12031
12032 /**
12033 * Returns true if things are idle enough to perform GCs.
12034 */
12035 private final boolean canGcNow() {
12036 return mParallelBroadcasts.size() == 0
12037 && mOrderedBroadcasts.size() == 0
12038 && (mSleeping || (mResumedActivity != null &&
12039 mResumedActivity.idle));
12040 }
12041
12042 /**
12043 * Perform GCs on all processes that are waiting for it, but only
12044 * if things are idle.
12045 */
12046 final void performAppGcsLocked() {
12047 final int N = mProcessesToGc.size();
12048 if (N <= 0) {
12049 return;
12050 }
12051 if (canGcNow()) {
12052 while (mProcessesToGc.size() > 0) {
12053 ProcessRecord proc = mProcessesToGc.remove(0);
12054 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12055 // To avoid spamming the system, we will GC processes one
12056 // at a time, waiting a few seconds between each.
12057 performAppGcLocked(proc);
12058 scheduleAppGcsLocked();
12059 return;
12060 }
12061 }
12062 }
12063 }
12064
12065 /**
12066 * If all looks good, perform GCs on all processes waiting for them.
12067 */
12068 final void performAppGcsIfAppropriateLocked() {
12069 if (canGcNow()) {
12070 performAppGcsLocked();
12071 return;
12072 }
12073 // Still not idle, wait some more.
12074 scheduleAppGcsLocked();
12075 }
12076
12077 /**
12078 * Schedule the execution of all pending app GCs.
12079 */
12080 final void scheduleAppGcsLocked() {
12081 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12082 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12083 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12084 }
12085
12086 /**
12087 * Set up to ask a process to GC itself. This will either do it
12088 * immediately, or put it on the list of processes to gc the next
12089 * time things are idle.
12090 */
12091 final void scheduleAppGcLocked(ProcessRecord app) {
12092 long now = SystemClock.uptimeMillis();
12093 if ((app.lastRequestedGc+5000) > now) {
12094 return;
12095 }
12096 if (!mProcessesToGc.contains(app)) {
12097 mProcessesToGc.add(app);
12098 scheduleAppGcsLocked();
12099 }
12100 }
12101
12102 private final boolean updateOomAdjLocked(
12103 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12104 app.hiddenAdj = hiddenAdj;
12105
12106 if (app.thread == null) {
12107 return true;
12108 }
12109
12110 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12111
12112 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12113 //Thread priority adjustment is disabled out to see
12114 //how the kernel scheduler performs.
12115 if (false) {
12116 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12117 app.setIsForeground = app.isForeground;
12118 if (app.pid != MY_PID) {
12119 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12120 + " to " + (app.isForeground
12121 ? Process.THREAD_PRIORITY_FOREGROUND
12122 : Process.THREAD_PRIORITY_DEFAULT));
12123 try {
12124 Process.setThreadPriority(app.pid, app.isForeground
12125 ? Process.THREAD_PRIORITY_FOREGROUND
12126 : Process.THREAD_PRIORITY_DEFAULT);
12127 } catch (RuntimeException e) {
12128 Log.w(TAG, "Exception trying to set priority of application thread "
12129 + app.pid, e);
12130 }
12131 }
12132 }
12133 }
12134 if (app.pid != 0 && app.pid != MY_PID) {
12135 if (app.curRawAdj != app.setRawAdj) {
12136 if (app.curRawAdj > FOREGROUND_APP_ADJ
12137 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12138 // If this app is transitioning from foreground to
12139 // non-foreground, have it do a gc.
12140 scheduleAppGcLocked(app);
12141 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12142 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12143 // Likewise do a gc when an app is moving in to the
12144 // background (such as a service stopping).
12145 scheduleAppGcLocked(app);
12146 }
12147 app.setRawAdj = app.curRawAdj;
12148 }
12149 if (adj != app.setAdj) {
12150 if (Process.setOomAdj(app.pid, adj)) {
12151 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12152 TAG, "Set app " + app.processName +
12153 " oom adj to " + adj);
12154 app.setAdj = adj;
12155 } else {
12156 return false;
12157 }
12158 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012159 if (app.setSchedGroup != app.curSchedGroup) {
12160 app.setSchedGroup = app.curSchedGroup;
12161 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12162 "Setting process group of " + app.processName
12163 + " to " + app.curSchedGroup);
12164 if (true) {
12165 try {
12166 Process.setProcessGroup(app.pid, app.curSchedGroup);
12167 } catch (Exception e) {
12168 Log.w(TAG, "Failed setting process group of " + app.pid
12169 + " to " + app.curSchedGroup);
12170 }
12171 }
12172 if (false) {
12173 if (app.thread != null) {
12174 try {
12175 app.thread.setSchedulingGroup(app.curSchedGroup);
12176 } catch (RemoteException e) {
12177 }
12178 }
12179 }
12180 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012181 }
12182
12183 return true;
12184 }
12185
12186 private final HistoryRecord resumedAppLocked() {
12187 HistoryRecord resumedActivity = mResumedActivity;
12188 if (resumedActivity == null || resumedActivity.app == null) {
12189 resumedActivity = mPausingActivity;
12190 if (resumedActivity == null || resumedActivity.app == null) {
12191 resumedActivity = topRunningActivityLocked(null);
12192 }
12193 }
12194 return resumedActivity;
12195 }
12196
12197 private final boolean updateOomAdjLocked(ProcessRecord app) {
12198 final HistoryRecord TOP_ACT = resumedAppLocked();
12199 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12200 int curAdj = app.curAdj;
12201 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12202 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12203
12204 mAdjSeq++;
12205
12206 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12207 if (res) {
12208 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12209 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12210 if (nowHidden != wasHidden) {
12211 // Changed to/from hidden state, so apps after it in the LRU
12212 // list may also be changed.
12213 updateOomAdjLocked();
12214 }
12215 }
12216 return res;
12217 }
12218
12219 private final boolean updateOomAdjLocked() {
12220 boolean didOomAdj = true;
12221 final HistoryRecord TOP_ACT = resumedAppLocked();
12222 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12223
12224 if (false) {
12225 RuntimeException e = new RuntimeException();
12226 e.fillInStackTrace();
12227 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12228 }
12229
12230 mAdjSeq++;
12231
12232 // First try updating the OOM adjustment for each of the
12233 // application processes based on their current state.
12234 int i = mLRUProcesses.size();
12235 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12236 while (i > 0) {
12237 i--;
12238 ProcessRecord app = mLRUProcesses.get(i);
12239 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12240 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12241 && app.curAdj == curHiddenAdj) {
12242 curHiddenAdj++;
12243 }
12244 } else {
12245 didOomAdj = false;
12246 }
12247 }
12248
12249 // todo: for now pretend like OOM ADJ didn't work, because things
12250 // aren't behaving as expected on Linux -- it's not killing processes.
12251 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12252 }
12253
12254 private final void trimApplications() {
12255 synchronized (this) {
12256 int i;
12257
12258 // First remove any unused application processes whose package
12259 // has been removed.
12260 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12261 final ProcessRecord app = mRemovedProcesses.get(i);
12262 if (app.activities.size() == 0
12263 && app.curReceiver == null && app.services.size() == 0) {
12264 Log.i(
12265 TAG, "Exiting empty application process "
12266 + app.processName + " ("
12267 + (app.thread != null ? app.thread.asBinder() : null)
12268 + ")\n");
12269 if (app.pid > 0 && app.pid != MY_PID) {
12270 Process.killProcess(app.pid);
12271 } else {
12272 try {
12273 app.thread.scheduleExit();
12274 } catch (Exception e) {
12275 // Ignore exceptions.
12276 }
12277 }
12278 cleanUpApplicationRecordLocked(app, false, -1);
12279 mRemovedProcesses.remove(i);
12280
12281 if (app.persistent) {
12282 if (app.persistent) {
12283 addAppLocked(app.info);
12284 }
12285 }
12286 }
12287 }
12288
12289 // Now try updating the OOM adjustment for each of the
12290 // application processes based on their current state.
12291 // If the setOomAdj() API is not supported, then go with our
12292 // back-up plan...
12293 if (!updateOomAdjLocked()) {
12294
12295 // Count how many processes are running services.
12296 int numServiceProcs = 0;
12297 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12298 final ProcessRecord app = mLRUProcesses.get(i);
12299
12300 if (app.persistent || app.services.size() != 0
12301 || app.curReceiver != null
12302 || app.persistentActivities > 0) {
12303 // Don't count processes holding services against our
12304 // maximum process count.
12305 if (localLOGV) Log.v(
12306 TAG, "Not trimming app " + app + " with services: "
12307 + app.services);
12308 numServiceProcs++;
12309 }
12310 }
12311
12312 int curMaxProcs = mProcessLimit;
12313 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12314 if (mAlwaysFinishActivities) {
12315 curMaxProcs = 1;
12316 }
12317 curMaxProcs += numServiceProcs;
12318
12319 // Quit as many processes as we can to get down to the desired
12320 // process count. First remove any processes that no longer
12321 // have activites running in them.
12322 for ( i=0;
12323 i<mLRUProcesses.size()
12324 && mLRUProcesses.size() > curMaxProcs;
12325 i++) {
12326 final ProcessRecord app = mLRUProcesses.get(i);
12327 // Quit an application only if it is not currently
12328 // running any activities.
12329 if (!app.persistent && app.activities.size() == 0
12330 && app.curReceiver == null && app.services.size() == 0) {
12331 Log.i(
12332 TAG, "Exiting empty application process "
12333 + app.processName + " ("
12334 + (app.thread != null ? app.thread.asBinder() : null)
12335 + ")\n");
12336 if (app.pid > 0 && app.pid != MY_PID) {
12337 Process.killProcess(app.pid);
12338 } else {
12339 try {
12340 app.thread.scheduleExit();
12341 } catch (Exception e) {
12342 // Ignore exceptions.
12343 }
12344 }
12345 // todo: For now we assume the application is not buggy
12346 // or evil, and will quit as a result of our request.
12347 // Eventually we need to drive this off of the death
12348 // notification, and kill the process if it takes too long.
12349 cleanUpApplicationRecordLocked(app, false, i);
12350 i--;
12351 }
12352 }
12353
12354 // If we still have too many processes, now from the least
12355 // recently used process we start finishing activities.
12356 if (Config.LOGV) Log.v(
12357 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12358 " of " + curMaxProcs + " processes");
12359 for ( i=0;
12360 i<mLRUProcesses.size()
12361 && mLRUProcesses.size() > curMaxProcs;
12362 i++) {
12363 final ProcessRecord app = mLRUProcesses.get(i);
12364 // Quit the application only if we have a state saved for
12365 // all of its activities.
12366 boolean canQuit = !app.persistent && app.curReceiver == null
12367 && app.services.size() == 0
12368 && app.persistentActivities == 0;
12369 int NUMA = app.activities.size();
12370 int j;
12371 if (Config.LOGV) Log.v(
12372 TAG, "Looking to quit " + app.processName);
12373 for (j=0; j<NUMA && canQuit; j++) {
12374 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12375 if (Config.LOGV) Log.v(
12376 TAG, " " + r.intent.getComponent().flattenToShortString()
12377 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12378 canQuit = (r.haveState || !r.stateNotNeeded)
12379 && !r.visible && r.stopped;
12380 }
12381 if (canQuit) {
12382 // Finish all of the activities, and then the app itself.
12383 for (j=0; j<NUMA; j++) {
12384 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12385 if (!r.finishing) {
12386 destroyActivityLocked(r, false);
12387 }
12388 r.resultTo = null;
12389 }
12390 Log.i(TAG, "Exiting application process "
12391 + app.processName + " ("
12392 + (app.thread != null ? app.thread.asBinder() : null)
12393 + ")\n");
12394 if (app.pid > 0 && app.pid != MY_PID) {
12395 Process.killProcess(app.pid);
12396 } else {
12397 try {
12398 app.thread.scheduleExit();
12399 } catch (Exception e) {
12400 // Ignore exceptions.
12401 }
12402 }
12403 // todo: For now we assume the application is not buggy
12404 // or evil, and will quit as a result of our request.
12405 // Eventually we need to drive this off of the death
12406 // notification, and kill the process if it takes too long.
12407 cleanUpApplicationRecordLocked(app, false, i);
12408 i--;
12409 //dump();
12410 }
12411 }
12412
12413 }
12414
12415 int curMaxActivities = MAX_ACTIVITIES;
12416 if (mAlwaysFinishActivities) {
12417 curMaxActivities = 1;
12418 }
12419
12420 // Finally, if there are too many activities now running, try to
12421 // finish as many as we can to get back down to the limit.
12422 for ( i=0;
12423 i<mLRUActivities.size()
12424 && mLRUActivities.size() > curMaxActivities;
12425 i++) {
12426 final HistoryRecord r
12427 = (HistoryRecord)mLRUActivities.get(i);
12428
12429 // We can finish this one if we have its icicle saved and
12430 // it is not persistent.
12431 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12432 && r.stopped && !r.persistent && !r.finishing) {
12433 final int origSize = mLRUActivities.size();
12434 destroyActivityLocked(r, true);
12435
12436 // This will remove it from the LRU list, so keep
12437 // our index at the same value. Note that this check to
12438 // see if the size changes is just paranoia -- if
12439 // something unexpected happens, we don't want to end up
12440 // in an infinite loop.
12441 if (origSize > mLRUActivities.size()) {
12442 i--;
12443 }
12444 }
12445 }
12446 }
12447 }
12448
12449 /** This method sends the specified signal to each of the persistent apps */
12450 public void signalPersistentProcesses(int sig) throws RemoteException {
12451 if (sig != Process.SIGNAL_USR1) {
12452 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12453 }
12454
12455 synchronized (this) {
12456 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12457 != PackageManager.PERMISSION_GRANTED) {
12458 throw new SecurityException("Requires permission "
12459 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12460 }
12461
12462 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12463 ProcessRecord r = mLRUProcesses.get(i);
12464 if (r.thread != null && r.persistent) {
12465 Process.sendSignal(r.pid, sig);
12466 }
12467 }
12468 }
12469 }
12470
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012471 public boolean profileControl(String process, boolean start,
12472 String path) throws RemoteException {
12473
12474 synchronized (this) {
12475 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12476 // its own permission.
12477 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12478 != PackageManager.PERMISSION_GRANTED) {
12479 throw new SecurityException("Requires permission "
12480 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12481 }
12482
12483 ProcessRecord proc = null;
12484 try {
12485 int pid = Integer.parseInt(process);
12486 synchronized (mPidsSelfLocked) {
12487 proc = mPidsSelfLocked.get(pid);
12488 }
12489 } catch (NumberFormatException e) {
12490 }
12491
12492 if (proc == null) {
12493 HashMap<String, SparseArray<ProcessRecord>> all
12494 = mProcessNames.getMap();
12495 SparseArray<ProcessRecord> procs = all.get(process);
12496 if (procs != null && procs.size() > 0) {
12497 proc = procs.valueAt(0);
12498 }
12499 }
12500
12501 if (proc == null || proc.thread == null) {
12502 throw new IllegalArgumentException("Unknown process: " + process);
12503 }
12504
12505 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12506 if (isSecure) {
12507 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12508 throw new SecurityException("Process not debuggable: " + proc);
12509 }
12510 }
12511
12512 try {
12513 proc.thread.profilerControl(start, path);
12514 return true;
12515 } catch (RemoteException e) {
12516 throw new IllegalStateException("Process disappeared");
12517 }
12518 }
12519 }
12520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012521 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12522 public void monitor() {
12523 synchronized (this) { }
12524 }
12525}