blob: 51ee41afb56e87f33b3ed357bf4c91de4480418f [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;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import 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;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
42import android.app.PendingIntent;
43import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070044import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020045import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
47import android.content.ContentResolver;
48import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070051import android.content.IIntentReceiver;
52import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.pm.ActivityInfo;
54import android.content.pm.ApplicationInfo;
55import android.content.pm.ConfigurationInfo;
56import android.content.pm.IPackageDataObserver;
57import android.content.pm.IPackageManager;
58import android.content.pm.InstrumentationInfo;
59import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070060import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.content.pm.ProviderInfo;
62import android.content.pm.ResolveInfo;
63import android.content.pm.ServiceInfo;
64import android.content.res.Configuration;
65import android.graphics.Bitmap;
66import android.net.Uri;
67import android.os.Binder;
68import android.os.Bundle;
69import android.os.Environment;
70import android.os.FileUtils;
71import android.os.Handler;
72import android.os.IBinder;
73import android.os.IPermissionController;
74import android.os.Looper;
75import android.os.Message;
76import android.os.Parcel;
77import android.os.ParcelFileDescriptor;
78import android.os.PowerManager;
79import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070080import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.RemoteException;
82import android.os.ServiceManager;
83import android.os.SystemClock;
84import android.os.SystemProperties;
85import android.provider.Checkin;
86import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020087import android.server.data.CrashData;
88import android.server.data.StackTraceElementData;
89import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.text.TextUtils;
91import android.util.Config;
92import android.util.EventLog;
93import android.util.Log;
94import android.util.PrintWriterPrinter;
95import android.util.SparseArray;
96import android.view.Gravity;
97import android.view.LayoutInflater;
98import android.view.View;
99import android.view.WindowManager;
100import android.view.WindowManagerPolicy;
101
102import dalvik.system.Zygote;
103
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200104import java.io.ByteArrayInputStream;
105import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import java.io.File;
107import java.io.FileDescriptor;
108import java.io.FileInputStream;
109import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200110import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import java.io.PrintWriter;
112import java.lang.IllegalStateException;
113import java.lang.ref.WeakReference;
114import java.util.ArrayList;
115import java.util.HashMap;
116import java.util.HashSet;
117import java.util.Iterator;
118import java.util.List;
119import java.util.Locale;
120import java.util.Map;
121
122public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
123 static final String TAG = "ActivityManager";
124 static final boolean DEBUG = false;
125 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
126 static final boolean DEBUG_SWITCH = localLOGV || false;
127 static final boolean DEBUG_TASKS = localLOGV || false;
128 static final boolean DEBUG_PAUSE = localLOGV || false;
129 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
130 static final boolean DEBUG_TRANSITION = localLOGV || false;
131 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700132 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 static final boolean DEBUG_SERVICE = localLOGV || false;
134 static final boolean DEBUG_VISBILITY = localLOGV || false;
135 static final boolean DEBUG_PROCESSES = localLOGV || false;
136 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700138 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean VALIDATE_TOKENS = false;
140 static final boolean SHOW_ACTIVITY_START_TIME = true;
141
142 // Control over CPU and battery monitoring.
143 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
144 static final boolean MONITOR_CPU_USAGE = true;
145 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
146 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
147 static final boolean MONITOR_THREAD_CPU_USAGE = false;
148
149 // Event log tags
150 static final int LOG_CONFIGURATION_CHANGED = 2719;
151 static final int LOG_CPU = 2721;
152 static final int LOG_AM_FINISH_ACTIVITY = 30001;
153 static final int LOG_TASK_TO_FRONT = 30002;
154 static final int LOG_AM_NEW_INTENT = 30003;
155 static final int LOG_AM_CREATE_TASK = 30004;
156 static final int LOG_AM_CREATE_ACTIVITY = 30005;
157 static final int LOG_AM_RESTART_ACTIVITY = 30006;
158 static final int LOG_AM_RESUME_ACTIVITY = 30007;
159 static final int LOG_ANR = 30008;
160 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
161 static final int LOG_AM_PROCESS_BOUND = 30010;
162 static final int LOG_AM_PROCESS_DIED = 30011;
163 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
164 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
165 static final int LOG_AM_PROCESS_START = 30014;
166 static final int LOG_AM_PROCESS_BAD = 30015;
167 static final int LOG_AM_PROCESS_GOOD = 30016;
168 static final int LOG_AM_LOW_MEMORY = 30017;
169 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
170 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
171 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
172 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
173 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
174 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
175 static final int LOG_AM_CREATE_SERVICE = 30030;
176 static final int LOG_AM_DESTROY_SERVICE = 30031;
177 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
178 static final int LOG_AM_DROP_PROCESS = 30033;
179 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
180 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
181 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
182
183 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
184 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
185
Dianne Hackborn1655be42009-05-08 14:29:01 -0700186 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700187 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 private static final String SYSTEM_SECURE = "ro.secure";
190
191 // This is the maximum number of application processes we would like
192 // to have running. Due to the asynchronous nature of things, we can
193 // temporarily go beyond this limit.
194 static final int MAX_PROCESSES = 2;
195
196 // Set to false to leave processes running indefinitely, relying on
197 // the kernel killing them as resources are required.
198 static final boolean ENFORCE_PROCESS_LIMIT = false;
199
200 // This is the maximum number of activities that we would like to have
201 // running at a given time.
202 static final int MAX_ACTIVITIES = 20;
203
204 // Maximum number of recent tasks that we can remember.
205 static final int MAX_RECENT_TASKS = 20;
206
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700207 // Amount of time after a call to stopAppSwitches() during which we will
208 // prevent further untrusted switches from happening.
209 static final long APP_SWITCH_DELAY_TIME = 5*1000;
210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 // How long until we reset a task when the user returns to it. Currently
212 // 30 minutes.
213 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
214
215 // Set to true to disable the icon that is shown while a new activity
216 // is being started.
217 static final boolean SHOW_APP_STARTING_ICON = true;
218
219 // How long we wait until giving up on the last activity to pause. This
220 // is short because it directly impacts the responsiveness of starting the
221 // next activity.
222 static final int PAUSE_TIMEOUT = 500;
223
224 /**
225 * How long we can hold the launch wake lock before giving up.
226 */
227 static final int LAUNCH_TIMEOUT = 10*1000;
228
229 // How long we wait for a launched process to attach to the activity manager
230 // before we decide it's never going to come up for real.
231 static final int PROC_START_TIMEOUT = 10*1000;
232
233 // How long we wait until giving up on the last activity telling us it
234 // is idle.
235 static final int IDLE_TIMEOUT = 10*1000;
236
237 // How long to wait after going idle before forcing apps to GC.
238 static final int GC_TIMEOUT = 5*1000;
239
240 // How long we wait until giving up on an activity telling us it has
241 // finished destroying itself.
242 static final int DESTROY_TIMEOUT = 10*1000;
243
244 // How long we allow a receiver to run before giving up on it.
245 static final int BROADCAST_TIMEOUT = 10*1000;
246
247 // How long we wait for a service to finish executing.
248 static final int SERVICE_TIMEOUT = 20*1000;
249
250 // How long a service needs to be running until restarting its process
251 // is no longer considered to be a relaunch of the service.
252 static final int SERVICE_RESTART_DURATION = 5*1000;
253
254 // Maximum amount of time for there to be no activity on a service before
255 // we consider it non-essential and allow its process to go on the
256 // LRU background list.
257 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
258
259 // How long we wait until we timeout on key dispatching.
260 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
261
262 // The minimum time we allow between crashes, for us to consider this
263 // application to be bad and stop and its services and reject broadcasts.
264 static final int MIN_CRASH_INTERVAL = 60*1000;
265
266 // How long we wait until we timeout on key dispatching during instrumentation.
267 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
268
269 // OOM adjustments for processes in various states:
270
271 // This is a process without anything currently running in it. Definitely
272 // the first to go! Value set in system/rootdir/init.rc on startup.
273 // This value is initalized in the constructor, careful when refering to
274 // this static variable externally.
275 static int EMPTY_APP_ADJ;
276
277 // This is a process with a content provider that does not have any clients
278 // attached to it. If it did have any clients, its adjustment would be the
279 // one for the highest-priority of those processes.
280 static int CONTENT_PROVIDER_ADJ;
281
282 // This is a process only hosting activities that are not visible,
283 // so it can be killed without any disruption. Value set in
284 // system/rootdir/init.rc on startup.
285 final int HIDDEN_APP_MAX_ADJ;
286 static int HIDDEN_APP_MIN_ADJ;
287
The Android Open Source Project4df24232009-03-05 14:34:35 -0800288 // This is a process holding the home application -- we want to try
289 // avoiding killing it, even if it would normally be in the background,
290 // because the user interacts with it so much.
291 final int HOME_APP_ADJ;
292
Christopher Tate6fa95972009-06-05 18:43:55 -0700293 // This is a process currently hosting a backup operation. Killing it
294 // is not entirely fatal but is generally a bad idea.
295 final int BACKUP_APP_ADJ;
296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 // This is a process holding a secondary server -- killing it will not
298 // have much of an impact as far as the user is concerned. Value set in
299 // system/rootdir/init.rc on startup.
300 final int SECONDARY_SERVER_ADJ;
301
302 // This is a process only hosting activities that are visible to the
303 // user, so we'd prefer they don't disappear. Value set in
304 // system/rootdir/init.rc on startup.
305 final int VISIBLE_APP_ADJ;
306
307 // This is the process running the current foreground app. We'd really
308 // rather not kill it! Value set in system/rootdir/init.rc on startup.
309 final int FOREGROUND_APP_ADJ;
310
311 // This is a process running a core server, such as telephony. Definitely
312 // don't want to kill it, but doing so is not completely fatal.
313 static final int CORE_SERVER_ADJ = -12;
314
315 // The system process runs at the default adjustment.
316 static final int SYSTEM_ADJ = -16;
317
318 // Memory pages are 4K.
319 static final int PAGE_SIZE = 4*1024;
320
321 // Corresponding memory levels for above adjustments.
322 final int EMPTY_APP_MEM;
323 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800324 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700325 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 final int SECONDARY_SERVER_MEM;
327 final int VISIBLE_APP_MEM;
328 final int FOREGROUND_APP_MEM;
329
330 final int MY_PID;
331
332 static final String[] EMPTY_STRING_ARRAY = new String[0];
333
334 enum ActivityState {
335 INITIALIZING,
336 RESUMED,
337 PAUSING,
338 PAUSED,
339 STOPPING,
340 STOPPED,
341 FINISHING,
342 DESTROYING,
343 DESTROYED
344 }
345
346 /**
347 * The back history of all previous (and possibly still
348 * running) activities. It contains HistoryRecord objects.
349 */
350 final ArrayList mHistory = new ArrayList();
351
352 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700353 * Description of a request to start a new activity, which has been held
354 * due to app switches being disabled.
355 */
356 class PendingActivityLaunch {
357 HistoryRecord r;
358 HistoryRecord sourceRecord;
359 Uri[] grantedUriPermissions;
360 int grantedMode;
361 boolean onlyIfNeeded;
362 }
363
364 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
365 = new ArrayList<PendingActivityLaunch>();
366
367 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 * List of all active broadcasts that are to be executed immediately
369 * (without waiting for another broadcast to finish). Currently this only
370 * contains broadcasts to registered receivers, to avoid spinning up
371 * a bunch of processes to execute IntentReceiver components.
372 */
373 final ArrayList<BroadcastRecord> mParallelBroadcasts
374 = new ArrayList<BroadcastRecord>();
375
376 /**
377 * List of all active broadcasts that are to be executed one at a time.
378 * The object at the top of the list is the currently activity broadcasts;
379 * those after it are waiting for the top to finish..
380 */
381 final ArrayList<BroadcastRecord> mOrderedBroadcasts
382 = new ArrayList<BroadcastRecord>();
383
384 /**
385 * Set when we current have a BROADCAST_INTENT_MSG in flight.
386 */
387 boolean mBroadcastsScheduled = false;
388
389 /**
390 * Set to indicate whether to issue an onUserLeaving callback when a
391 * newly launched activity is being brought in front of us.
392 */
393 boolean mUserLeaving = false;
394
395 /**
396 * When we are in the process of pausing an activity, before starting the
397 * next one, this variable holds the activity that is currently being paused.
398 */
399 HistoryRecord mPausingActivity = null;
400
401 /**
402 * Current activity that is resumed, or null if there is none.
403 */
404 HistoryRecord mResumedActivity = null;
405
406 /**
407 * Activity we have told the window manager to have key focus.
408 */
409 HistoryRecord mFocusedActivity = null;
410
411 /**
412 * This is the last activity that we put into the paused state. This is
413 * used to determine if we need to do an activity transition while sleeping,
414 * when we normally hold the top activity paused.
415 */
416 HistoryRecord mLastPausedActivity = null;
417
418 /**
419 * List of activities that are waiting for a new activity
420 * to become visible before completing whatever operation they are
421 * supposed to do.
422 */
423 final ArrayList mWaitingVisibleActivities = new ArrayList();
424
425 /**
426 * List of activities that are ready to be stopped, but waiting
427 * for the next activity to settle down before doing so. It contains
428 * HistoryRecord objects.
429 */
430 final ArrayList<HistoryRecord> mStoppingActivities
431 = new ArrayList<HistoryRecord>();
432
433 /**
434 * List of intents that were used to start the most recent tasks.
435 */
436 final ArrayList<TaskRecord> mRecentTasks
437 = new ArrayList<TaskRecord>();
438
439 /**
440 * List of activities that are ready to be finished, but waiting
441 * for the previous activity to settle down before doing so. It contains
442 * HistoryRecord objects.
443 */
444 final ArrayList mFinishingActivities = new ArrayList();
445
446 /**
447 * All of the applications we currently have running organized by name.
448 * The keys are strings of the application package name (as
449 * returned by the package manager), and the keys are ApplicationRecord
450 * objects.
451 */
452 final ProcessMap<ProcessRecord> mProcessNames
453 = new ProcessMap<ProcessRecord>();
454
455 /**
456 * The last time that various processes have crashed.
457 */
458 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
459
460 /**
461 * Set of applications that we consider to be bad, and will reject
462 * incoming broadcasts from (which the user has no control over).
463 * Processes are added to this set when they have crashed twice within
464 * a minimum amount of time; they are removed from it when they are
465 * later restarted (hopefully due to some user action). The value is the
466 * time it was added to the list.
467 */
468 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
469
470 /**
471 * All of the processes we currently have running organized by pid.
472 * The keys are the pid running the application.
473 *
474 * <p>NOTE: This object is protected by its own lock, NOT the global
475 * activity manager lock!
476 */
477 final SparseArray<ProcessRecord> mPidsSelfLocked
478 = new SparseArray<ProcessRecord>();
479
480 /**
481 * All of the processes that have been forced to be foreground. The key
482 * is the pid of the caller who requested it (we hold a death
483 * link on it).
484 */
485 abstract class ForegroundToken implements IBinder.DeathRecipient {
486 int pid;
487 IBinder token;
488 }
489 final SparseArray<ForegroundToken> mForegroundProcesses
490 = new SparseArray<ForegroundToken>();
491
492 /**
493 * List of records for processes that someone had tried to start before the
494 * system was ready. We don't start them at that point, but ensure they
495 * are started by the time booting is complete.
496 */
497 final ArrayList<ProcessRecord> mProcessesOnHold
498 = new ArrayList<ProcessRecord>();
499
500 /**
501 * List of records for processes that we have started and are waiting
502 * for them to call back. This is really only needed when running in
503 * single processes mode, in which case we do not have a unique pid for
504 * each process.
505 */
506 final ArrayList<ProcessRecord> mStartingProcesses
507 = new ArrayList<ProcessRecord>();
508
509 /**
510 * List of persistent applications that are in the process
511 * of being started.
512 */
513 final ArrayList<ProcessRecord> mPersistentStartingProcesses
514 = new ArrayList<ProcessRecord>();
515
516 /**
517 * Processes that are being forcibly torn down.
518 */
519 final ArrayList<ProcessRecord> mRemovedProcesses
520 = new ArrayList<ProcessRecord>();
521
522 /**
523 * List of running applications, sorted by recent usage.
524 * The first entry in the list is the least recently used.
525 * It contains ApplicationRecord objects. This list does NOT include
526 * any persistent application records (since we never want to exit them).
527 */
528 final ArrayList<ProcessRecord> mLRUProcesses
529 = new ArrayList<ProcessRecord>();
530
531 /**
532 * List of processes that should gc as soon as things are idle.
533 */
534 final ArrayList<ProcessRecord> mProcessesToGc
535 = new ArrayList<ProcessRecord>();
536
537 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800538 * This is the process holding what we currently consider to be
539 * the "home" activity.
540 */
541 private ProcessRecord mHomeProcess;
542
543 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 * List of running activities, sorted by recent usage.
545 * The first entry in the list is the least recently used.
546 * It contains HistoryRecord objects.
547 */
548 private final ArrayList mLRUActivities = new ArrayList();
549
550 /**
551 * Set of PendingResultRecord objects that are currently active.
552 */
553 final HashSet mPendingResultRecords = new HashSet();
554
555 /**
556 * Set of IntentSenderRecord objects that are currently active.
557 */
558 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
559 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
560
561 /**
562 * Intent broadcast that we have tried to start, but are
563 * waiting for its application's process to be created. We only
564 * need one (instead of a list) because we always process broadcasts
565 * one at a time, so no others can be started while waiting for this
566 * one.
567 */
568 BroadcastRecord mPendingBroadcast = null;
569
570 /**
571 * Keeps track of all IIntentReceivers that have been registered for
572 * broadcasts. Hash keys are the receiver IBinder, hash value is
573 * a ReceiverList.
574 */
575 final HashMap mRegisteredReceivers = new HashMap();
576
577 /**
578 * Resolver for broadcast intents to registered receivers.
579 * Holds BroadcastFilter (subclass of IntentFilter).
580 */
581 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
582 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
583 @Override
584 protected boolean allowFilterResult(
585 BroadcastFilter filter, List<BroadcastFilter> dest) {
586 IBinder target = filter.receiverList.receiver.asBinder();
587 for (int i=dest.size()-1; i>=0; i--) {
588 if (dest.get(i).receiverList.receiver.asBinder() == target) {
589 return false;
590 }
591 }
592 return true;
593 }
594 };
595
596 /**
597 * State of all active sticky broadcasts. Keys are the action of the
598 * sticky Intent, values are an ArrayList of all broadcasted intents with
599 * that action (which should usually be one).
600 */
601 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
602 new HashMap<String, ArrayList<Intent>>();
603
604 /**
605 * All currently running services.
606 */
607 final HashMap<ComponentName, ServiceRecord> mServices =
608 new HashMap<ComponentName, ServiceRecord>();
609
610 /**
611 * All currently running services indexed by the Intent used to start them.
612 */
613 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
614 new HashMap<Intent.FilterComparison, ServiceRecord>();
615
616 /**
617 * All currently bound service connections. Keys are the IBinder of
618 * the client's IServiceConnection.
619 */
620 final HashMap<IBinder, ConnectionRecord> mServiceConnections
621 = new HashMap<IBinder, ConnectionRecord>();
622
623 /**
624 * List of services that we have been asked to start,
625 * but haven't yet been able to. It is used to hold start requests
626 * while waiting for their corresponding application thread to get
627 * going.
628 */
629 final ArrayList<ServiceRecord> mPendingServices
630 = new ArrayList<ServiceRecord>();
631
632 /**
633 * List of services that are scheduled to restart following a crash.
634 */
635 final ArrayList<ServiceRecord> mRestartingServices
636 = new ArrayList<ServiceRecord>();
637
638 /**
639 * List of services that are in the process of being stopped.
640 */
641 final ArrayList<ServiceRecord> mStoppingServices
642 = new ArrayList<ServiceRecord>();
643
644 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700645 * Backup/restore process management
646 */
647 String mBackupAppName = null;
648 BackupRecord mBackupTarget = null;
649
650 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 * List of PendingThumbnailsRecord objects of clients who are still
652 * waiting to receive all of the thumbnails for a task.
653 */
654 final ArrayList mPendingThumbnails = new ArrayList();
655
656 /**
657 * List of HistoryRecord objects that have been finished and must
658 * still report back to a pending thumbnail receiver.
659 */
660 final ArrayList mCancelledThumbnails = new ArrayList();
661
662 /**
663 * All of the currently running global content providers. Keys are a
664 * string containing the provider name and values are a
665 * ContentProviderRecord object containing the data about it. Note
666 * that a single provider may be published under multiple names, so
667 * there may be multiple entries here for a single one in mProvidersByClass.
668 */
669 final HashMap mProvidersByName = new HashMap();
670
671 /**
672 * All of the currently running global content providers. Keys are a
673 * string containing the provider's implementation class and values are a
674 * ContentProviderRecord object containing the data about it.
675 */
676 final HashMap mProvidersByClass = new HashMap();
677
678 /**
679 * List of content providers who have clients waiting for them. The
680 * application is currently being launched and the provider will be
681 * removed from this list once it is published.
682 */
683 final ArrayList mLaunchingProviders = new ArrayList();
684
685 /**
686 * Global set of specific Uri permissions that have been granted.
687 */
688 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
689 = new SparseArray<HashMap<Uri, UriPermission>>();
690
691 /**
692 * Thread-local storage used to carry caller permissions over through
693 * indirect content-provider access.
694 * @see #ActivityManagerService.openContentUri()
695 */
696 private class Identity {
697 public int pid;
698 public int uid;
699
700 Identity(int _pid, int _uid) {
701 pid = _pid;
702 uid = _uid;
703 }
704 }
705 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
706
707 /**
708 * All information we have collected about the runtime performance of
709 * any user id that can impact battery performance.
710 */
711 final BatteryStatsService mBatteryStatsService;
712
713 /**
714 * information about component usage
715 */
716 final UsageStatsService mUsageStatsService;
717
718 /**
719 * Current configuration information. HistoryRecord objects are given
720 * a reference to this object to indicate which configuration they are
721 * currently running in, so this object must be kept immutable.
722 */
723 Configuration mConfiguration = new Configuration();
724
725 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700726 * Hardware-reported OpenGLES version.
727 */
728 final int GL_ES_VERSION;
729
730 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 * List of initialization arguments to pass to all processes when binding applications to them.
732 * For example, references to the commonly used services.
733 */
734 HashMap<String, IBinder> mAppBindArgs;
735
736 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700737 * Temporary to avoid allocations. Protected by main lock.
738 */
739 final StringBuilder mStringBuilder = new StringBuilder(256);
740
741 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 * Used to control how we initialize the service.
743 */
744 boolean mStartRunning = false;
745 ComponentName mTopComponent;
746 String mTopAction;
747 String mTopData;
748 boolean mSystemReady = false;
749 boolean mBooting = false;
750
751 Context mContext;
752
753 int mFactoryTest;
754
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700755 boolean mCheckedForSetup;
756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700758 * The time at which we will allow normal application switches again,
759 * after a call to {@link #stopAppSwitches()}.
760 */
761 long mAppSwitchesAllowedTime;
762
763 /**
764 * This is set to true after the first switch after mAppSwitchesAllowedTime
765 * is set; any switches after that will clear the time.
766 */
767 boolean mDidAppSwitch;
768
769 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 * Set while we are wanting to sleep, to prevent any
771 * activities from being started/resumed.
772 */
773 boolean mSleeping = false;
774
775 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700776 * Set if we are shutting down the system, similar to sleeping.
777 */
778 boolean mShuttingDown = false;
779
780 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 * Set when the system is going to sleep, until we have
782 * successfully paused the current activity and released our wake lock.
783 * At that point the system is allowed to actually sleep.
784 */
785 PowerManager.WakeLock mGoingToSleep;
786
787 /**
788 * We don't want to allow the device to go to sleep while in the process
789 * of launching an activity. This is primarily to allow alarm intent
790 * receivers to launch an activity and get that to run before the device
791 * goes back to sleep.
792 */
793 PowerManager.WakeLock mLaunchingActivity;
794
795 /**
796 * Task identifier that activities are currently being started
797 * in. Incremented each time a new task is created.
798 * todo: Replace this with a TokenSpace class that generates non-repeating
799 * integers that won't wrap.
800 */
801 int mCurTask = 1;
802
803 /**
804 * Current sequence id for oom_adj computation traversal.
805 */
806 int mAdjSeq = 0;
807
808 /**
809 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
810 * is set, indicating the user wants processes started in such a way
811 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
812 * running in each process (thus no pre-initialized process, etc).
813 */
814 boolean mSimpleProcessManagement = false;
815
816 /**
817 * System monitoring: number of processes that died since the last
818 * N procs were started.
819 */
820 int[] mProcDeaths = new int[20];
821
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700822 /**
823 * This is set if we had to do a delayed dexopt of an app before launching
824 * it, to increasing the ANR timeouts in that case.
825 */
826 boolean mDidDexOpt;
827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 String mDebugApp = null;
829 boolean mWaitForDebugger = false;
830 boolean mDebugTransient = false;
831 String mOrigDebugApp = null;
832 boolean mOrigWaitForDebugger = false;
833 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700834 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700836 final RemoteCallbackList<IActivityWatcher> mWatchers
837 = new RemoteCallbackList<IActivityWatcher>();
838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 /**
840 * Callback of last caller to {@link #requestPss}.
841 */
842 Runnable mRequestPssCallback;
843
844 /**
845 * Remaining processes for which we are waiting results from the last
846 * call to {@link #requestPss}.
847 */
848 final ArrayList<ProcessRecord> mRequestPssList
849 = new ArrayList<ProcessRecord>();
850
851 /**
852 * Runtime statistics collection thread. This object's lock is used to
853 * protect all related state.
854 */
855 final Thread mProcessStatsThread;
856
857 /**
858 * Used to collect process stats when showing not responding dialog.
859 * Protected by mProcessStatsThread.
860 */
861 final ProcessStats mProcessStats = new ProcessStats(
862 MONITOR_THREAD_CPU_USAGE);
863 long mLastCpuTime = 0;
864 long mLastWriteTime = 0;
865
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700866 long mInitialStartTime = 0;
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 /**
869 * Set to true after the system has finished booting.
870 */
871 boolean mBooted = false;
872
873 int mProcessLimit = 0;
874
875 WindowManagerService mWindowManager;
876
877 static ActivityManagerService mSelf;
878 static ActivityThread mSystemThread;
879
880 private final class AppDeathRecipient implements IBinder.DeathRecipient {
881 final ProcessRecord mApp;
882 final int mPid;
883 final IApplicationThread mAppThread;
884
885 AppDeathRecipient(ProcessRecord app, int pid,
886 IApplicationThread thread) {
887 if (localLOGV) Log.v(
888 TAG, "New death recipient " + this
889 + " for thread " + thread.asBinder());
890 mApp = app;
891 mPid = pid;
892 mAppThread = thread;
893 }
894
895 public void binderDied() {
896 if (localLOGV) Log.v(
897 TAG, "Death received in " + this
898 + " for thread " + mAppThread.asBinder());
899 removeRequestedPss(mApp);
900 synchronized(ActivityManagerService.this) {
901 appDiedLocked(mApp, mPid, mAppThread);
902 }
903 }
904 }
905
906 static final int SHOW_ERROR_MSG = 1;
907 static final int SHOW_NOT_RESPONDING_MSG = 2;
908 static final int SHOW_FACTORY_ERROR_MSG = 3;
909 static final int UPDATE_CONFIGURATION_MSG = 4;
910 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
911 static final int WAIT_FOR_DEBUGGER_MSG = 6;
912 static final int BROADCAST_INTENT_MSG = 7;
913 static final int BROADCAST_TIMEOUT_MSG = 8;
914 static final int PAUSE_TIMEOUT_MSG = 9;
915 static final int IDLE_TIMEOUT_MSG = 10;
916 static final int IDLE_NOW_MSG = 11;
917 static final int SERVICE_TIMEOUT_MSG = 12;
918 static final int UPDATE_TIME_ZONE = 13;
919 static final int SHOW_UID_ERROR_MSG = 14;
920 static final int IM_FEELING_LUCKY_MSG = 15;
921 static final int LAUNCH_TIMEOUT_MSG = 16;
922 static final int DESTROY_TIMEOUT_MSG = 17;
923 static final int SERVICE_ERROR_MSG = 18;
924 static final int RESUME_TOP_ACTIVITY_MSG = 19;
925 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700926 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927
928 AlertDialog mUidAlert;
929
930 final Handler mHandler = new Handler() {
931 //public Handler() {
932 // if (localLOGV) Log.v(TAG, "Handler started!");
933 //}
934
935 public void handleMessage(Message msg) {
936 switch (msg.what) {
937 case SHOW_ERROR_MSG: {
938 HashMap data = (HashMap) msg.obj;
939 byte[] crashData = (byte[])data.get("crashData");
940 if (crashData != null) {
941 // This needs to be *un*synchronized to avoid deadlock.
942 ContentResolver resolver = mContext.getContentResolver();
943 Checkin.reportCrash(resolver, crashData);
944 }
945 synchronized (ActivityManagerService.this) {
946 ProcessRecord proc = (ProcessRecord)data.get("app");
947 if (proc != null && proc.crashDialog != null) {
948 Log.e(TAG, "App already has crash dialog: " + proc);
949 return;
950 }
951 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700952 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 Dialog d = new AppErrorDialog(
954 mContext, res, proc,
955 (Integer)data.get("flags"),
956 (String)data.get("shortMsg"),
957 (String)data.get("longMsg"));
958 d.show();
959 proc.crashDialog = d;
960 } else {
961 // The device is asleep, so just pretend that the user
962 // saw a crash dialog and hit "force quit".
963 res.set(0);
964 }
965 }
966 } break;
967 case SHOW_NOT_RESPONDING_MSG: {
968 synchronized (ActivityManagerService.this) {
969 HashMap data = (HashMap) msg.obj;
970 ProcessRecord proc = (ProcessRecord)data.get("app");
971 if (proc != null && proc.anrDialog != null) {
972 Log.e(TAG, "App already has anr dialog: " + proc);
973 return;
974 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800975
976 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
977 null, null, 0, null, null, null,
978 false, false, MY_PID, Process.SYSTEM_UID);
979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
981 mContext, proc, (HistoryRecord)data.get("activity"));
982 d.show();
983 proc.anrDialog = d;
984 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700985
986 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 } break;
988 case SHOW_FACTORY_ERROR_MSG: {
989 Dialog d = new FactoryErrorDialog(
990 mContext, msg.getData().getCharSequence("msg"));
991 d.show();
992 enableScreenAfterBoot();
993 } break;
994 case UPDATE_CONFIGURATION_MSG: {
995 final ContentResolver resolver = mContext.getContentResolver();
996 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
997 } break;
998 case GC_BACKGROUND_PROCESSES_MSG: {
999 synchronized (ActivityManagerService.this) {
1000 performAppGcsIfAppropriateLocked();
1001 }
1002 } break;
1003 case WAIT_FOR_DEBUGGER_MSG: {
1004 synchronized (ActivityManagerService.this) {
1005 ProcessRecord app = (ProcessRecord)msg.obj;
1006 if (msg.arg1 != 0) {
1007 if (!app.waitedForDebugger) {
1008 Dialog d = new AppWaitingForDebuggerDialog(
1009 ActivityManagerService.this,
1010 mContext, app);
1011 app.waitDialog = d;
1012 app.waitedForDebugger = true;
1013 d.show();
1014 }
1015 } else {
1016 if (app.waitDialog != null) {
1017 app.waitDialog.dismiss();
1018 app.waitDialog = null;
1019 }
1020 }
1021 }
1022 } break;
1023 case BROADCAST_INTENT_MSG: {
1024 if (DEBUG_BROADCAST) Log.v(
1025 TAG, "Received BROADCAST_INTENT_MSG");
1026 processNextBroadcast(true);
1027 } break;
1028 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001029 if (mDidDexOpt) {
1030 mDidDexOpt = false;
1031 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1032 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1033 return;
1034 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 broadcastTimeout();
1036 } break;
1037 case PAUSE_TIMEOUT_MSG: {
1038 IBinder token = (IBinder)msg.obj;
1039 // We don't at this point know if the activity is fullscreen,
1040 // so we need to be conservative and assume it isn't.
1041 Log.w(TAG, "Activity pause timeout for " + token);
1042 activityPaused(token, null, true);
1043 } break;
1044 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001045 if (mDidDexOpt) {
1046 mDidDexOpt = false;
1047 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1048 nmsg.obj = msg.obj;
1049 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1050 return;
1051 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 // We don't at this point know if the activity is fullscreen,
1053 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001054 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 Log.w(TAG, "Activity idle timeout for " + token);
1056 activityIdleInternal(token, true);
1057 } break;
1058 case DESTROY_TIMEOUT_MSG: {
1059 IBinder token = (IBinder)msg.obj;
1060 // We don't at this point know if the activity is fullscreen,
1061 // so we need to be conservative and assume it isn't.
1062 Log.w(TAG, "Activity destroy timeout for " + token);
1063 activityDestroyed(token);
1064 } break;
1065 case IDLE_NOW_MSG: {
1066 IBinder token = (IBinder)msg.obj;
1067 activityIdle(token);
1068 } break;
1069 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001070 if (mDidDexOpt) {
1071 mDidDexOpt = false;
1072 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1073 nmsg.obj = msg.obj;
1074 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1075 return;
1076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 serviceTimeout((ProcessRecord)msg.obj);
1078 } break;
1079 case UPDATE_TIME_ZONE: {
1080 synchronized (ActivityManagerService.this) {
1081 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1082 ProcessRecord r = mLRUProcesses.get(i);
1083 if (r.thread != null) {
1084 try {
1085 r.thread.updateTimeZone();
1086 } catch (RemoteException ex) {
1087 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1088 }
1089 }
1090 }
1091 }
1092 break;
1093 }
1094 case SHOW_UID_ERROR_MSG: {
1095 // XXX This is a temporary dialog, no need to localize.
1096 AlertDialog d = new BaseErrorDialog(mContext);
1097 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1098 d.setCancelable(false);
1099 d.setTitle("System UIDs Inconsistent");
1100 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1101 d.setButton("I'm Feeling Lucky",
1102 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1103 mUidAlert = d;
1104 d.show();
1105 } break;
1106 case IM_FEELING_LUCKY_MSG: {
1107 if (mUidAlert != null) {
1108 mUidAlert.dismiss();
1109 mUidAlert = null;
1110 }
1111 } break;
1112 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001113 if (mDidDexOpt) {
1114 mDidDexOpt = false;
1115 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1116 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1117 return;
1118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 synchronized (ActivityManagerService.this) {
1120 if (mLaunchingActivity.isHeld()) {
1121 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1122 mLaunchingActivity.release();
1123 }
1124 }
1125 } break;
1126 case SERVICE_ERROR_MSG: {
1127 ServiceRecord srv = (ServiceRecord)msg.obj;
1128 // This needs to be *un*synchronized to avoid deadlock.
1129 Checkin.logEvent(mContext.getContentResolver(),
1130 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1131 srv.name.toShortString());
1132 } break;
1133 case RESUME_TOP_ACTIVITY_MSG: {
1134 synchronized (ActivityManagerService.this) {
1135 resumeTopActivityLocked(null);
1136 }
1137 }
1138 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001139 if (mDidDexOpt) {
1140 mDidDexOpt = false;
1141 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1142 nmsg.obj = msg.obj;
1143 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1144 return;
1145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 ProcessRecord app = (ProcessRecord)msg.obj;
1147 synchronized (ActivityManagerService.this) {
1148 processStartTimedOutLocked(app);
1149 }
1150 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001151 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1152 synchronized (ActivityManagerService.this) {
1153 doPendingActivityLaunchesLocked(true);
1154 }
1155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 }
1157 }
1158 };
1159
1160 public static void setSystemProcess() {
1161 try {
1162 ActivityManagerService m = mSelf;
1163
1164 ServiceManager.addService("activity", m);
1165 ServiceManager.addService("meminfo", new MemBinder(m));
1166 if (MONITOR_CPU_USAGE) {
1167 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1168 }
1169 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1170 ServiceManager.addService("activity.services", new ServicesBinder(m));
1171 ServiceManager.addService("activity.senders", new SendersBinder(m));
1172 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1173 ServiceManager.addService("permission", new PermissionController(m));
1174
1175 ApplicationInfo info =
1176 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001177 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 synchronized (mSelf) {
1179 ProcessRecord app = mSelf.newProcessRecordLocked(
1180 mSystemThread.getApplicationThread(), info,
1181 info.processName);
1182 app.persistent = true;
1183 app.pid = Process.myPid();
1184 app.maxAdj = SYSTEM_ADJ;
1185 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1186 synchronized (mSelf.mPidsSelfLocked) {
1187 mSelf.mPidsSelfLocked.put(app.pid, app);
1188 }
1189 mSelf.updateLRUListLocked(app, true);
1190 }
1191 } catch (PackageManager.NameNotFoundException e) {
1192 throw new RuntimeException(
1193 "Unable to find android system package", e);
1194 }
1195 }
1196
1197 public void setWindowManager(WindowManagerService wm) {
1198 mWindowManager = wm;
1199 }
1200
1201 public static final Context main(int factoryTest) {
1202 AThread thr = new AThread();
1203 thr.start();
1204
1205 synchronized (thr) {
1206 while (thr.mService == null) {
1207 try {
1208 thr.wait();
1209 } catch (InterruptedException e) {
1210 }
1211 }
1212 }
1213
1214 ActivityManagerService m = thr.mService;
1215 mSelf = m;
1216 ActivityThread at = ActivityThread.systemMain();
1217 mSystemThread = at;
1218 Context context = at.getSystemContext();
1219 m.mContext = context;
1220 m.mFactoryTest = factoryTest;
1221 PowerManager pm =
1222 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1223 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1224 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1225 m.mLaunchingActivity.setReferenceCounted(false);
1226
1227 m.mBatteryStatsService.publish(context);
1228 m.mUsageStatsService.publish(context);
1229
1230 synchronized (thr) {
1231 thr.mReady = true;
1232 thr.notifyAll();
1233 }
1234
1235 m.startRunning(null, null, null, null);
1236
1237 return context;
1238 }
1239
1240 public static ActivityManagerService self() {
1241 return mSelf;
1242 }
1243
1244 static class AThread extends Thread {
1245 ActivityManagerService mService;
1246 boolean mReady = false;
1247
1248 public AThread() {
1249 super("ActivityManager");
1250 }
1251
1252 public void run() {
1253 Looper.prepare();
1254
1255 android.os.Process.setThreadPriority(
1256 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1257
1258 ActivityManagerService m = new ActivityManagerService();
1259
1260 synchronized (this) {
1261 mService = m;
1262 notifyAll();
1263 }
1264
1265 synchronized (this) {
1266 while (!mReady) {
1267 try {
1268 wait();
1269 } catch (InterruptedException e) {
1270 }
1271 }
1272 }
1273
1274 Looper.loop();
1275 }
1276 }
1277
1278 static class BroadcastsBinder extends Binder {
1279 ActivityManagerService mActivityManagerService;
1280 BroadcastsBinder(ActivityManagerService activityManagerService) {
1281 mActivityManagerService = activityManagerService;
1282 }
1283
1284 @Override
1285 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1286 mActivityManagerService.dumpBroadcasts(pw);
1287 }
1288 }
1289
1290 static class ServicesBinder extends Binder {
1291 ActivityManagerService mActivityManagerService;
1292 ServicesBinder(ActivityManagerService activityManagerService) {
1293 mActivityManagerService = activityManagerService;
1294 }
1295
1296 @Override
1297 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1298 mActivityManagerService.dumpServices(pw);
1299 }
1300 }
1301
1302 static class SendersBinder extends Binder {
1303 ActivityManagerService mActivityManagerService;
1304 SendersBinder(ActivityManagerService activityManagerService) {
1305 mActivityManagerService = activityManagerService;
1306 }
1307
1308 @Override
1309 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1310 mActivityManagerService.dumpSenders(pw);
1311 }
1312 }
1313
1314 static class ProvidersBinder extends Binder {
1315 ActivityManagerService mActivityManagerService;
1316 ProvidersBinder(ActivityManagerService activityManagerService) {
1317 mActivityManagerService = activityManagerService;
1318 }
1319
1320 @Override
1321 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1322 mActivityManagerService.dumpProviders(pw);
1323 }
1324 }
1325
1326 static class MemBinder extends Binder {
1327 ActivityManagerService mActivityManagerService;
1328 MemBinder(ActivityManagerService activityManagerService) {
1329 mActivityManagerService = activityManagerService;
1330 }
1331
1332 @Override
1333 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1334 ActivityManagerService service = mActivityManagerService;
1335 ArrayList<ProcessRecord> procs;
1336 synchronized (mActivityManagerService) {
1337 if (args != null && args.length > 0
1338 && args[0].charAt(0) != '-') {
1339 procs = new ArrayList<ProcessRecord>();
1340 int pid = -1;
1341 try {
1342 pid = Integer.parseInt(args[0]);
1343 } catch (NumberFormatException e) {
1344
1345 }
1346 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1347 ProcessRecord proc = service.mLRUProcesses.get(i);
1348 if (proc.pid == pid) {
1349 procs.add(proc);
1350 } else if (proc.processName.equals(args[0])) {
1351 procs.add(proc);
1352 }
1353 }
1354 if (procs.size() <= 0) {
1355 pw.println("No process found for: " + args[0]);
1356 return;
1357 }
1358 } else {
1359 procs = service.mLRUProcesses;
1360 }
1361 }
1362 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1363 }
1364 }
1365
1366 static class CpuBinder extends Binder {
1367 ActivityManagerService mActivityManagerService;
1368 CpuBinder(ActivityManagerService activityManagerService) {
1369 mActivityManagerService = activityManagerService;
1370 }
1371
1372 @Override
1373 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1374 synchronized (mActivityManagerService.mProcessStatsThread) {
1375 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1376 }
1377 }
1378 }
1379
1380 private ActivityManagerService() {
1381 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1382 if (v != null && Integer.getInteger(v) != 0) {
1383 mSimpleProcessManagement = true;
1384 }
1385 v = System.getenv("ANDROID_DEBUG_APP");
1386 if (v != null) {
1387 mSimpleProcessManagement = true;
1388 }
1389
1390 MY_PID = Process.myPid();
1391
1392 File dataDir = Environment.getDataDirectory();
1393 File systemDir = new File(dataDir, "system");
1394 systemDir.mkdirs();
1395 mBatteryStatsService = new BatteryStatsService(new File(
1396 systemDir, "batterystats.bin").toString());
1397 mBatteryStatsService.getActiveStatistics().readLocked();
1398 mBatteryStatsService.getActiveStatistics().writeLocked();
1399
1400 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001401 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402
Jack Palevichb90d28c2009-07-22 15:35:24 -07001403 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1404 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 mConfiguration.makeDefault();
1407 mProcessStats.init();
1408
1409 // Add ourself to the Watchdog monitors.
1410 Watchdog.getInstance().addMonitor(this);
1411
1412 // These values are set in system/rootdir/init.rc on startup.
1413 FOREGROUND_APP_ADJ =
1414 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1415 VISIBLE_APP_ADJ =
1416 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1417 SECONDARY_SERVER_ADJ =
1418 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001419 BACKUP_APP_ADJ =
1420 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001421 HOME_APP_ADJ =
1422 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 HIDDEN_APP_MIN_ADJ =
1424 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1425 CONTENT_PROVIDER_ADJ =
1426 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1427 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1428 EMPTY_APP_ADJ =
1429 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1430 FOREGROUND_APP_MEM =
1431 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1432 VISIBLE_APP_MEM =
1433 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1434 SECONDARY_SERVER_MEM =
1435 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001436 BACKUP_APP_MEM =
1437 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001438 HOME_APP_MEM =
1439 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 HIDDEN_APP_MEM =
1441 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1442 EMPTY_APP_MEM =
1443 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1444
1445 mProcessStatsThread = new Thread("ProcessStats") {
1446 public void run() {
1447 while (true) {
1448 try {
1449 try {
1450 synchronized(this) {
1451 final long now = SystemClock.uptimeMillis();
1452 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1453 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1454 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1455 // + ", write delay=" + nextWriteDelay);
1456 if (nextWriteDelay < nextCpuDelay) {
1457 nextCpuDelay = nextWriteDelay;
1458 }
1459 if (nextCpuDelay > 0) {
1460 this.wait(nextCpuDelay);
1461 }
1462 }
1463 } catch (InterruptedException e) {
1464 }
1465
1466 updateCpuStatsNow();
1467 } catch (Exception e) {
1468 Log.e(TAG, "Unexpected exception collecting process stats", e);
1469 }
1470 }
1471 }
1472 };
1473 mProcessStatsThread.start();
1474 }
1475
1476 @Override
1477 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1478 throws RemoteException {
1479 try {
1480 return super.onTransact(code, data, reply, flags);
1481 } catch (RuntimeException e) {
1482 // The activity manager only throws security exceptions, so let's
1483 // log all others.
1484 if (!(e instanceof SecurityException)) {
1485 Log.e(TAG, "Activity Manager Crash", e);
1486 }
1487 throw e;
1488 }
1489 }
1490
1491 void updateCpuStats() {
1492 synchronized (mProcessStatsThread) {
1493 final long now = SystemClock.uptimeMillis();
1494 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1495 mProcessStatsThread.notify();
1496 }
1497 }
1498 }
1499
1500 void updateCpuStatsNow() {
1501 synchronized (mProcessStatsThread) {
1502 final long now = SystemClock.uptimeMillis();
1503 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 if (MONITOR_CPU_USAGE &&
1506 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1507 mLastCpuTime = now;
1508 haveNewCpuStats = true;
1509 mProcessStats.update();
1510 //Log.i(TAG, mProcessStats.printCurrentState());
1511 //Log.i(TAG, "Total CPU usage: "
1512 // + mProcessStats.getTotalCpuPercent() + "%");
1513
1514 // Log the cpu usage if the property is set.
1515 if ("true".equals(SystemProperties.get("events.cpu"))) {
1516 int user = mProcessStats.getLastUserTime();
1517 int system = mProcessStats.getLastSystemTime();
1518 int iowait = mProcessStats.getLastIoWaitTime();
1519 int irq = mProcessStats.getLastIrqTime();
1520 int softIrq = mProcessStats.getLastSoftIrqTime();
1521 int idle = mProcessStats.getLastIdleTime();
1522
1523 int total = user + system + iowait + irq + softIrq + idle;
1524 if (total == 0) total = 1;
1525
1526 EventLog.writeEvent(LOG_CPU,
1527 ((user+system+iowait+irq+softIrq) * 100) / total,
1528 (user * 100) / total,
1529 (system * 100) / total,
1530 (iowait * 100) / total,
1531 (irq * 100) / total,
1532 (softIrq * 100) / total);
1533 }
1534 }
1535
Amith Yamasani819f9282009-06-24 23:18:15 -07001536 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001537 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 synchronized(mPidsSelfLocked) {
1539 if (haveNewCpuStats) {
1540 if (mBatteryStatsService.isOnBattery()) {
1541 final int N = mProcessStats.countWorkingStats();
1542 for (int i=0; i<N; i++) {
1543 ProcessStats.Stats st
1544 = mProcessStats.getWorkingStats(i);
1545 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1546 if (pr != null) {
1547 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1548 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001549 } else {
1550 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001551 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001552 if (ps != null) {
1553 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
1556 }
1557 }
1558 }
1559 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1562 mLastWriteTime = now;
1563 mBatteryStatsService.getActiveStatistics().writeLocked();
1564 }
1565 }
1566 }
1567 }
1568
1569 /**
1570 * Initialize the application bind args. These are passed to each
1571 * process when the bindApplication() IPC is sent to the process. They're
1572 * lazily setup to make sure the services are running when they're asked for.
1573 */
1574 private HashMap<String, IBinder> getCommonServicesLocked() {
1575 if (mAppBindArgs == null) {
1576 mAppBindArgs = new HashMap<String, IBinder>();
1577
1578 // Setup the application init args
1579 mAppBindArgs.put("package", ServiceManager.getService("package"));
1580 mAppBindArgs.put("window", ServiceManager.getService("window"));
1581 mAppBindArgs.put(Context.ALARM_SERVICE,
1582 ServiceManager.getService(Context.ALARM_SERVICE));
1583 }
1584 return mAppBindArgs;
1585 }
1586
1587 private final void setFocusedActivityLocked(HistoryRecord r) {
1588 if (mFocusedActivity != r) {
1589 mFocusedActivity = r;
1590 mWindowManager.setFocusedApp(r, true);
1591 }
1592 }
1593
1594 private final void updateLRUListLocked(ProcessRecord app,
1595 boolean oomAdj) {
1596 // put it on the LRU to keep track of when it should be exited.
1597 int lrui = mLRUProcesses.indexOf(app);
1598 if (lrui >= 0) mLRUProcesses.remove(lrui);
1599 mLRUProcesses.add(app);
1600 //Log.i(TAG, "Putting proc to front: " + app.processName);
1601 if (oomAdj) {
1602 updateOomAdjLocked();
1603 }
1604 }
1605
1606 private final boolean updateLRUListLocked(HistoryRecord r) {
1607 final boolean hadit = mLRUActivities.remove(r);
1608 mLRUActivities.add(r);
1609 return hadit;
1610 }
1611
1612 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1613 int i = mHistory.size()-1;
1614 while (i >= 0) {
1615 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1616 if (!r.finishing && r != notTop) {
1617 return r;
1618 }
1619 i--;
1620 }
1621 return null;
1622 }
1623
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001624 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1625 int i = mHistory.size()-1;
1626 while (i >= 0) {
1627 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1628 if (!r.finishing && !r.delayedResume && r != notTop) {
1629 return r;
1630 }
1631 i--;
1632 }
1633 return null;
1634 }
1635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 /**
1637 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001638 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 *
1640 * @param token If non-null, any history records matching this token will be skipped.
1641 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1642 *
1643 * @return Returns the HistoryRecord of the next activity on the stack.
1644 */
1645 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1646 int i = mHistory.size()-1;
1647 while (i >= 0) {
1648 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1649 // Note: the taskId check depends on real taskId fields being non-zero
1650 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1651 return r;
1652 }
1653 i--;
1654 }
1655 return null;
1656 }
1657
1658 private final ProcessRecord getProcessRecordLocked(
1659 String processName, int uid) {
1660 if (uid == Process.SYSTEM_UID) {
1661 // The system gets to run in any process. If there are multiple
1662 // processes with the same uid, just pick the first (this
1663 // should never happen).
1664 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1665 processName);
1666 return procs != null ? procs.valueAt(0) : null;
1667 }
1668 ProcessRecord proc = mProcessNames.get(processName, uid);
1669 return proc;
1670 }
1671
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001672 private void ensurePackageDexOpt(String packageName) {
1673 IPackageManager pm = ActivityThread.getPackageManager();
1674 try {
1675 if (pm.performDexOpt(packageName)) {
1676 mDidDexOpt = true;
1677 }
1678 } catch (RemoteException e) {
1679 }
1680 }
1681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 private boolean isNextTransitionForward() {
1683 int transit = mWindowManager.getPendingAppTransition();
1684 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1685 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1686 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1687 }
1688
1689 private final boolean realStartActivityLocked(HistoryRecord r,
1690 ProcessRecord app, boolean andResume, boolean checkConfig)
1691 throws RemoteException {
1692
1693 r.startFreezingScreenLocked(app, 0);
1694 mWindowManager.setAppVisibility(r, true);
1695
1696 // Have the window manager re-evaluate the orientation of
1697 // the screen based on the new activity order. Note that
1698 // as a result of this, it can call back into the activity
1699 // manager with a new orientation. We don't care about that,
1700 // because the activity is not currently running so we are
1701 // just restarting it anyway.
1702 if (checkConfig) {
1703 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001704 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 r.mayFreezeScreenLocked(app) ? r : null);
1706 updateConfigurationLocked(config, r);
1707 }
1708
1709 r.app = app;
1710
1711 if (localLOGV) Log.v(TAG, "Launching: " + r);
1712
1713 int idx = app.activities.indexOf(r);
1714 if (idx < 0) {
1715 app.activities.add(r);
1716 }
1717 updateLRUListLocked(app, true);
1718
1719 try {
1720 if (app.thread == null) {
1721 throw new RemoteException();
1722 }
1723 List<ResultInfo> results = null;
1724 List<Intent> newIntents = null;
1725 if (andResume) {
1726 results = r.results;
1727 newIntents = r.newIntents;
1728 }
1729 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1730 + " icicle=" + r.icicle
1731 + " with results=" + results + " newIntents=" + newIntents
1732 + " andResume=" + andResume);
1733 if (andResume) {
1734 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1735 System.identityHashCode(r),
1736 r.task.taskId, r.shortComponentName);
1737 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001738 if (r.isHomeActivity) {
1739 mHomeProcess = app;
1740 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001741 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001743 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 r.info, r.icicle, results, newIntents, !andResume,
1745 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 } catch (RemoteException e) {
1747 if (r.launchFailed) {
1748 // This is the second time we failed -- finish activity
1749 // and give up.
1750 Log.e(TAG, "Second failure launching "
1751 + r.intent.getComponent().flattenToShortString()
1752 + ", giving up", e);
1753 appDiedLocked(app, app.pid, app.thread);
1754 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1755 "2nd-crash");
1756 return false;
1757 }
1758
1759 // This is the first time we failed -- restart process and
1760 // retry.
1761 app.activities.remove(r);
1762 throw e;
1763 }
1764
1765 r.launchFailed = false;
1766 if (updateLRUListLocked(r)) {
1767 Log.w(TAG, "Activity " + r
1768 + " being launched, but already in LRU list");
1769 }
1770
1771 if (andResume) {
1772 // As part of the process of launching, ActivityThread also performs
1773 // a resume.
1774 r.state = ActivityState.RESUMED;
1775 r.icicle = null;
1776 r.haveState = false;
1777 r.stopped = false;
1778 mResumedActivity = r;
1779 r.task.touchActiveTime();
1780 completeResumeLocked(r);
1781 pauseIfSleepingLocked();
1782 } else {
1783 // This activity is not starting in the resumed state... which
1784 // should look like we asked it to pause+stop (but remain visible),
1785 // and it has done so and reported back the current icicle and
1786 // other state.
1787 r.state = ActivityState.STOPPED;
1788 r.stopped = true;
1789 }
1790
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001791 // Launch the new version setup screen if needed. We do this -after-
1792 // launching the initial activity (that is, home), so that it can have
1793 // a chance to initialize itself while in the background, making the
1794 // switch back to it faster and look better.
1795 startSetupActivityLocked();
1796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 return true;
1798 }
1799
1800 private final void startSpecificActivityLocked(HistoryRecord r,
1801 boolean andResume, boolean checkConfig) {
1802 // Is this activity's application already running?
1803 ProcessRecord app = getProcessRecordLocked(r.processName,
1804 r.info.applicationInfo.uid);
1805
1806 if (r.startTime == 0) {
1807 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001808 if (mInitialStartTime == 0) {
1809 mInitialStartTime = r.startTime;
1810 }
1811 } else if (mInitialStartTime == 0) {
1812 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 }
1814
1815 if (app != null && app.thread != null) {
1816 try {
1817 realStartActivityLocked(r, app, andResume, checkConfig);
1818 return;
1819 } catch (RemoteException e) {
1820 Log.w(TAG, "Exception when starting activity "
1821 + r.intent.getComponent().flattenToShortString(), e);
1822 }
1823
1824 // If a dead object exception was thrown -- fall through to
1825 // restart the application.
1826 }
1827
1828 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1829 "activity", r.intent.getComponent());
1830 }
1831
1832 private final ProcessRecord startProcessLocked(String processName,
1833 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1834 String hostingType, ComponentName hostingName) {
1835 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1836 // We don't have to do anything more if:
1837 // (1) There is an existing application record; and
1838 // (2) The caller doesn't think it is dead, OR there is no thread
1839 // object attached to it so we know it couldn't have crashed; and
1840 // (3) There is a pid assigned to it, so it is either starting or
1841 // already running.
1842 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1843 + " app=" + app + " knownToBeDead=" + knownToBeDead
1844 + " thread=" + (app != null ? app.thread : null)
1845 + " pid=" + (app != null ? app.pid : -1));
1846 if (app != null &&
1847 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1848 return app;
1849 }
1850
1851 String hostingNameStr = hostingName != null
1852 ? hostingName.flattenToShortString() : null;
1853
1854 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1855 // If we are in the background, then check to see if this process
1856 // is bad. If so, we will just silently fail.
1857 if (mBadProcesses.get(info.processName, info.uid) != null) {
1858 return null;
1859 }
1860 } else {
1861 // When the user is explicitly starting a process, then clear its
1862 // crash count so that we won't make it bad until they see at
1863 // least one crash dialog again, and make the process good again
1864 // if it had been bad.
1865 mProcessCrashTimes.remove(info.processName, info.uid);
1866 if (mBadProcesses.get(info.processName, info.uid) != null) {
1867 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1868 info.processName);
1869 mBadProcesses.remove(info.processName, info.uid);
1870 if (app != null) {
1871 app.bad = false;
1872 }
1873 }
1874 }
1875
1876 if (app == null) {
1877 app = newProcessRecordLocked(null, info, processName);
1878 mProcessNames.put(processName, info.uid, app);
1879 } else {
1880 // If this is a new package in the process, add the package to the list
1881 app.addPackage(info.packageName);
1882 }
1883
1884 // If the system is not ready yet, then hold off on starting this
1885 // process until it is.
1886 if (!mSystemReady
1887 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1888 if (!mProcessesOnHold.contains(app)) {
1889 mProcessesOnHold.add(app);
1890 }
1891 return app;
1892 }
1893
1894 startProcessLocked(app, hostingType, hostingNameStr);
1895 return (app.pid != 0) ? app : null;
1896 }
1897
1898 private final void startProcessLocked(ProcessRecord app,
1899 String hostingType, String hostingNameStr) {
1900 if (app.pid > 0 && app.pid != MY_PID) {
1901 synchronized (mPidsSelfLocked) {
1902 mPidsSelfLocked.remove(app.pid);
1903 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1904 }
1905 app.pid = 0;
1906 }
1907
1908 mProcessesOnHold.remove(app);
1909
1910 updateCpuStats();
1911
1912 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1913 mProcDeaths[0] = 0;
1914
1915 try {
1916 int uid = app.info.uid;
1917 int[] gids = null;
1918 try {
1919 gids = mContext.getPackageManager().getPackageGids(
1920 app.info.packageName);
1921 } catch (PackageManager.NameNotFoundException e) {
1922 Log.w(TAG, "Unable to retrieve gids", e);
1923 }
1924 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1925 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1926 && mTopComponent != null
1927 && app.processName.equals(mTopComponent.getPackageName())) {
1928 uid = 0;
1929 }
1930 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1931 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1932 uid = 0;
1933 }
1934 }
1935 int debugFlags = 0;
1936 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1937 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1938 }
1939 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1940 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1941 }
1942 if ("1".equals(SystemProperties.get("debug.assert"))) {
1943 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1944 }
1945 int pid = Process.start("android.app.ActivityThread",
1946 mSimpleProcessManagement ? app.processName : null, uid, uid,
1947 gids, debugFlags, null);
1948 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1949 synchronized (bs) {
1950 if (bs.isOnBattery()) {
1951 app.batteryStats.incStartsLocked();
1952 }
1953 }
1954
1955 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1956 app.processName, hostingType,
1957 hostingNameStr != null ? hostingNameStr : "");
1958
1959 if (app.persistent) {
1960 Watchdog.getInstance().processStarted(app, app.processName, pid);
1961 }
1962
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001963 StringBuilder buf = mStringBuilder;
1964 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001965 buf.append("Start proc ");
1966 buf.append(app.processName);
1967 buf.append(" for ");
1968 buf.append(hostingType);
1969 if (hostingNameStr != null) {
1970 buf.append(" ");
1971 buf.append(hostingNameStr);
1972 }
1973 buf.append(": pid=");
1974 buf.append(pid);
1975 buf.append(" uid=");
1976 buf.append(uid);
1977 buf.append(" gids={");
1978 if (gids != null) {
1979 for (int gi=0; gi<gids.length; gi++) {
1980 if (gi != 0) buf.append(", ");
1981 buf.append(gids[gi]);
1982
1983 }
1984 }
1985 buf.append("}");
1986 Log.i(TAG, buf.toString());
1987 if (pid == 0 || pid == MY_PID) {
1988 // Processes are being emulated with threads.
1989 app.pid = MY_PID;
1990 app.removed = false;
1991 mStartingProcesses.add(app);
1992 } else if (pid > 0) {
1993 app.pid = pid;
1994 app.removed = false;
1995 synchronized (mPidsSelfLocked) {
1996 this.mPidsSelfLocked.put(pid, app);
1997 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1998 msg.obj = app;
1999 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2000 }
2001 } else {
2002 app.pid = 0;
2003 RuntimeException e = new RuntimeException(
2004 "Failure starting process " + app.processName
2005 + ": returned pid=" + pid);
2006 Log.e(TAG, e.getMessage(), e);
2007 }
2008 } catch (RuntimeException e) {
2009 // XXX do better error recovery.
2010 app.pid = 0;
2011 Log.e(TAG, "Failure starting process " + app.processName, e);
2012 }
2013 }
2014
2015 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2016 if (mPausingActivity != null) {
2017 RuntimeException e = new RuntimeException();
2018 Log.e(TAG, "Trying to pause when pause is already pending for "
2019 + mPausingActivity, e);
2020 }
2021 HistoryRecord prev = mResumedActivity;
2022 if (prev == null) {
2023 RuntimeException e = new RuntimeException();
2024 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2025 resumeTopActivityLocked(null);
2026 return;
2027 }
2028 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2029 mResumedActivity = null;
2030 mPausingActivity = prev;
2031 mLastPausedActivity = prev;
2032 prev.state = ActivityState.PAUSING;
2033 prev.task.touchActiveTime();
2034
2035 updateCpuStats();
2036
2037 if (prev.app != null && prev.app.thread != null) {
2038 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2039 try {
2040 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2041 System.identityHashCode(prev),
2042 prev.shortComponentName);
2043 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2044 prev.configChangeFlags);
2045 updateUsageStats(prev, false);
2046 } catch (Exception e) {
2047 // Ignore exception, if process died other code will cleanup.
2048 Log.w(TAG, "Exception thrown during pause", e);
2049 mPausingActivity = null;
2050 mLastPausedActivity = null;
2051 }
2052 } else {
2053 mPausingActivity = null;
2054 mLastPausedActivity = null;
2055 }
2056
2057 // If we are not going to sleep, we want to ensure the device is
2058 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002059 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002060 mLaunchingActivity.acquire();
2061 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2062 // To be safe, don't allow the wake lock to be held for too long.
2063 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2064 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2065 }
2066 }
2067
2068
2069 if (mPausingActivity != null) {
2070 // Have the window manager pause its key dispatching until the new
2071 // activity has started. If we're pausing the activity just because
2072 // the screen is being turned off and the UI is sleeping, don't interrupt
2073 // key dispatch; the same activity will pick it up again on wakeup.
2074 if (!uiSleeping) {
2075 prev.pauseKeyDispatchingLocked();
2076 } else {
2077 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2078 }
2079
2080 // Schedule a pause timeout in case the app doesn't respond.
2081 // We don't give it much time because this directly impacts the
2082 // responsiveness seen by the user.
2083 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2084 msg.obj = prev;
2085 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2086 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2087 } else {
2088 // This activity failed to schedule the
2089 // pause, so just treat it as being paused now.
2090 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2091 resumeTopActivityLocked(null);
2092 }
2093 }
2094
2095 private final void completePauseLocked() {
2096 HistoryRecord prev = mPausingActivity;
2097 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2098
2099 if (prev != null) {
2100 if (prev.finishing) {
2101 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2102 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2103 } else if (prev.app != null) {
2104 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2105 if (prev.waitingVisible) {
2106 prev.waitingVisible = false;
2107 mWaitingVisibleActivities.remove(prev);
2108 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2109 TAG, "Complete pause, no longer waiting: " + prev);
2110 }
2111 if (prev.configDestroy) {
2112 // The previous is being paused because the configuration
2113 // is changing, which means it is actually stopping...
2114 // To juggle the fact that we are also starting a new
2115 // instance right now, we need to first completely stop
2116 // the current instance before starting the new one.
2117 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2118 destroyActivityLocked(prev, true);
2119 } else {
2120 mStoppingActivities.add(prev);
2121 if (mStoppingActivities.size() > 3) {
2122 // If we already have a few activities waiting to stop,
2123 // then give up on things going idle and start clearing
2124 // them out.
2125 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2126 Message msg = Message.obtain();
2127 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2128 mHandler.sendMessage(msg);
2129 }
2130 }
2131 } else {
2132 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2133 prev = null;
2134 }
2135 mPausingActivity = null;
2136 }
2137
Dianne Hackborn55280a92009-05-07 15:53:46 -07002138 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 resumeTopActivityLocked(prev);
2140 } else {
2141 if (mGoingToSleep.isHeld()) {
2142 mGoingToSleep.release();
2143 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002144 if (mShuttingDown) {
2145 notifyAll();
2146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147 }
2148
2149 if (prev != null) {
2150 prev.resumeKeyDispatchingLocked();
2151 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002152
2153 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2154 long diff = 0;
2155 synchronized (mProcessStatsThread) {
2156 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2157 }
2158 if (diff > 0) {
2159 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2160 synchronized (bsi) {
2161 BatteryStatsImpl.Uid.Proc ps =
2162 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2163 prev.info.packageName);
2164 if (ps != null) {
2165 ps.addForegroundTimeLocked(diff);
2166 }
2167 }
2168 }
2169 }
2170 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 }
2172
2173 /**
2174 * Once we know that we have asked an application to put an activity in
2175 * the resumed state (either by launching it or explicitly telling it),
2176 * this function updates the rest of our state to match that fact.
2177 */
2178 private final void completeResumeLocked(HistoryRecord next) {
2179 next.idle = false;
2180 next.results = null;
2181 next.newIntents = null;
2182
2183 // schedule an idle timeout in case the app doesn't do it for us.
2184 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2185 msg.obj = next;
2186 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2187
2188 if (false) {
2189 // The activity was never told to pause, so just keep
2190 // things going as-is. To maintain our own state,
2191 // we need to emulate it coming back and saying it is
2192 // idle.
2193 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2194 msg.obj = next;
2195 mHandler.sendMessage(msg);
2196 }
2197
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002198 reportResumedActivity(next);
2199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200 next.thumbnail = null;
2201 setFocusedActivityLocked(next);
2202 next.resumeKeyDispatchingLocked();
2203 ensureActivitiesVisibleLocked(null, 0);
2204 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002205
2206 // Mark the point when the activity is resuming
2207 // TODO: To be more accurate, the mark should be before the onCreate,
2208 // not after the onResume. But for subsequent starts, onResume is fine.
2209 if (next.app != null) {
2210 synchronized (mProcessStatsThread) {
2211 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2212 }
2213 } else {
2214 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 }
2217
2218 /**
2219 * Make sure that all activities that need to be visible (that is, they
2220 * currently can be seen by the user) actually are.
2221 */
2222 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2223 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2224 if (DEBUG_VISBILITY) Log.v(
2225 TAG, "ensureActivitiesVisible behind " + top
2226 + " configChanges=0x" + Integer.toHexString(configChanges));
2227
2228 // If the top activity is not fullscreen, then we need to
2229 // make sure any activities under it are now visible.
2230 final int count = mHistory.size();
2231 int i = count-1;
2232 while (mHistory.get(i) != top) {
2233 i--;
2234 }
2235 HistoryRecord r;
2236 boolean behindFullscreen = false;
2237 for (; i>=0; i--) {
2238 r = (HistoryRecord)mHistory.get(i);
2239 if (DEBUG_VISBILITY) Log.v(
2240 TAG, "Make visible? " + r + " finishing=" + r.finishing
2241 + " state=" + r.state);
2242 if (r.finishing) {
2243 continue;
2244 }
2245
2246 final boolean doThisProcess = onlyThisProcess == null
2247 || onlyThisProcess.equals(r.processName);
2248
2249 // First: if this is not the current activity being started, make
2250 // sure it matches the current configuration.
2251 if (r != starting && doThisProcess) {
2252 ensureActivityConfigurationLocked(r, 0);
2253 }
2254
2255 if (r.app == null || r.app.thread == null) {
2256 if (onlyThisProcess == null
2257 || onlyThisProcess.equals(r.processName)) {
2258 // This activity needs to be visible, but isn't even
2259 // running... get it started, but don't resume it
2260 // at this point.
2261 if (DEBUG_VISBILITY) Log.v(
2262 TAG, "Start and freeze screen for " + r);
2263 if (r != starting) {
2264 r.startFreezingScreenLocked(r.app, configChanges);
2265 }
2266 if (!r.visible) {
2267 if (DEBUG_VISBILITY) Log.v(
2268 TAG, "Starting and making visible: " + r);
2269 mWindowManager.setAppVisibility(r, true);
2270 }
2271 if (r != starting) {
2272 startSpecificActivityLocked(r, false, false);
2273 }
2274 }
2275
2276 } else if (r.visible) {
2277 // If this activity is already visible, then there is nothing
2278 // else to do here.
2279 if (DEBUG_VISBILITY) Log.v(
2280 TAG, "Skipping: already visible at " + r);
2281 r.stopFreezingScreenLocked(false);
2282
2283 } else if (onlyThisProcess == null) {
2284 // This activity is not currently visible, but is running.
2285 // Tell it to become visible.
2286 r.visible = true;
2287 if (r.state != ActivityState.RESUMED && r != starting) {
2288 // If this activity is paused, tell it
2289 // to now show its window.
2290 if (DEBUG_VISBILITY) Log.v(
2291 TAG, "Making visible and scheduling visibility: " + r);
2292 try {
2293 mWindowManager.setAppVisibility(r, true);
2294 r.app.thread.scheduleWindowVisibility(r, true);
2295 r.stopFreezingScreenLocked(false);
2296 } catch (Exception e) {
2297 // Just skip on any failure; we'll make it
2298 // visible when it next restarts.
2299 Log.w(TAG, "Exception thrown making visibile: "
2300 + r.intent.getComponent(), e);
2301 }
2302 }
2303 }
2304
2305 // Aggregate current change flags.
2306 configChanges |= r.configChangeFlags;
2307
2308 if (r.fullscreen) {
2309 // At this point, nothing else needs to be shown
2310 if (DEBUG_VISBILITY) Log.v(
2311 TAG, "Stopping: fullscreen at " + r);
2312 behindFullscreen = true;
2313 i--;
2314 break;
2315 }
2316 }
2317
2318 // Now for any activities that aren't visible to the user, make
2319 // sure they no longer are keeping the screen frozen.
2320 while (i >= 0) {
2321 r = (HistoryRecord)mHistory.get(i);
2322 if (DEBUG_VISBILITY) Log.v(
2323 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2324 + " state=" + r.state
2325 + " behindFullscreen=" + behindFullscreen);
2326 if (!r.finishing) {
2327 if (behindFullscreen) {
2328 if (r.visible) {
2329 if (DEBUG_VISBILITY) Log.v(
2330 TAG, "Making invisible: " + r);
2331 r.visible = false;
2332 try {
2333 mWindowManager.setAppVisibility(r, false);
2334 if ((r.state == ActivityState.STOPPING
2335 || r.state == ActivityState.STOPPED)
2336 && r.app != null && r.app.thread != null) {
2337 if (DEBUG_VISBILITY) Log.v(
2338 TAG, "Scheduling invisibility: " + r);
2339 r.app.thread.scheduleWindowVisibility(r, false);
2340 }
2341 } catch (Exception e) {
2342 // Just skip on any failure; we'll make it
2343 // visible when it next restarts.
2344 Log.w(TAG, "Exception thrown making hidden: "
2345 + r.intent.getComponent(), e);
2346 }
2347 } else {
2348 if (DEBUG_VISBILITY) Log.v(
2349 TAG, "Already invisible: " + r);
2350 }
2351 } else if (r.fullscreen) {
2352 if (DEBUG_VISBILITY) Log.v(
2353 TAG, "Now behindFullscreen: " + r);
2354 behindFullscreen = true;
2355 }
2356 }
2357 i--;
2358 }
2359 }
2360
2361 /**
2362 * Version of ensureActivitiesVisible that can easily be called anywhere.
2363 */
2364 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2365 int configChanges) {
2366 HistoryRecord r = topRunningActivityLocked(null);
2367 if (r != null) {
2368 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2369 }
2370 }
2371
2372 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2373 if (resumed) {
2374 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2375 } else {
2376 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2377 }
2378 }
2379
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002380 private boolean startHomeActivityLocked() {
2381 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2382 && mTopAction == null) {
2383 // We are running in factory test mode, but unable to find
2384 // the factory test app, so just sit around displaying the
2385 // error message and don't try to start anything.
2386 return false;
2387 }
2388 Intent intent = new Intent(
2389 mTopAction,
2390 mTopData != null ? Uri.parse(mTopData) : null);
2391 intent.setComponent(mTopComponent);
2392 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2393 intent.addCategory(Intent.CATEGORY_HOME);
2394 }
2395 ActivityInfo aInfo =
2396 intent.resolveActivityInfo(mContext.getPackageManager(),
2397 STOCK_PM_FLAGS);
2398 if (aInfo != null) {
2399 intent.setComponent(new ComponentName(
2400 aInfo.applicationInfo.packageName, aInfo.name));
2401 // Don't do this if the home app is currently being
2402 // instrumented.
2403 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2404 aInfo.applicationInfo.uid);
2405 if (app == null || app.instrumentationClass == null) {
2406 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2407 startActivityLocked(null, intent, null, null, 0, aInfo,
2408 null, null, 0, 0, 0, false, false);
2409 }
2410 }
2411
2412
2413 return true;
2414 }
2415
2416 /**
2417 * Starts the "new version setup screen" if appropriate.
2418 */
2419 private void startSetupActivityLocked() {
2420 // Only do this once per boot.
2421 if (mCheckedForSetup) {
2422 return;
2423 }
2424
2425 // We will show this screen if the current one is a different
2426 // version than the last one shown, and we are not running in
2427 // low-level factory test mode.
2428 final ContentResolver resolver = mContext.getContentResolver();
2429 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2430 Settings.Secure.getInt(resolver,
2431 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2432 mCheckedForSetup = true;
2433
2434 // See if we should be showing the platform update setup UI.
2435 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2436 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2437 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2438
2439 // We don't allow third party apps to replace this.
2440 ResolveInfo ri = null;
2441 for (int i=0; ris != null && i<ris.size(); i++) {
2442 if ((ris.get(i).activityInfo.applicationInfo.flags
2443 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2444 ri = ris.get(i);
2445 break;
2446 }
2447 }
2448
2449 if (ri != null) {
2450 String vers = ri.activityInfo.metaData != null
2451 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2452 : null;
2453 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2454 vers = ri.activityInfo.applicationInfo.metaData.getString(
2455 Intent.METADATA_SETUP_VERSION);
2456 }
2457 String lastVers = Settings.Secure.getString(
2458 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2459 if (vers != null && !vers.equals(lastVers)) {
2460 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2461 intent.setComponent(new ComponentName(
2462 ri.activityInfo.packageName, ri.activityInfo.name));
2463 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2464 null, null, 0, 0, 0, false, false);
2465 }
2466 }
2467 }
2468 }
2469
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002470 private void reportResumedActivity(HistoryRecord r) {
2471 //Log.i(TAG, "**** REPORT RESUME: " + r);
2472
2473 final int identHash = System.identityHashCode(r);
2474 updateUsageStats(r, true);
2475
2476 int i = mWatchers.beginBroadcast();
2477 while (i > 0) {
2478 i--;
2479 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2480 if (w != null) {
2481 try {
2482 w.activityResuming(identHash);
2483 } catch (RemoteException e) {
2484 }
2485 }
2486 }
2487 mWatchers.finishBroadcast();
2488 }
2489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002490 /**
2491 * Ensure that the top activity in the stack is resumed.
2492 *
2493 * @param prev The previously resumed activity, for when in the process
2494 * of pausing; can be null to call from elsewhere.
2495 *
2496 * @return Returns true if something is being resumed, or false if
2497 * nothing happened.
2498 */
2499 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2500 // Find the first activity that is not finishing.
2501 HistoryRecord next = topRunningActivityLocked(null);
2502
2503 // Remember how we'll process this pause/resume situation, and ensure
2504 // that the state is reset however we wind up proceeding.
2505 final boolean userLeaving = mUserLeaving;
2506 mUserLeaving = false;
2507
2508 if (next == null) {
2509 // There are no more activities! Let's just start up the
2510 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002511 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002512 }
2513
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002514 next.delayedResume = false;
2515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 // If the top activity is the resumed one, nothing to do.
2517 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2518 // Make sure we have executed any pending transitions, since there
2519 // should be nothing left to do at this point.
2520 mWindowManager.executeAppTransition();
2521 return false;
2522 }
2523
2524 // If we are sleeping, and there is no resumed activity, and the top
2525 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002526 if ((mSleeping || mShuttingDown)
2527 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 // Make sure we have executed any pending transitions, since there
2529 // should be nothing left to do at this point.
2530 mWindowManager.executeAppTransition();
2531 return false;
2532 }
2533
2534 // The activity may be waiting for stop, but that is no longer
2535 // appropriate for it.
2536 mStoppingActivities.remove(next);
2537 mWaitingVisibleActivities.remove(next);
2538
2539 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2540
2541 // If we are currently pausing an activity, then don't do anything
2542 // until that is done.
2543 if (mPausingActivity != null) {
2544 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2545 return false;
2546 }
2547
2548 // We need to start pausing the current activity so the top one
2549 // can be resumed...
2550 if (mResumedActivity != null) {
2551 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2552 startPausingLocked(userLeaving, false);
2553 return true;
2554 }
2555
2556 if (prev != null && prev != next) {
2557 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2558 prev.waitingVisible = true;
2559 mWaitingVisibleActivities.add(prev);
2560 if (DEBUG_SWITCH) Log.v(
2561 TAG, "Resuming top, waiting visible to hide: " + prev);
2562 } else {
2563 // The next activity is already visible, so hide the previous
2564 // activity's windows right now so we can show the new one ASAP.
2565 // We only do this if the previous is finishing, which should mean
2566 // it is on top of the one being resumed so hiding it quickly
2567 // is good. Otherwise, we want to do the normal route of allowing
2568 // the resumed activity to be shown so we can decide if the
2569 // previous should actually be hidden depending on whether the
2570 // new one is found to be full-screen or not.
2571 if (prev.finishing) {
2572 mWindowManager.setAppVisibility(prev, false);
2573 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2574 + prev + ", waitingVisible="
2575 + (prev != null ? prev.waitingVisible : null)
2576 + ", nowVisible=" + next.nowVisible);
2577 } else {
2578 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2579 + prev + ", waitingVisible="
2580 + (prev != null ? prev.waitingVisible : null)
2581 + ", nowVisible=" + next.nowVisible);
2582 }
2583 }
2584 }
2585
2586 // We are starting up the next activity, so tell the window manager
2587 // that the previous one will be hidden soon. This way it can know
2588 // to ignore it when computing the desired screen orientation.
2589 if (prev != null) {
2590 if (prev.finishing) {
2591 if (DEBUG_TRANSITION) Log.v(TAG,
2592 "Prepare close transition: prev=" + prev);
2593 mWindowManager.prepareAppTransition(prev.task == next.task
2594 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2595 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2596 mWindowManager.setAppWillBeHidden(prev);
2597 mWindowManager.setAppVisibility(prev, false);
2598 } else {
2599 if (DEBUG_TRANSITION) Log.v(TAG,
2600 "Prepare open transition: prev=" + prev);
2601 mWindowManager.prepareAppTransition(prev.task == next.task
2602 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2603 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2604 }
2605 if (false) {
2606 mWindowManager.setAppWillBeHidden(prev);
2607 mWindowManager.setAppVisibility(prev, false);
2608 }
2609 } else if (mHistory.size() > 1) {
2610 if (DEBUG_TRANSITION) Log.v(TAG,
2611 "Prepare open transition: no previous");
2612 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2613 }
2614
2615 if (next.app != null && next.app.thread != null) {
2616 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2617
2618 // This activity is now becoming visible.
2619 mWindowManager.setAppVisibility(next, true);
2620
2621 HistoryRecord lastResumedActivity = mResumedActivity;
2622 ActivityState lastState = next.state;
2623
2624 updateCpuStats();
2625
2626 next.state = ActivityState.RESUMED;
2627 mResumedActivity = next;
2628 next.task.touchActiveTime();
2629 updateLRUListLocked(next.app, true);
2630 updateLRUListLocked(next);
2631
2632 // Have the window manager re-evaluate the orientation of
2633 // the screen based on the new activity order.
2634 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002635 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002636 next.mayFreezeScreenLocked(next.app) ? next : null);
2637 if (config != null) {
2638 next.frozenBeforeDestroy = true;
2639 }
2640 if (!updateConfigurationLocked(config, next)) {
2641 // The configuration update wasn't able to keep the existing
2642 // instance of the activity, and instead started a new one.
2643 // We should be all done, but let's just make sure our activity
2644 // is still at the top and schedule another run if something
2645 // weird happened.
2646 HistoryRecord nextNext = topRunningActivityLocked(null);
2647 if (DEBUG_SWITCH) Log.i(TAG,
2648 "Activity config changed during resume: " + next
2649 + ", new next: " + nextNext);
2650 if (nextNext != next) {
2651 // Do over!
2652 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2653 }
2654 mWindowManager.executeAppTransition();
2655 return true;
2656 }
2657
2658 try {
2659 // Deliver all pending results.
2660 ArrayList a = next.results;
2661 if (a != null) {
2662 final int N = a.size();
2663 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002664 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002665 TAG, "Delivering results to " + next
2666 + ": " + a);
2667 next.app.thread.scheduleSendResult(next, a);
2668 }
2669 }
2670
2671 if (next.newIntents != null) {
2672 next.app.thread.scheduleNewIntent(next.newIntents, next);
2673 }
2674
2675 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2676 System.identityHashCode(next),
2677 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678
2679 next.app.thread.scheduleResumeActivity(next,
2680 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 pauseIfSleepingLocked();
2683
2684 } catch (Exception e) {
2685 // Whoops, need to restart this activity!
2686 next.state = lastState;
2687 mResumedActivity = lastResumedActivity;
2688 if (Config.LOGD) Log.d(TAG,
2689 "Restarting because process died: " + next);
2690 if (!next.hasBeenLaunched) {
2691 next.hasBeenLaunched = true;
2692 } else {
2693 if (SHOW_APP_STARTING_ICON) {
2694 mWindowManager.setAppStartingWindow(
2695 next, next.packageName, next.theme,
2696 next.nonLocalizedLabel,
2697 next.labelRes, next.icon, null, true);
2698 }
2699 }
2700 startSpecificActivityLocked(next, true, false);
2701 return true;
2702 }
2703
2704 // From this point on, if something goes wrong there is no way
2705 // to recover the activity.
2706 try {
2707 next.visible = true;
2708 completeResumeLocked(next);
2709 } catch (Exception e) {
2710 // If any exception gets thrown, toss away this
2711 // activity and try the next one.
2712 Log.w(TAG, "Exception thrown during resume of " + next, e);
2713 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2714 "resume-exception");
2715 return true;
2716 }
2717
2718 // Didn't need to use the icicle, and it is now out of date.
2719 next.icicle = null;
2720 next.haveState = false;
2721 next.stopped = false;
2722
2723 } else {
2724 // Whoops, need to restart this activity!
2725 if (!next.hasBeenLaunched) {
2726 next.hasBeenLaunched = true;
2727 } else {
2728 if (SHOW_APP_STARTING_ICON) {
2729 mWindowManager.setAppStartingWindow(
2730 next, next.packageName, next.theme,
2731 next.nonLocalizedLabel,
2732 next.labelRes, next.icon, null, true);
2733 }
2734 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2735 }
2736 startSpecificActivityLocked(next, true, true);
2737 }
2738
2739 return true;
2740 }
2741
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002742 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2743 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002744 final int NH = mHistory.size();
2745
2746 int addPos = -1;
2747
2748 if (!newTask) {
2749 // If starting in an existing task, find where that is...
2750 HistoryRecord next = null;
2751 boolean startIt = true;
2752 for (int i = NH-1; i >= 0; i--) {
2753 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2754 if (p.finishing) {
2755 continue;
2756 }
2757 if (p.task == r.task) {
2758 // Here it is! Now, if this is not yet visible to the
2759 // user, then just add it without starting; it will
2760 // get started when the user navigates back to it.
2761 addPos = i+1;
2762 if (!startIt) {
2763 mHistory.add(addPos, r);
2764 r.inHistory = true;
2765 r.task.numActivities++;
2766 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2767 r.info.screenOrientation, r.fullscreen);
2768 if (VALIDATE_TOKENS) {
2769 mWindowManager.validateAppTokens(mHistory);
2770 }
2771 return;
2772 }
2773 break;
2774 }
2775 if (p.fullscreen) {
2776 startIt = false;
2777 }
2778 next = p;
2779 }
2780 }
2781
2782 // Place a new activity at top of stack, so it is next to interact
2783 // with the user.
2784 if (addPos < 0) {
2785 addPos = mHistory.size();
2786 }
2787
2788 // If we are not placing the new activity frontmost, we do not want
2789 // to deliver the onUserLeaving callback to the actual frontmost
2790 // activity
2791 if (addPos < NH) {
2792 mUserLeaving = false;
2793 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2794 }
2795
2796 // Slot the activity into the history stack and proceed
2797 mHistory.add(addPos, r);
2798 r.inHistory = true;
2799 r.frontOfTask = newTask;
2800 r.task.numActivities++;
2801 if (NH > 0) {
2802 // We want to show the starting preview window if we are
2803 // switching to a new task, or the next activity's process is
2804 // not currently running.
2805 boolean showStartingIcon = newTask;
2806 ProcessRecord proc = r.app;
2807 if (proc == null) {
2808 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2809 }
2810 if (proc == null || proc.thread == null) {
2811 showStartingIcon = true;
2812 }
2813 if (DEBUG_TRANSITION) Log.v(TAG,
2814 "Prepare open transition: starting " + r);
2815 mWindowManager.prepareAppTransition(newTask
2816 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2817 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2818 mWindowManager.addAppToken(
2819 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2820 boolean doShow = true;
2821 if (newTask) {
2822 // Even though this activity is starting fresh, we still need
2823 // to reset it to make sure we apply affinities to move any
2824 // existing activities from other tasks in to it.
2825 // If the caller has requested that the target task be
2826 // reset, then do so.
2827 if ((r.intent.getFlags()
2828 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2829 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002830 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 }
2832 }
2833 if (SHOW_APP_STARTING_ICON && doShow) {
2834 // Figure out if we are transitioning from another activity that is
2835 // "has the same starting icon" as the next one. This allows the
2836 // window manager to keep the previous window it had previously
2837 // created, if it still had one.
2838 HistoryRecord prev = mResumedActivity;
2839 if (prev != null) {
2840 // We don't want to reuse the previous starting preview if:
2841 // (1) The current activity is in a different task.
2842 if (prev.task != r.task) prev = null;
2843 // (2) The current activity is already displayed.
2844 else if (prev.nowVisible) prev = null;
2845 }
2846 mWindowManager.setAppStartingWindow(
2847 r, r.packageName, r.theme, r.nonLocalizedLabel,
2848 r.labelRes, r.icon, prev, showStartingIcon);
2849 }
2850 } else {
2851 // If this is the first activity, don't do any fancy animations,
2852 // because there is nothing for it to animate on top of.
2853 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2854 r.info.screenOrientation, r.fullscreen);
2855 }
2856 if (VALIDATE_TOKENS) {
2857 mWindowManager.validateAppTokens(mHistory);
2858 }
2859
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002860 if (doResume) {
2861 resumeTopActivityLocked(null);
2862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863 }
2864
2865 /**
2866 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002867 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2868 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002869 * an instance of that activity in the stack and, if found, finish all
2870 * activities on top of it and return the instance.
2871 *
2872 * @param newR Description of the new activity being started.
2873 * @return Returns the old activity that should be continue to be used,
2874 * or null if none was found.
2875 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002876 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 HistoryRecord newR, boolean doClear) {
2878 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002879
2880 // First find the requested task.
2881 while (i > 0) {
2882 i--;
2883 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2884 if (r.task.taskId == taskId) {
2885 i++;
2886 break;
2887 }
2888 }
2889
2890 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002891 while (i > 0) {
2892 i--;
2893 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2894 if (r.finishing) {
2895 continue;
2896 }
2897 if (r.task.taskId != taskId) {
2898 return null;
2899 }
2900 if (r.realActivity.equals(newR.realActivity)) {
2901 // Here it is! Now finish everything in front...
2902 HistoryRecord ret = r;
2903 if (doClear) {
2904 while (i < (mHistory.size()-1)) {
2905 i++;
2906 r = (HistoryRecord)mHistory.get(i);
2907 if (r.finishing) {
2908 continue;
2909 }
2910 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2911 null, "clear")) {
2912 i--;
2913 }
2914 }
2915 }
2916
2917 // Finally, if this is a normal launch mode (that is, not
2918 // expecting onNewIntent()), then we will finish the current
2919 // instance of the activity so a new fresh one can be started.
2920 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2921 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002922 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 if (index >= 0) {
2924 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2925 null, "clear");
2926 }
2927 return null;
2928 }
2929 }
2930
2931 return ret;
2932 }
2933 }
2934
2935 return null;
2936 }
2937
2938 /**
2939 * Find the activity in the history stack within the given task. Returns
2940 * the index within the history at which it's found, or < 0 if not found.
2941 */
2942 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2943 int i = mHistory.size();
2944 while (i > 0) {
2945 i--;
2946 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2947 if (candidate.task.taskId != task) {
2948 break;
2949 }
2950 if (candidate.realActivity.equals(r.realActivity)) {
2951 return i;
2952 }
2953 }
2954
2955 return -1;
2956 }
2957
2958 /**
2959 * Reorder the history stack so that the activity at the given index is
2960 * brought to the front.
2961 */
2962 private final HistoryRecord moveActivityToFrontLocked(int where) {
2963 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2964 int top = mHistory.size();
2965 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2966 mHistory.add(top, newTop);
2967 oldTop.frontOfTask = false;
2968 newTop.frontOfTask = true;
2969 return newTop;
2970 }
2971
2972 /**
2973 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2974 * method will be called at the proper time.
2975 */
2976 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2977 boolean sent = false;
2978 if (r.state == ActivityState.RESUMED
2979 && r.app != null && r.app.thread != null) {
2980 try {
2981 ArrayList<Intent> ar = new ArrayList<Intent>();
2982 ar.add(new Intent(intent));
2983 r.app.thread.scheduleNewIntent(ar, r);
2984 sent = true;
2985 } catch (Exception e) {
2986 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2987 }
2988 }
2989 if (!sent) {
2990 r.addNewIntentLocked(new Intent(intent));
2991 }
2992 }
2993
2994 private final void logStartActivity(int tag, HistoryRecord r,
2995 TaskRecord task) {
2996 EventLog.writeEvent(tag,
2997 System.identityHashCode(r), task.taskId,
2998 r.shortComponentName, r.intent.getAction(),
2999 r.intent.getType(), r.intent.getDataString(),
3000 r.intent.getFlags());
3001 }
3002
3003 private final int startActivityLocked(IApplicationThread caller,
3004 Intent intent, String resolvedType,
3005 Uri[] grantedUriPermissions,
3006 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3007 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003008 int callingPid, int callingUid, boolean onlyIfNeeded,
3009 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 Log.i(TAG, "Starting activity: " + intent);
3011
3012 HistoryRecord sourceRecord = null;
3013 HistoryRecord resultRecord = null;
3014 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003015 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003016 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003017 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3018 if (index >= 0) {
3019 sourceRecord = (HistoryRecord)mHistory.get(index);
3020 if (requestCode >= 0 && !sourceRecord.finishing) {
3021 resultRecord = sourceRecord;
3022 }
3023 }
3024 }
3025
3026 int launchFlags = intent.getFlags();
3027
3028 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3029 && sourceRecord != null) {
3030 // Transfer the result target from the source activity to the new
3031 // one being started, including any failures.
3032 if (requestCode >= 0) {
3033 return START_FORWARD_AND_REQUEST_CONFLICT;
3034 }
3035 resultRecord = sourceRecord.resultTo;
3036 resultWho = sourceRecord.resultWho;
3037 requestCode = sourceRecord.requestCode;
3038 sourceRecord.resultTo = null;
3039 if (resultRecord != null) {
3040 resultRecord.removeResultsLocked(
3041 sourceRecord, resultWho, requestCode);
3042 }
3043 }
3044
3045 int err = START_SUCCESS;
3046
3047 if (intent.getComponent() == null) {
3048 // We couldn't find a class that can handle the given Intent.
3049 // That's the end of that!
3050 err = START_INTENT_NOT_RESOLVED;
3051 }
3052
3053 if (err == START_SUCCESS && aInfo == null) {
3054 // We couldn't find the specific class specified in the Intent.
3055 // Also the end of the line.
3056 err = START_CLASS_NOT_FOUND;
3057 }
3058
3059 ProcessRecord callerApp = null;
3060 if (err == START_SUCCESS && caller != null) {
3061 callerApp = getRecordForAppLocked(caller);
3062 if (callerApp != null) {
3063 callingPid = callerApp.pid;
3064 callingUid = callerApp.info.uid;
3065 } else {
3066 Log.w(TAG, "Unable to find app for caller " + caller
3067 + " (pid=" + callingPid + ") when starting: "
3068 + intent.toString());
3069 err = START_PERMISSION_DENIED;
3070 }
3071 }
3072
3073 if (err != START_SUCCESS) {
3074 if (resultRecord != null) {
3075 sendActivityResultLocked(-1,
3076 resultRecord, resultWho, requestCode,
3077 Activity.RESULT_CANCELED, null);
3078 }
3079 return err;
3080 }
3081
3082 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3083 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3084 if (perm != PackageManager.PERMISSION_GRANTED) {
3085 if (resultRecord != null) {
3086 sendActivityResultLocked(-1,
3087 resultRecord, resultWho, requestCode,
3088 Activity.RESULT_CANCELED, null);
3089 }
3090 String msg = "Permission Denial: starting " + intent.toString()
3091 + " from " + callerApp + " (pid=" + callingPid
3092 + ", uid=" + callingUid + ")"
3093 + " requires " + aInfo.permission;
3094 Log.w(TAG, msg);
3095 throw new SecurityException(msg);
3096 }
3097
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003098 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 boolean abort = false;
3100 try {
3101 // The Intent we give to the watcher has the extra data
3102 // stripped off, since it can contain private information.
3103 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003104 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 aInfo.applicationInfo.packageName);
3106 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003107 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003108 }
3109
3110 if (abort) {
3111 if (resultRecord != null) {
3112 sendActivityResultLocked(-1,
3113 resultRecord, resultWho, requestCode,
3114 Activity.RESULT_CANCELED, null);
3115 }
3116 // We pretend to the caller that it was really started, but
3117 // they will just get a cancel result.
3118 return START_SUCCESS;
3119 }
3120 }
3121
3122 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3123 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003124 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003125
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003126 if (mResumedActivity == null
3127 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3128 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3129 PendingActivityLaunch pal = new PendingActivityLaunch();
3130 pal.r = r;
3131 pal.sourceRecord = sourceRecord;
3132 pal.grantedUriPermissions = grantedUriPermissions;
3133 pal.grantedMode = grantedMode;
3134 pal.onlyIfNeeded = onlyIfNeeded;
3135 mPendingActivityLaunches.add(pal);
3136 return START_SWITCHES_CANCELED;
3137 }
3138 }
3139
3140 if (mDidAppSwitch) {
3141 // This is the second allowed switch since we stopped switches,
3142 // so now just generally allow switches. Use case: user presses
3143 // home (switches disabled, switch to home, mDidAppSwitch now true);
3144 // user taps a home icon (coming from home so allowed, we hit here
3145 // and now allow anyone to switch again).
3146 mAppSwitchesAllowedTime = 0;
3147 } else {
3148 mDidAppSwitch = true;
3149 }
3150
3151 doPendingActivityLaunchesLocked(false);
3152
3153 return startActivityUncheckedLocked(r, sourceRecord,
3154 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3155 }
3156
3157 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3158 final int N = mPendingActivityLaunches.size();
3159 if (N <= 0) {
3160 return;
3161 }
3162 for (int i=0; i<N; i++) {
3163 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3164 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3165 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3166 doResume && i == (N-1));
3167 }
3168 mPendingActivityLaunches.clear();
3169 }
3170
3171 private final int startActivityUncheckedLocked(HistoryRecord r,
3172 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3173 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3174 final Intent intent = r.intent;
3175 final int callingUid = r.launchedFromUid;
3176
3177 int launchFlags = intent.getFlags();
3178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 // We'll invoke onUserLeaving before onPause only if the launching
3180 // activity did not explicitly state that this is an automated launch.
3181 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3182 if (DEBUG_USER_LEAVING) Log.v(TAG,
3183 "startActivity() => mUserLeaving=" + mUserLeaving);
3184
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003185 // If the caller has asked not to resume at this point, we make note
3186 // of this in the record so that we can skip it when trying to find
3187 // the top running activity.
3188 if (!doResume) {
3189 r.delayedResume = true;
3190 }
3191
3192 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3193 != 0 ? r : null;
3194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 // If the onlyIfNeeded flag is set, then we can do this if the activity
3196 // being launched is the same as the one making the call... or, as
3197 // a special case, if we do not know the caller then we count the
3198 // current top activity as the caller.
3199 if (onlyIfNeeded) {
3200 HistoryRecord checkedCaller = sourceRecord;
3201 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003202 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 }
3204 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3205 // Caller is not the same as launcher, so always needed.
3206 onlyIfNeeded = false;
3207 }
3208 }
3209
3210 if (grantedUriPermissions != null && callingUid > 0) {
3211 for (int i=0; i<grantedUriPermissions.length; i++) {
3212 grantUriPermissionLocked(callingUid, r.packageName,
3213 grantedUriPermissions[i], grantedMode, r);
3214 }
3215 }
3216
3217 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3218 intent, r);
3219
3220 if (sourceRecord == null) {
3221 // This activity is not being started from another... in this
3222 // case we -always- start a new task.
3223 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3224 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3225 + intent);
3226 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3227 }
3228 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3229 // The original activity who is starting us is running as a single
3230 // instance... this new activity it is starting must go on its
3231 // own task.
3232 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3233 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3234 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3235 // The activity being started is a single instance... it always
3236 // gets launched into its own task.
3237 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3238 }
3239
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003240 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 // For whatever reason this activity is being launched into a new
3242 // task... yet the caller has requested a result back. Well, that
3243 // is pretty messed up, so instead immediately send back a cancel
3244 // and let the new task continue launched as normal without a
3245 // dependency on its originator.
3246 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3247 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003248 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003249 Activity.RESULT_CANCELED, null);
3250 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 }
3252
3253 boolean addingToTask = false;
3254 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3255 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3256 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3257 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3258 // If bring to front is requested, and no result is requested, and
3259 // we can find a task that was started with this same
3260 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003261 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 // See if there is a task to bring to the front. If this is
3263 // a SINGLE_INSTANCE activity, there can be one and only one
3264 // instance of it in the history, and it is always in its own
3265 // unique task, so we do a special search.
3266 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3267 ? findTaskLocked(intent, r.info)
3268 : findActivityLocked(intent, r.info);
3269 if (taskTop != null) {
3270 if (taskTop.task.intent == null) {
3271 // This task was started because of movement of
3272 // the activity based on affinity... now that we
3273 // are actually launching it, we can assign the
3274 // base intent.
3275 taskTop.task.setIntent(intent, r.info);
3276 }
3277 // If the target task is not in the front, then we need
3278 // to bring it to the front... except... well, with
3279 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3280 // to have the same behavior as if a new instance was
3281 // being started, which means not bringing it to the front
3282 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003283 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 if (curTop.task != taskTop.task) {
3285 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3286 boolean callerAtFront = sourceRecord == null
3287 || curTop.task == sourceRecord.task;
3288 if (callerAtFront) {
3289 // We really do want to push this one into the
3290 // user's face, right now.
3291 moveTaskToFrontLocked(taskTop.task);
3292 }
3293 }
3294 // If the caller has requested that the target task be
3295 // reset, then do so.
3296 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3297 taskTop = resetTaskIfNeededLocked(taskTop, r);
3298 }
3299 if (onlyIfNeeded) {
3300 // We don't need to start a new activity, and
3301 // the client said not to do anything if that
3302 // is the case, so this is it! And for paranoia, make
3303 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003304 if (doResume) {
3305 resumeTopActivityLocked(null);
3306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 return START_RETURN_INTENT_TO_CALLER;
3308 }
3309 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3310 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3311 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3312 // In this situation we want to remove all activities
3313 // from the task up to the one being started. In most
3314 // cases this means we are resetting the task to its
3315 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003316 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003317 taskTop.task.taskId, r, true);
3318 if (top != null) {
3319 if (top.frontOfTask) {
3320 // Activity aliases may mean we use different
3321 // intents for the top activity, so make sure
3322 // the task now has the identity of the new
3323 // intent.
3324 top.task.setIntent(r.intent, r.info);
3325 }
3326 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3327 deliverNewIntentLocked(top, r.intent);
3328 } else {
3329 // A special case: we need to
3330 // start the activity because it is not currently
3331 // running, and the caller has asked to clear the
3332 // current task to have this activity at the top.
3333 addingToTask = true;
3334 // Now pretend like this activity is being started
3335 // by the top of its task, so it is put in the
3336 // right place.
3337 sourceRecord = taskTop;
3338 }
3339 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3340 // In this case the top activity on the task is the
3341 // same as the one being launched, so we take that
3342 // as a request to bring the task to the foreground.
3343 // If the top activity in the task is the root
3344 // activity, deliver this new intent to it if it
3345 // desires.
3346 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3347 && taskTop.realActivity.equals(r.realActivity)) {
3348 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3349 if (taskTop.frontOfTask) {
3350 taskTop.task.setIntent(r.intent, r.info);
3351 }
3352 deliverNewIntentLocked(taskTop, r.intent);
3353 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3354 // In this case we are launching the root activity
3355 // of the task, but with a different intent. We
3356 // should start a new instance on top.
3357 addingToTask = true;
3358 sourceRecord = taskTop;
3359 }
3360 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3361 // In this case an activity is being launched in to an
3362 // existing task, without resetting that task. This
3363 // is typically the situation of launching an activity
3364 // from a notification or shortcut. We want to place
3365 // the new activity on top of the current task.
3366 addingToTask = true;
3367 sourceRecord = taskTop;
3368 } else if (!taskTop.task.rootWasReset) {
3369 // In this case we are launching in to an existing task
3370 // that has not yet been started from its front door.
3371 // The current task has been brought to the front.
3372 // Ideally, we'd probably like to place this new task
3373 // at the bottom of its stack, but that's a little hard
3374 // to do with the current organization of the code so
3375 // for now we'll just drop it.
3376 taskTop.task.setIntent(r.intent, r.info);
3377 }
3378 if (!addingToTask) {
3379 // We didn't do anything... but it was needed (a.k.a., client
3380 // don't use that intent!) And for paranoia, make
3381 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003382 if (doResume) {
3383 resumeTopActivityLocked(null);
3384 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 return START_TASK_TO_FRONT;
3386 }
3387 }
3388 }
3389 }
3390
3391 //String uri = r.intent.toURI();
3392 //Intent intent2 = new Intent(uri);
3393 //Log.i(TAG, "Given intent: " + r.intent);
3394 //Log.i(TAG, "URI is: " + uri);
3395 //Log.i(TAG, "To intent: " + intent2);
3396
3397 if (r.packageName != null) {
3398 // If the activity being launched is the same as the one currently
3399 // at the top, then we need to check if it should only be launched
3400 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003401 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3402 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 if (top.realActivity.equals(r.realActivity)) {
3404 if (top.app != null && top.app.thread != null) {
3405 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3406 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3407 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3408 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3409 // For paranoia, make sure we have correctly
3410 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003411 if (doResume) {
3412 resumeTopActivityLocked(null);
3413 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003414 if (onlyIfNeeded) {
3415 // We don't need to start a new activity, and
3416 // the client said not to do anything if that
3417 // is the case, so this is it!
3418 return START_RETURN_INTENT_TO_CALLER;
3419 }
3420 deliverNewIntentLocked(top, r.intent);
3421 return START_DELIVERED_TO_TOP;
3422 }
3423 }
3424 }
3425 }
3426
3427 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003428 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003430 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 Activity.RESULT_CANCELED, null);
3432 }
3433 return START_CLASS_NOT_FOUND;
3434 }
3435
3436 boolean newTask = false;
3437
3438 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003439 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3441 // todo: should do better management of integers.
3442 mCurTask++;
3443 if (mCurTask <= 0) {
3444 mCurTask = 1;
3445 }
3446 r.task = new TaskRecord(mCurTask, r.info, intent,
3447 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3448 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3449 + " in new task " + r.task);
3450 newTask = true;
3451 addRecentTask(r.task);
3452
3453 } else if (sourceRecord != null) {
3454 if (!addingToTask &&
3455 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3456 // In this case, we are adding the activity to an existing
3457 // task, but the caller has asked to clear that task if the
3458 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 sourceRecord.task.taskId, r, true);
3461 if (top != null) {
3462 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3463 deliverNewIntentLocked(top, r.intent);
3464 // For paranoia, make sure we have correctly
3465 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003466 if (doResume) {
3467 resumeTopActivityLocked(null);
3468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 return START_DELIVERED_TO_TOP;
3470 }
3471 } else if (!addingToTask &&
3472 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3473 // In this case, we are launching an activity in our own task
3474 // that may already be running somewhere in the history, and
3475 // we want to shuffle it to the front of the stack if so.
3476 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3477 if (where >= 0) {
3478 HistoryRecord top = moveActivityToFrontLocked(where);
3479 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3480 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003481 if (doResume) {
3482 resumeTopActivityLocked(null);
3483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 return START_DELIVERED_TO_TOP;
3485 }
3486 }
3487 // An existing activity is starting this new activity, so we want
3488 // to keep the new one in the same task as the one that is starting
3489 // it.
3490 r.task = sourceRecord.task;
3491 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3492 + " in existing task " + r.task);
3493
3494 } else {
3495 // This not being started from an existing activity, and not part
3496 // of a new task... just put it in the top task, though these days
3497 // this case should never happen.
3498 final int N = mHistory.size();
3499 HistoryRecord prev =
3500 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3501 r.task = prev != null
3502 ? prev.task
3503 : new TaskRecord(mCurTask, r.info, intent,
3504 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3505 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3506 + " in new guessed " + r.task);
3507 }
3508 if (newTask) {
3509 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3510 }
3511 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003512 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 return START_SUCCESS;
3514 }
3515
3516 public final int startActivity(IApplicationThread caller,
3517 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3518 int grantedMode, IBinder resultTo,
3519 String resultWho, int requestCode, boolean onlyIfNeeded,
3520 boolean debug) {
3521 // Refuse possible leaked file descriptors
3522 if (intent != null && intent.hasFileDescriptors()) {
3523 throw new IllegalArgumentException("File descriptors passed in Intent");
3524 }
3525
The Android Open Source Project4df24232009-03-05 14:34:35 -08003526 final boolean componentSpecified = intent.getComponent() != null;
3527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 // Don't modify the client's object!
3529 intent = new Intent(intent);
3530
3531 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 ActivityInfo aInfo;
3533 try {
3534 ResolveInfo rInfo =
3535 ActivityThread.getPackageManager().resolveIntent(
3536 intent, resolvedType,
3537 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003538 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 aInfo = rInfo != null ? rInfo.activityInfo : null;
3540 } catch (RemoteException e) {
3541 aInfo = null;
3542 }
3543
3544 if (aInfo != null) {
3545 // Store the found target back into the intent, because now that
3546 // we have it we never want to do this again. For example, if the
3547 // user navigates back to this point in the history, we should
3548 // always restart the exact same activity.
3549 intent.setComponent(new ComponentName(
3550 aInfo.applicationInfo.packageName, aInfo.name));
3551
3552 // Don't debug things in the system process
3553 if (debug) {
3554 if (!aInfo.processName.equals("system")) {
3555 setDebugApp(aInfo.processName, true, false);
3556 }
3557 }
3558 }
3559
3560 synchronized(this) {
3561 final long origId = Binder.clearCallingIdentity();
3562 int res = startActivityLocked(caller, intent, resolvedType,
3563 grantedUriPermissions, grantedMode, aInfo,
3564 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003565 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 Binder.restoreCallingIdentity(origId);
3567 return res;
3568 }
3569 }
3570
3571 public boolean startNextMatchingActivity(IBinder callingActivity,
3572 Intent intent) {
3573 // Refuse possible leaked file descriptors
3574 if (intent != null && intent.hasFileDescriptors() == true) {
3575 throw new IllegalArgumentException("File descriptors passed in Intent");
3576 }
3577
3578 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003579 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 if (index < 0) {
3581 return false;
3582 }
3583 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3584 if (r.app == null || r.app.thread == null) {
3585 // The caller is not running... d'oh!
3586 return false;
3587 }
3588 intent = new Intent(intent);
3589 // The caller is not allowed to change the data.
3590 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3591 // And we are resetting to find the next component...
3592 intent.setComponent(null);
3593
3594 ActivityInfo aInfo = null;
3595 try {
3596 List<ResolveInfo> resolves =
3597 ActivityThread.getPackageManager().queryIntentActivities(
3598 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003599 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600
3601 // Look for the original activity in the list...
3602 final int N = resolves != null ? resolves.size() : 0;
3603 for (int i=0; i<N; i++) {
3604 ResolveInfo rInfo = resolves.get(i);
3605 if (rInfo.activityInfo.packageName.equals(r.packageName)
3606 && rInfo.activityInfo.name.equals(r.info.name)) {
3607 // We found the current one... the next matching is
3608 // after it.
3609 i++;
3610 if (i<N) {
3611 aInfo = resolves.get(i).activityInfo;
3612 }
3613 break;
3614 }
3615 }
3616 } catch (RemoteException e) {
3617 }
3618
3619 if (aInfo == null) {
3620 // Nobody who is next!
3621 return false;
3622 }
3623
3624 intent.setComponent(new ComponentName(
3625 aInfo.applicationInfo.packageName, aInfo.name));
3626 intent.setFlags(intent.getFlags()&~(
3627 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3628 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3629 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3630 Intent.FLAG_ACTIVITY_NEW_TASK));
3631
3632 // Okay now we need to start the new activity, replacing the
3633 // currently running activity. This is a little tricky because
3634 // we want to start the new one as if the current one is finished,
3635 // but not finish the current one first so that there is no flicker.
3636 // And thus...
3637 final boolean wasFinishing = r.finishing;
3638 r.finishing = true;
3639
3640 // Propagate reply information over to the new activity.
3641 final HistoryRecord resultTo = r.resultTo;
3642 final String resultWho = r.resultWho;
3643 final int requestCode = r.requestCode;
3644 r.resultTo = null;
3645 if (resultTo != null) {
3646 resultTo.removeResultsLocked(r, resultWho, requestCode);
3647 }
3648
3649 final long origId = Binder.clearCallingIdentity();
3650 // XXX we are not dealing with propagating grantedUriPermissions...
3651 // those are not yet exposed to user code, so there is no need.
3652 int res = startActivityLocked(r.app.thread, intent,
3653 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003654 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003655 Binder.restoreCallingIdentity(origId);
3656
3657 r.finishing = wasFinishing;
3658 if (res != START_SUCCESS) {
3659 return false;
3660 }
3661 return true;
3662 }
3663 }
3664
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003665 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003666 Intent intent, String resolvedType, IBinder resultTo,
3667 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003668
3669 // This is so super not safe, that only the system (or okay root)
3670 // can do it.
3671 final int callingUid = Binder.getCallingUid();
3672 if (callingUid != 0 && callingUid != Process.myUid()) {
3673 throw new SecurityException(
3674 "startActivityInPackage only available to the system");
3675 }
3676
The Android Open Source Project4df24232009-03-05 14:34:35 -08003677 final boolean componentSpecified = intent.getComponent() != null;
3678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003679 // Don't modify the client's object!
3680 intent = new Intent(intent);
3681
3682 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 ActivityInfo aInfo;
3684 try {
3685 ResolveInfo rInfo =
3686 ActivityThread.getPackageManager().resolveIntent(
3687 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003688 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689 aInfo = rInfo != null ? rInfo.activityInfo : null;
3690 } catch (RemoteException e) {
3691 aInfo = null;
3692 }
3693
3694 if (aInfo != null) {
3695 // Store the found target back into the intent, because now that
3696 // we have it we never want to do this again. For example, if the
3697 // user navigates back to this point in the history, we should
3698 // always restart the exact same activity.
3699 intent.setComponent(new ComponentName(
3700 aInfo.applicationInfo.packageName, aInfo.name));
3701 }
3702
3703 synchronized(this) {
3704 return startActivityLocked(null, intent, resolvedType,
3705 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003706 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 }
3708 }
3709
3710 private final void addRecentTask(TaskRecord task) {
3711 // Remove any existing entries that are the same kind of task.
3712 int N = mRecentTasks.size();
3713 for (int i=0; i<N; i++) {
3714 TaskRecord tr = mRecentTasks.get(i);
3715 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3716 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3717 mRecentTasks.remove(i);
3718 i--;
3719 N--;
3720 if (task.intent == null) {
3721 // If the new recent task we are adding is not fully
3722 // specified, then replace it with the existing recent task.
3723 task = tr;
3724 }
3725 }
3726 }
3727 if (N >= MAX_RECENT_TASKS) {
3728 mRecentTasks.remove(N-1);
3729 }
3730 mRecentTasks.add(0, task);
3731 }
3732
3733 public void setRequestedOrientation(IBinder token,
3734 int requestedOrientation) {
3735 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003736 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 if (index < 0) {
3738 return;
3739 }
3740 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3741 final long origId = Binder.clearCallingIdentity();
3742 mWindowManager.setAppOrientation(r, requestedOrientation);
3743 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003744 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003745 r.mayFreezeScreenLocked(r.app) ? r : null);
3746 if (config != null) {
3747 r.frozenBeforeDestroy = true;
3748 if (!updateConfigurationLocked(config, r)) {
3749 resumeTopActivityLocked(null);
3750 }
3751 }
3752 Binder.restoreCallingIdentity(origId);
3753 }
3754 }
3755
3756 public int getRequestedOrientation(IBinder token) {
3757 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003758 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003759 if (index < 0) {
3760 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3761 }
3762 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3763 return mWindowManager.getAppOrientation(r);
3764 }
3765 }
3766
3767 private final void stopActivityLocked(HistoryRecord r) {
3768 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3769 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3770 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3771 if (!r.finishing) {
3772 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3773 "no-history");
3774 }
3775 } else if (r.app != null && r.app.thread != null) {
3776 if (mFocusedActivity == r) {
3777 setFocusedActivityLocked(topRunningActivityLocked(null));
3778 }
3779 r.resumeKeyDispatchingLocked();
3780 try {
3781 r.stopped = false;
3782 r.state = ActivityState.STOPPING;
3783 if (DEBUG_VISBILITY) Log.v(
3784 TAG, "Stopping visible=" + r.visible + " for " + r);
3785 if (!r.visible) {
3786 mWindowManager.setAppVisibility(r, false);
3787 }
3788 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3789 } catch (Exception e) {
3790 // Maybe just ignore exceptions here... if the process
3791 // has crashed, our death notification will clean things
3792 // up.
3793 Log.w(TAG, "Exception thrown during pause", e);
3794 // Just in case, assume it to be stopped.
3795 r.stopped = true;
3796 r.state = ActivityState.STOPPED;
3797 if (r.configDestroy) {
3798 destroyActivityLocked(r, true);
3799 }
3800 }
3801 }
3802 }
3803
3804 /**
3805 * @return Returns true if the activity is being finished, false if for
3806 * some reason it is being left as-is.
3807 */
3808 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3809 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003810 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003811 TAG, "Finishing activity: token=" + token
3812 + ", result=" + resultCode + ", data=" + resultData);
3813
Dianne Hackborn75b03852009-06-12 15:43:26 -07003814 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003815 if (index < 0) {
3816 return false;
3817 }
3818 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3819
3820 // Is this the last activity left?
3821 boolean lastActivity = true;
3822 for (int i=mHistory.size()-1; i>=0; i--) {
3823 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3824 if (!p.finishing && p != r) {
3825 lastActivity = false;
3826 break;
3827 }
3828 }
3829
3830 // If this is the last activity, but it is the home activity, then
3831 // just don't finish it.
3832 if (lastActivity) {
3833 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3834 return false;
3835 }
3836 }
3837
3838 finishActivityLocked(r, index, resultCode, resultData, reason);
3839 return true;
3840 }
3841
3842 /**
3843 * @return Returns true if this activity has been removed from the history
3844 * list, or false if it is still in the list and will be removed later.
3845 */
3846 private final boolean finishActivityLocked(HistoryRecord r, int index,
3847 int resultCode, Intent resultData, String reason) {
3848 if (r.finishing) {
3849 Log.w(TAG, "Duplicate finish request for " + r);
3850 return false;
3851 }
3852
3853 r.finishing = true;
3854 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3855 System.identityHashCode(r),
3856 r.task.taskId, r.shortComponentName, reason);
3857 r.task.numActivities--;
3858 if (r.frontOfTask && index < (mHistory.size()-1)) {
3859 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3860 if (next.task == r.task) {
3861 next.frontOfTask = true;
3862 }
3863 }
3864
3865 r.pauseKeyDispatchingLocked();
3866 if (mFocusedActivity == r) {
3867 setFocusedActivityLocked(topRunningActivityLocked(null));
3868 }
3869
3870 // send the result
3871 HistoryRecord resultTo = r.resultTo;
3872 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003873 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3874 + " who=" + r.resultWho + " req=" + r.requestCode
3875 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 if (r.info.applicationInfo.uid > 0) {
3877 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3878 r.packageName, resultData, r);
3879 }
3880 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3881 resultData);
3882 r.resultTo = null;
3883 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003884 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885
3886 // Make sure this HistoryRecord is not holding on to other resources,
3887 // because clients have remote IPC references to this object so we
3888 // can't assume that will go away and want to avoid circular IPC refs.
3889 r.results = null;
3890 r.pendingResults = null;
3891 r.newIntents = null;
3892 r.icicle = null;
3893
3894 if (mPendingThumbnails.size() > 0) {
3895 // There are clients waiting to receive thumbnails so, in case
3896 // this is an activity that someone is waiting for, add it
3897 // to the pending list so we can correctly update the clients.
3898 mCancelledThumbnails.add(r);
3899 }
3900
3901 if (mResumedActivity == r) {
3902 boolean endTask = index <= 0
3903 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3904 if (DEBUG_TRANSITION) Log.v(TAG,
3905 "Prepare close transition: finishing " + r);
3906 mWindowManager.prepareAppTransition(endTask
3907 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3908 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3909
3910 // Tell window manager to prepare for this one to be removed.
3911 mWindowManager.setAppVisibility(r, false);
3912
3913 if (mPausingActivity == null) {
3914 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3915 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3916 startPausingLocked(false, false);
3917 }
3918
3919 } else if (r.state != ActivityState.PAUSING) {
3920 // If the activity is PAUSING, we will complete the finish once
3921 // it is done pausing; else we can just directly finish it here.
3922 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3923 return finishCurrentActivityLocked(r, index,
3924 FINISH_AFTER_PAUSE) == null;
3925 } else {
3926 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3927 }
3928
3929 return false;
3930 }
3931
3932 private static final int FINISH_IMMEDIATELY = 0;
3933 private static final int FINISH_AFTER_PAUSE = 1;
3934 private static final int FINISH_AFTER_VISIBLE = 2;
3935
3936 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3937 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003938 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003939 if (index < 0) {
3940 return null;
3941 }
3942
3943 return finishCurrentActivityLocked(r, index, mode);
3944 }
3945
3946 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3947 int index, int mode) {
3948 // First things first: if this activity is currently visible,
3949 // and the resumed activity is not yet visible, then hold off on
3950 // finishing until the resumed one becomes visible.
3951 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3952 if (!mStoppingActivities.contains(r)) {
3953 mStoppingActivities.add(r);
3954 if (mStoppingActivities.size() > 3) {
3955 // If we already have a few activities waiting to stop,
3956 // then give up on things going idle and start clearing
3957 // them out.
3958 Message msg = Message.obtain();
3959 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3960 mHandler.sendMessage(msg);
3961 }
3962 }
3963 r.state = ActivityState.STOPPING;
3964 updateOomAdjLocked();
3965 return r;
3966 }
3967
3968 // make sure the record is cleaned out of other places.
3969 mStoppingActivities.remove(r);
3970 mWaitingVisibleActivities.remove(r);
3971 if (mResumedActivity == r) {
3972 mResumedActivity = null;
3973 }
3974 final ActivityState prevState = r.state;
3975 r.state = ActivityState.FINISHING;
3976
3977 if (mode == FINISH_IMMEDIATELY
3978 || prevState == ActivityState.STOPPED
3979 || prevState == ActivityState.INITIALIZING) {
3980 // If this activity is already stopped, we can just finish
3981 // it right now.
3982 return destroyActivityLocked(r, true) ? null : r;
3983 } else {
3984 // Need to go through the full pause cycle to get this
3985 // activity into the stopped state and then finish it.
3986 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3987 mFinishingActivities.add(r);
3988 resumeTopActivityLocked(null);
3989 }
3990 return r;
3991 }
3992
3993 /**
3994 * This is the internal entry point for handling Activity.finish().
3995 *
3996 * @param token The Binder token referencing the Activity we want to finish.
3997 * @param resultCode Result code, if any, from this Activity.
3998 * @param resultData Result data (Intent), if any, from this Activity.
3999 *
4000 * @result Returns true if the activity successfully finished, or false if it is still running.
4001 */
4002 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4003 // Refuse possible leaked file descriptors
4004 if (resultData != null && resultData.hasFileDescriptors() == true) {
4005 throw new IllegalArgumentException("File descriptors passed in Intent");
4006 }
4007
4008 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004009 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004010 // Find the first activity that is not finishing.
4011 HistoryRecord next = topRunningActivityLocked(token, 0);
4012 if (next != null) {
4013 // ask watcher if this is allowed
4014 boolean resumeOK = true;
4015 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004016 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004018 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004019 }
4020
4021 if (!resumeOK) {
4022 return false;
4023 }
4024 }
4025 }
4026 final long origId = Binder.clearCallingIdentity();
4027 boolean res = requestFinishActivityLocked(token, resultCode,
4028 resultData, "app-request");
4029 Binder.restoreCallingIdentity(origId);
4030 return res;
4031 }
4032 }
4033
4034 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4035 String resultWho, int requestCode, int resultCode, Intent data) {
4036
4037 if (callingUid > 0) {
4038 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4039 data, r);
4040 }
4041
The Android Open Source Project10592532009-03-18 17:39:46 -07004042 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4043 + " : who=" + resultWho + " req=" + requestCode
4044 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004045 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4046 try {
4047 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4048 list.add(new ResultInfo(resultWho, requestCode,
4049 resultCode, data));
4050 r.app.thread.scheduleSendResult(r, list);
4051 return;
4052 } catch (Exception e) {
4053 Log.w(TAG, "Exception thrown sending result to " + r, e);
4054 }
4055 }
4056
4057 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4058 }
4059
4060 public final void finishSubActivity(IBinder token, String resultWho,
4061 int requestCode) {
4062 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004063 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004064 if (index < 0) {
4065 return;
4066 }
4067 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4068
4069 final long origId = Binder.clearCallingIdentity();
4070
4071 int i;
4072 for (i=mHistory.size()-1; i>=0; i--) {
4073 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4074 if (r.resultTo == self && r.requestCode == requestCode) {
4075 if ((r.resultWho == null && resultWho == null) ||
4076 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4077 finishActivityLocked(r, i,
4078 Activity.RESULT_CANCELED, null, "request-sub");
4079 }
4080 }
4081 }
4082
4083 Binder.restoreCallingIdentity(origId);
4084 }
4085 }
4086
4087 /**
4088 * Perform clean-up of service connections in an activity record.
4089 */
4090 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4091 // Throw away any services that have been bound by this activity.
4092 if (r.connections != null) {
4093 Iterator<ConnectionRecord> it = r.connections.iterator();
4094 while (it.hasNext()) {
4095 ConnectionRecord c = it.next();
4096 removeConnectionLocked(c, null, r);
4097 }
4098 r.connections = null;
4099 }
4100 }
4101
4102 /**
4103 * Perform the common clean-up of an activity record. This is called both
4104 * as part of destroyActivityLocked() (when destroying the client-side
4105 * representation) and cleaning things up as a result of its hosting
4106 * processing going away, in which case there is no remaining client-side
4107 * state to destroy so only the cleanup here is needed.
4108 */
4109 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4110 if (mResumedActivity == r) {
4111 mResumedActivity = null;
4112 }
4113 if (mFocusedActivity == r) {
4114 mFocusedActivity = null;
4115 }
4116
4117 r.configDestroy = false;
4118 r.frozenBeforeDestroy = false;
4119
4120 // Make sure this record is no longer in the pending finishes list.
4121 // This could happen, for example, if we are trimming activities
4122 // down to the max limit while they are still waiting to finish.
4123 mFinishingActivities.remove(r);
4124 mWaitingVisibleActivities.remove(r);
4125
4126 // Remove any pending results.
4127 if (r.finishing && r.pendingResults != null) {
4128 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4129 PendingIntentRecord rec = apr.get();
4130 if (rec != null) {
4131 cancelIntentSenderLocked(rec, false);
4132 }
4133 }
4134 r.pendingResults = null;
4135 }
4136
4137 if (cleanServices) {
4138 cleanUpActivityServicesLocked(r);
4139 }
4140
4141 if (mPendingThumbnails.size() > 0) {
4142 // There are clients waiting to receive thumbnails so, in case
4143 // this is an activity that someone is waiting for, add it
4144 // to the pending list so we can correctly update the clients.
4145 mCancelledThumbnails.add(r);
4146 }
4147
4148 // Get rid of any pending idle timeouts.
4149 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4150 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4151 }
4152
4153 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4154 if (r.state != ActivityState.DESTROYED) {
4155 mHistory.remove(r);
4156 r.inHistory = false;
4157 r.state = ActivityState.DESTROYED;
4158 mWindowManager.removeAppToken(r);
4159 if (VALIDATE_TOKENS) {
4160 mWindowManager.validateAppTokens(mHistory);
4161 }
4162 cleanUpActivityServicesLocked(r);
4163 removeActivityUriPermissionsLocked(r);
4164 }
4165 }
4166
4167 /**
4168 * Destroy the current CLIENT SIDE instance of an activity. This may be
4169 * called both when actually finishing an activity, or when performing
4170 * a configuration switch where we destroy the current client-side object
4171 * but then create a new client-side object for this same HistoryRecord.
4172 */
4173 private final boolean destroyActivityLocked(HistoryRecord r,
4174 boolean removeFromApp) {
4175 if (DEBUG_SWITCH) Log.v(
4176 TAG, "Removing activity: token=" + r
4177 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4178 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4179 System.identityHashCode(r),
4180 r.task.taskId, r.shortComponentName);
4181
4182 boolean removedFromHistory = false;
4183
4184 cleanUpActivityLocked(r, false);
4185
4186 if (r.app != null) {
4187 if (removeFromApp) {
4188 int idx = r.app.activities.indexOf(r);
4189 if (idx >= 0) {
4190 r.app.activities.remove(idx);
4191 }
4192 if (r.persistent) {
4193 decPersistentCountLocked(r.app);
4194 }
4195 }
4196
4197 boolean skipDestroy = false;
4198
4199 try {
4200 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4201 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4202 r.configChangeFlags);
4203 } catch (Exception e) {
4204 // We can just ignore exceptions here... if the process
4205 // has crashed, our death notification will clean things
4206 // up.
4207 //Log.w(TAG, "Exception thrown during finish", e);
4208 if (r.finishing) {
4209 removeActivityFromHistoryLocked(r);
4210 removedFromHistory = true;
4211 skipDestroy = true;
4212 }
4213 }
4214
4215 r.app = null;
4216 r.nowVisible = false;
4217
4218 if (r.finishing && !skipDestroy) {
4219 r.state = ActivityState.DESTROYING;
4220 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4221 msg.obj = r;
4222 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4223 } else {
4224 r.state = ActivityState.DESTROYED;
4225 }
4226 } else {
4227 // remove this record from the history.
4228 if (r.finishing) {
4229 removeActivityFromHistoryLocked(r);
4230 removedFromHistory = true;
4231 } else {
4232 r.state = ActivityState.DESTROYED;
4233 }
4234 }
4235
4236 r.configChangeFlags = 0;
4237
4238 if (!mLRUActivities.remove(r)) {
4239 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4240 }
4241
4242 return removedFromHistory;
4243 }
4244
4245 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4246 ProcessRecord app)
4247 {
4248 int i = list.size();
4249 if (localLOGV) Log.v(
4250 TAG, "Removing app " + app + " from list " + list
4251 + " with " + i + " entries");
4252 while (i > 0) {
4253 i--;
4254 HistoryRecord r = (HistoryRecord)list.get(i);
4255 if (localLOGV) Log.v(
4256 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4257 if (r.app == app) {
4258 if (localLOGV) Log.v(TAG, "Removing this entry!");
4259 list.remove(i);
4260 }
4261 }
4262 }
4263
4264 /**
4265 * Main function for removing an existing process from the activity manager
4266 * as a result of that process going away. Clears out all connections
4267 * to the process.
4268 */
4269 private final void handleAppDiedLocked(ProcessRecord app,
4270 boolean restarting) {
4271 cleanUpApplicationRecordLocked(app, restarting, -1);
4272 if (!restarting) {
4273 mLRUProcesses.remove(app);
4274 }
4275
4276 // Just in case...
4277 if (mPausingActivity != null && mPausingActivity.app == app) {
4278 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4279 mPausingActivity = null;
4280 }
4281 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4282 mLastPausedActivity = null;
4283 }
4284
4285 // Remove this application's activities from active lists.
4286 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4287 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4288 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4289 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4290
4291 boolean atTop = true;
4292 boolean hasVisibleActivities = false;
4293
4294 // Clean out the history list.
4295 int i = mHistory.size();
4296 if (localLOGV) Log.v(
4297 TAG, "Removing app " + app + " from history with " + i + " entries");
4298 while (i > 0) {
4299 i--;
4300 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4301 if (localLOGV) Log.v(
4302 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4303 if (r.app == app) {
4304 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4305 if (localLOGV) Log.v(
4306 TAG, "Removing this entry! frozen=" + r.haveState
4307 + " finishing=" + r.finishing);
4308 mHistory.remove(i);
4309
4310 r.inHistory = false;
4311 mWindowManager.removeAppToken(r);
4312 if (VALIDATE_TOKENS) {
4313 mWindowManager.validateAppTokens(mHistory);
4314 }
4315 removeActivityUriPermissionsLocked(r);
4316
4317 } else {
4318 // We have the current state for this activity, so
4319 // it can be restarted later when needed.
4320 if (localLOGV) Log.v(
4321 TAG, "Keeping entry, setting app to null");
4322 if (r.visible) {
4323 hasVisibleActivities = true;
4324 }
4325 r.app = null;
4326 r.nowVisible = false;
4327 if (!r.haveState) {
4328 r.icicle = null;
4329 }
4330 }
4331
4332 cleanUpActivityLocked(r, true);
4333 r.state = ActivityState.STOPPED;
4334 }
4335 atTop = false;
4336 }
4337
4338 app.activities.clear();
4339
4340 if (app.instrumentationClass != null) {
4341 Log.w(TAG, "Crash of app " + app.processName
4342 + " running instrumentation " + app.instrumentationClass);
4343 Bundle info = new Bundle();
4344 info.putString("shortMsg", "Process crashed.");
4345 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4346 }
4347
4348 if (!restarting) {
4349 if (!resumeTopActivityLocked(null)) {
4350 // If there was nothing to resume, and we are not already
4351 // restarting this process, but there is a visible activity that
4352 // is hosted by the process... then make sure all visible
4353 // activities are running, taking care of restarting this
4354 // process.
4355 if (hasVisibleActivities) {
4356 ensureActivitiesVisibleLocked(null, 0);
4357 }
4358 }
4359 }
4360 }
4361
4362 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4363 IBinder threadBinder = thread.asBinder();
4364
4365 // Find the application record.
4366 int count = mLRUProcesses.size();
4367 int i;
4368 for (i=0; i<count; i++) {
4369 ProcessRecord rec = mLRUProcesses.get(i);
4370 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4371 return i;
4372 }
4373 }
4374 return -1;
4375 }
4376
4377 private final ProcessRecord getRecordForAppLocked(
4378 IApplicationThread thread) {
4379 if (thread == null) {
4380 return null;
4381 }
4382
4383 int appIndex = getLRURecordIndexForAppLocked(thread);
4384 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4385 }
4386
4387 private final void appDiedLocked(ProcessRecord app, int pid,
4388 IApplicationThread thread) {
4389
4390 mProcDeaths[0]++;
4391
4392 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4393 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4394 + ") has died.");
4395 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4396 if (localLOGV) Log.v(
4397 TAG, "Dying app: " + app + ", pid: " + pid
4398 + ", thread: " + thread.asBinder());
4399 boolean doLowMem = app.instrumentationClass == null;
4400 handleAppDiedLocked(app, false);
4401
4402 if (doLowMem) {
4403 // If there are no longer any background processes running,
4404 // and the app that died was not running instrumentation,
4405 // then tell everyone we are now low on memory.
4406 boolean haveBg = false;
4407 int count = mLRUProcesses.size();
4408 int i;
4409 for (i=0; i<count; i++) {
4410 ProcessRecord rec = mLRUProcesses.get(i);
4411 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4412 haveBg = true;
4413 break;
4414 }
4415 }
4416
4417 if (!haveBg) {
4418 Log.i(TAG, "Low Memory: No more background processes.");
4419 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4420 for (i=0; i<count; i++) {
4421 ProcessRecord rec = mLRUProcesses.get(i);
4422 if (rec.thread != null) {
4423 rec.lastRequestedGc = SystemClock.uptimeMillis();
4424 try {
4425 rec.thread.scheduleLowMemory();
4426 } catch (RemoteException e) {
4427 // Don't care if the process is gone.
4428 }
4429 }
4430 }
4431 }
4432 }
4433 } else if (Config.LOGD) {
4434 Log.d(TAG, "Received spurious death notification for thread "
4435 + thread.asBinder());
4436 }
4437 }
4438
4439 final String readFile(String filename) {
4440 try {
4441 FileInputStream fs = new FileInputStream(filename);
4442 byte[] inp = new byte[8192];
4443 int size = fs.read(inp);
4444 fs.close();
4445 return new String(inp, 0, 0, size);
4446 } catch (java.io.IOException e) {
4447 }
4448 return "";
4449 }
4450
4451 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4452 final String annotation) {
4453 if (app.notResponding || app.crashing) {
4454 return;
4455 }
4456
4457 // Log the ANR to the event log.
4458 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4459
4460 // If we are on a secure build and the application is not interesting to the user (it is
4461 // not visible or in the background), just kill it instead of displaying a dialog.
4462 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4463 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4464 Process.killProcess(app.pid);
4465 return;
4466 }
4467
4468 // DeviceMonitor.start();
4469
4470 String processInfo = null;
4471 if (MONITOR_CPU_USAGE) {
4472 updateCpuStatsNow();
4473 synchronized (mProcessStatsThread) {
4474 processInfo = mProcessStats.printCurrentState();
4475 }
4476 }
4477
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004478 StringBuilder info = mStringBuilder;
4479 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 info.append("ANR (application not responding) in process: ");
4481 info.append(app.processName);
4482 if (annotation != null) {
4483 info.append("\nAnnotation: ");
4484 info.append(annotation);
4485 }
4486 if (MONITOR_CPU_USAGE) {
4487 info.append("\nCPU usage:\n");
4488 info.append(processInfo);
4489 }
4490 Log.i(TAG, info.toString());
4491
4492 // The application is not responding. Dump as many thread traces as we can.
4493 boolean fileDump = prepareTraceFile(true);
4494 if (!fileDump) {
4495 // Dumping traces to the log, just dump the process that isn't responding so
4496 // we don't overflow the log
4497 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4498 } else {
4499 // Dumping traces to a file so dump all active processes we know about
4500 synchronized (this) {
4501 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4502 ProcessRecord r = mLRUProcesses.get(i);
4503 if (r.thread != null) {
4504 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4505 }
4506 }
4507 }
4508 }
4509
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004510 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004511 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004512 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004513 app.pid, info.toString());
4514 if (res != 0) {
4515 if (res < 0) {
4516 // wait until the SIGQUIT has had a chance to process before killing the
4517 // process.
4518 try {
4519 wait(2000);
4520 } catch (InterruptedException e) {
4521 }
4522
4523 Process.killProcess(app.pid);
4524 return;
4525 }
4526 }
4527 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004528 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004529 }
4530 }
4531
4532 makeAppNotRespondingLocked(app,
4533 activity != null ? activity.shortComponentName : null,
4534 annotation != null ? "ANR " + annotation : "ANR",
4535 info.toString(), null);
4536 Message msg = Message.obtain();
4537 HashMap map = new HashMap();
4538 msg.what = SHOW_NOT_RESPONDING_MSG;
4539 msg.obj = map;
4540 map.put("app", app);
4541 if (activity != null) {
4542 map.put("activity", activity);
4543 }
4544
4545 mHandler.sendMessage(msg);
4546 return;
4547 }
4548
4549 /**
4550 * If a stack trace file has been configured, prepare the filesystem
4551 * by creating the directory if it doesn't exist and optionally
4552 * removing the old trace file.
4553 *
4554 * @param removeExisting If set, the existing trace file will be removed.
4555 * @return Returns true if the trace file preparations succeeded
4556 */
4557 public static boolean prepareTraceFile(boolean removeExisting) {
4558 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4559 boolean fileReady = false;
4560 if (!TextUtils.isEmpty(tracesPath)) {
4561 File f = new File(tracesPath);
4562 if (!f.exists()) {
4563 // Ensure the enclosing directory exists
4564 File dir = f.getParentFile();
4565 if (!dir.exists()) {
4566 fileReady = dir.mkdirs();
4567 FileUtils.setPermissions(dir.getAbsolutePath(),
4568 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4569 } else if (dir.isDirectory()) {
4570 fileReady = true;
4571 }
4572 } else if (removeExisting) {
4573 // Remove the previous traces file, so we don't fill the disk.
4574 // The VM will recreate it
4575 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4576 fileReady = f.delete();
4577 }
4578 }
4579
4580 return fileReady;
4581 }
4582
4583
4584 private final void decPersistentCountLocked(ProcessRecord app)
4585 {
4586 app.persistentActivities--;
4587 if (app.persistentActivities > 0) {
4588 // Still more of 'em...
4589 return;
4590 }
4591 if (app.persistent) {
4592 // Ah, but the application itself is persistent. Whatever!
4593 return;
4594 }
4595
4596 // App is no longer persistent... make sure it and the ones
4597 // following it in the LRU list have the correc oom_adj.
4598 updateOomAdjLocked();
4599 }
4600
4601 public void setPersistent(IBinder token, boolean isPersistent) {
4602 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4603 != PackageManager.PERMISSION_GRANTED) {
4604 String msg = "Permission Denial: setPersistent() from pid="
4605 + Binder.getCallingPid()
4606 + ", uid=" + Binder.getCallingUid()
4607 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4608 Log.w(TAG, msg);
4609 throw new SecurityException(msg);
4610 }
4611
4612 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004613 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004614 if (index < 0) {
4615 return;
4616 }
4617 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4618 ProcessRecord app = r.app;
4619
4620 if (localLOGV) Log.v(
4621 TAG, "Setting persistence " + isPersistent + ": " + r);
4622
4623 if (isPersistent) {
4624 if (r.persistent) {
4625 // Okay okay, I heard you already!
4626 if (localLOGV) Log.v(TAG, "Already persistent!");
4627 return;
4628 }
4629 r.persistent = true;
4630 app.persistentActivities++;
4631 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4632 if (app.persistentActivities > 1) {
4633 // We aren't the first...
4634 if (localLOGV) Log.v(TAG, "Not the first!");
4635 return;
4636 }
4637 if (app.persistent) {
4638 // This would be redundant.
4639 if (localLOGV) Log.v(TAG, "App is persistent!");
4640 return;
4641 }
4642
4643 // App is now persistent... make sure it and the ones
4644 // following it now have the correct oom_adj.
4645 final long origId = Binder.clearCallingIdentity();
4646 updateOomAdjLocked();
4647 Binder.restoreCallingIdentity(origId);
4648
4649 } else {
4650 if (!r.persistent) {
4651 // Okay okay, I heard you already!
4652 return;
4653 }
4654 r.persistent = false;
4655 final long origId = Binder.clearCallingIdentity();
4656 decPersistentCountLocked(app);
4657 Binder.restoreCallingIdentity(origId);
4658
4659 }
4660 }
4661 }
4662
4663 public boolean clearApplicationUserData(final String packageName,
4664 final IPackageDataObserver observer) {
4665 int uid = Binder.getCallingUid();
4666 int pid = Binder.getCallingPid();
4667 long callingId = Binder.clearCallingIdentity();
4668 try {
4669 IPackageManager pm = ActivityThread.getPackageManager();
4670 int pkgUid = -1;
4671 synchronized(this) {
4672 try {
4673 pkgUid = pm.getPackageUid(packageName);
4674 } catch (RemoteException e) {
4675 }
4676 if (pkgUid == -1) {
4677 Log.w(TAG, "Invalid packageName:" + packageName);
4678 return false;
4679 }
4680 if (uid == pkgUid || checkComponentPermission(
4681 android.Manifest.permission.CLEAR_APP_USER_DATA,
4682 pid, uid, -1)
4683 == PackageManager.PERMISSION_GRANTED) {
4684 restartPackageLocked(packageName, pkgUid);
4685 } else {
4686 throw new SecurityException(pid+" does not have permission:"+
4687 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4688 "for process:"+packageName);
4689 }
4690 }
4691
4692 try {
4693 //clear application user data
4694 pm.clearApplicationUserData(packageName, observer);
4695 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4696 Uri.fromParts("package", packageName, null));
4697 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4698 broadcastIntentLocked(null, null, intent,
4699 null, null, 0, null, null, null,
4700 false, false, MY_PID, Process.SYSTEM_UID);
4701 } catch (RemoteException e) {
4702 }
4703 } finally {
4704 Binder.restoreCallingIdentity(callingId);
4705 }
4706 return true;
4707 }
4708
4709 public void restartPackage(final String packageName) {
4710 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4711 != PackageManager.PERMISSION_GRANTED) {
4712 String msg = "Permission Denial: restartPackage() from pid="
4713 + Binder.getCallingPid()
4714 + ", uid=" + Binder.getCallingUid()
4715 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4716 Log.w(TAG, msg);
4717 throw new SecurityException(msg);
4718 }
4719
4720 long callingId = Binder.clearCallingIdentity();
4721 try {
4722 IPackageManager pm = ActivityThread.getPackageManager();
4723 int pkgUid = -1;
4724 synchronized(this) {
4725 try {
4726 pkgUid = pm.getPackageUid(packageName);
4727 } catch (RemoteException e) {
4728 }
4729 if (pkgUid == -1) {
4730 Log.w(TAG, "Invalid packageName: " + packageName);
4731 return;
4732 }
4733 restartPackageLocked(packageName, pkgUid);
4734 }
4735 } finally {
4736 Binder.restoreCallingIdentity(callingId);
4737 }
4738 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004739
4740 /*
4741 * The pkg name and uid have to be specified.
4742 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4743 */
4744 public void killApplicationWithUid(String pkg, int uid) {
4745 if (pkg == null) {
4746 return;
4747 }
4748 // Make sure the uid is valid.
4749 if (uid < 0) {
4750 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4751 return;
4752 }
4753 int callerUid = Binder.getCallingUid();
4754 // Only the system server can kill an application
4755 if (callerUid == Process.SYSTEM_UID) {
4756 uninstallPackageLocked(pkg, uid, false);
4757 } else {
4758 throw new SecurityException(callerUid + " cannot kill pkg: " +
4759 pkg);
4760 }
4761 }
4762
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004763 public void closeSystemDialogs(String reason) {
4764 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4765 if (reason != null) {
4766 intent.putExtra("reason", reason);
4767 }
4768
4769 final int uid = Binder.getCallingUid();
4770 final long origId = Binder.clearCallingIdentity();
4771 synchronized (this) {
4772 int i = mWatchers.beginBroadcast();
4773 while (i > 0) {
4774 i--;
4775 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4776 if (w != null) {
4777 try {
4778 w.closingSystemDialogs(reason);
4779 } catch (RemoteException e) {
4780 }
4781 }
4782 }
4783 mWatchers.finishBroadcast();
4784
4785 broadcastIntentLocked(null, null, intent, null,
4786 null, 0, null, null, null, false, false, -1, uid);
4787 }
4788 Binder.restoreCallingIdentity(origId);
4789 }
4790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004791 private void restartPackageLocked(final String packageName, int uid) {
4792 uninstallPackageLocked(packageName, uid, false);
4793 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4794 Uri.fromParts("package", packageName, null));
4795 intent.putExtra(Intent.EXTRA_UID, uid);
4796 broadcastIntentLocked(null, null, intent,
4797 null, null, 0, null, null, null,
4798 false, false, MY_PID, Process.SYSTEM_UID);
4799 }
4800
4801 private final void uninstallPackageLocked(String name, int uid,
4802 boolean callerWillRestart) {
4803 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4804
4805 int i, N;
4806
4807 final String procNamePrefix = name + ":";
4808 if (uid < 0) {
4809 try {
4810 uid = ActivityThread.getPackageManager().getPackageUid(name);
4811 } catch (RemoteException e) {
4812 }
4813 }
4814
4815 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4816 while (badApps.hasNext()) {
4817 SparseArray<Long> ba = badApps.next();
4818 if (ba.get(uid) != null) {
4819 badApps.remove();
4820 }
4821 }
4822
4823 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4824
4825 // Remove all processes this package may have touched: all with the
4826 // same UID (except for the system or root user), and all whose name
4827 // matches the package name.
4828 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4829 final int NA = apps.size();
4830 for (int ia=0; ia<NA; ia++) {
4831 ProcessRecord app = apps.valueAt(ia);
4832 if (app.removed) {
4833 procs.add(app);
4834 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4835 || app.processName.equals(name)
4836 || app.processName.startsWith(procNamePrefix)) {
4837 app.removed = true;
4838 procs.add(app);
4839 }
4840 }
4841 }
4842
4843 N = procs.size();
4844 for (i=0; i<N; i++) {
4845 removeProcessLocked(procs.get(i), callerWillRestart);
4846 }
4847
4848 for (i=mHistory.size()-1; i>=0; i--) {
4849 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4850 if (r.packageName.equals(name)) {
4851 if (Config.LOGD) Log.d(
4852 TAG, " Force finishing activity "
4853 + r.intent.getComponent().flattenToShortString());
4854 if (r.app != null) {
4855 r.app.removed = true;
4856 }
4857 r.app = null;
4858 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4859 }
4860 }
4861
4862 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4863 for (ServiceRecord service : mServices.values()) {
4864 if (service.packageName.equals(name)) {
4865 if (service.app != null) {
4866 service.app.removed = true;
4867 }
4868 service.app = null;
4869 services.add(service);
4870 }
4871 }
4872
4873 N = services.size();
4874 for (i=0; i<N; i++) {
4875 bringDownServiceLocked(services.get(i), true);
4876 }
4877
4878 resumeTopActivityLocked(null);
4879 }
4880
4881 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4882 final String name = app.processName;
4883 final int uid = app.info.uid;
4884 if (Config.LOGD) Log.d(
4885 TAG, "Force removing process " + app + " (" + name
4886 + "/" + uid + ")");
4887
4888 mProcessNames.remove(name, uid);
4889 boolean needRestart = false;
4890 if (app.pid > 0 && app.pid != MY_PID) {
4891 int pid = app.pid;
4892 synchronized (mPidsSelfLocked) {
4893 mPidsSelfLocked.remove(pid);
4894 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4895 }
4896 handleAppDiedLocked(app, true);
4897 mLRUProcesses.remove(app);
4898 Process.killProcess(pid);
4899
4900 if (app.persistent) {
4901 if (!callerWillRestart) {
4902 addAppLocked(app.info);
4903 } else {
4904 needRestart = true;
4905 }
4906 }
4907 } else {
4908 mRemovedProcesses.add(app);
4909 }
4910
4911 return needRestart;
4912 }
4913
4914 private final void processStartTimedOutLocked(ProcessRecord app) {
4915 final int pid = app.pid;
4916 boolean gone = false;
4917 synchronized (mPidsSelfLocked) {
4918 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4919 if (knownApp != null && knownApp.thread == null) {
4920 mPidsSelfLocked.remove(pid);
4921 gone = true;
4922 }
4923 }
4924
4925 if (gone) {
4926 Log.w(TAG, "Process " + app + " failed to attach");
4927 mProcessNames.remove(app.processName, app.info.uid);
4928 Process.killProcess(pid);
4929 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4930 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4931 mPendingBroadcast = null;
4932 scheduleBroadcastsLocked();
4933 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004934 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4935 Log.w(TAG, "Unattached app died before backup, skipping");
4936 try {
4937 IBackupManager bm = IBackupManager.Stub.asInterface(
4938 ServiceManager.getService(Context.BACKUP_SERVICE));
4939 bm.agentDisconnected(app.info.packageName);
4940 } catch (RemoteException e) {
4941 // Can't happen; the backup manager is local
4942 }
4943 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004944 } else {
4945 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4946 }
4947 }
4948
4949 private final boolean attachApplicationLocked(IApplicationThread thread,
4950 int pid) {
4951
4952 // Find the application record that is being attached... either via
4953 // the pid if we are running in multiple processes, or just pull the
4954 // next app record if we are emulating process with anonymous threads.
4955 ProcessRecord app;
4956 if (pid != MY_PID && pid >= 0) {
4957 synchronized (mPidsSelfLocked) {
4958 app = mPidsSelfLocked.get(pid);
4959 }
4960 } else if (mStartingProcesses.size() > 0) {
4961 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004962 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004963 } else {
4964 app = null;
4965 }
4966
4967 if (app == null) {
4968 Log.w(TAG, "No pending application record for pid " + pid
4969 + " (IApplicationThread " + thread + "); dropping process");
4970 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4971 if (pid > 0 && pid != MY_PID) {
4972 Process.killProcess(pid);
4973 } else {
4974 try {
4975 thread.scheduleExit();
4976 } catch (Exception e) {
4977 // Ignore exceptions.
4978 }
4979 }
4980 return false;
4981 }
4982
4983 // If this application record is still attached to a previous
4984 // process, clean it up now.
4985 if (app.thread != null) {
4986 handleAppDiedLocked(app, true);
4987 }
4988
4989 // Tell the process all about itself.
4990
4991 if (localLOGV) Log.v(
4992 TAG, "Binding process pid " + pid + " to record " + app);
4993
4994 String processName = app.processName;
4995 try {
4996 thread.asBinder().linkToDeath(new AppDeathRecipient(
4997 app, pid, thread), 0);
4998 } catch (RemoteException e) {
4999 app.resetPackageList();
5000 startProcessLocked(app, "link fail", processName);
5001 return false;
5002 }
5003
5004 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5005
5006 app.thread = thread;
5007 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005008 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005009 app.forcingToForeground = null;
5010 app.foregroundServices = false;
5011 app.debugging = false;
5012
5013 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5014
5015 List providers = generateApplicationProvidersLocked(app);
5016
5017 if (localLOGV) Log.v(
5018 TAG, "New app record " + app
5019 + " thread=" + thread.asBinder() + " pid=" + pid);
5020 try {
5021 int testMode = IApplicationThread.DEBUG_OFF;
5022 if (mDebugApp != null && mDebugApp.equals(processName)) {
5023 testMode = mWaitForDebugger
5024 ? IApplicationThread.DEBUG_WAIT
5025 : IApplicationThread.DEBUG_ON;
5026 app.debugging = true;
5027 if (mDebugTransient) {
5028 mDebugApp = mOrigDebugApp;
5029 mWaitForDebugger = mOrigWaitForDebugger;
5030 }
5031 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005032 // If the app is being launched for restore or full backup, set it up specially
5033 boolean isRestrictedBackupMode = false;
5034 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5035 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5036 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5037 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005038 ensurePackageDexOpt(app.instrumentationInfo != null
5039 ? app.instrumentationInfo.packageName
5040 : app.info.packageName);
5041 if (app.instrumentationClass != null) {
5042 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005043 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005044 thread.bindApplication(processName, app.instrumentationInfo != null
5045 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005046 app.instrumentationClass, app.instrumentationProfileFile,
5047 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07005048 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005049 updateLRUListLocked(app, false);
5050 app.lastRequestedGc = SystemClock.uptimeMillis();
5051 } catch (Exception e) {
5052 // todo: Yikes! What should we do? For now we will try to
5053 // start another process, but that could easily get us in
5054 // an infinite loop of restarting processes...
5055 Log.w(TAG, "Exception thrown during bind!", e);
5056
5057 app.resetPackageList();
5058 startProcessLocked(app, "bind fail", processName);
5059 return false;
5060 }
5061
5062 // Remove this record from the list of starting applications.
5063 mPersistentStartingProcesses.remove(app);
5064 mProcessesOnHold.remove(app);
5065
5066 boolean badApp = false;
5067 boolean didSomething = false;
5068
5069 // See if the top visible activity is waiting to run in this process...
5070 HistoryRecord hr = topRunningActivityLocked(null);
5071 if (hr != null) {
5072 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5073 && processName.equals(hr.processName)) {
5074 try {
5075 if (realStartActivityLocked(hr, app, true, true)) {
5076 didSomething = true;
5077 }
5078 } catch (Exception e) {
5079 Log.w(TAG, "Exception in new application when starting activity "
5080 + hr.intent.getComponent().flattenToShortString(), e);
5081 badApp = true;
5082 }
5083 } else {
5084 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5085 }
5086 }
5087
5088 // Find any services that should be running in this process...
5089 if (!badApp && mPendingServices.size() > 0) {
5090 ServiceRecord sr = null;
5091 try {
5092 for (int i=0; i<mPendingServices.size(); i++) {
5093 sr = mPendingServices.get(i);
5094 if (app.info.uid != sr.appInfo.uid
5095 || !processName.equals(sr.processName)) {
5096 continue;
5097 }
5098
5099 mPendingServices.remove(i);
5100 i--;
5101 realStartServiceLocked(sr, app);
5102 didSomething = true;
5103 }
5104 } catch (Exception e) {
5105 Log.w(TAG, "Exception in new application when starting service "
5106 + sr.shortName, e);
5107 badApp = true;
5108 }
5109 }
5110
5111 // Check if the next broadcast receiver is in this process...
5112 BroadcastRecord br = mPendingBroadcast;
5113 if (!badApp && br != null && br.curApp == app) {
5114 try {
5115 mPendingBroadcast = null;
5116 processCurBroadcastLocked(br, app);
5117 didSomething = true;
5118 } catch (Exception e) {
5119 Log.w(TAG, "Exception in new application when starting receiver "
5120 + br.curComponent.flattenToShortString(), e);
5121 badApp = true;
5122 logBroadcastReceiverDiscard(br);
5123 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5124 br.resultExtras, br.resultAbort, true);
5125 scheduleBroadcastsLocked();
5126 }
5127 }
5128
Christopher Tate181fafa2009-05-14 11:12:14 -07005129 // Check whether the next backup agent is in this process...
5130 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5131 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005132 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005133 try {
5134 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5135 } catch (Exception e) {
5136 Log.w(TAG, "Exception scheduling backup agent creation: ");
5137 e.printStackTrace();
5138 }
5139 }
5140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005141 if (badApp) {
5142 // todo: Also need to kill application to deal with all
5143 // kinds of exceptions.
5144 handleAppDiedLocked(app, false);
5145 return false;
5146 }
5147
5148 if (!didSomething) {
5149 updateOomAdjLocked();
5150 }
5151
5152 return true;
5153 }
5154
5155 public final void attachApplication(IApplicationThread thread) {
5156 synchronized (this) {
5157 int callingPid = Binder.getCallingPid();
5158 final long origId = Binder.clearCallingIdentity();
5159 attachApplicationLocked(thread, callingPid);
5160 Binder.restoreCallingIdentity(origId);
5161 }
5162 }
5163
5164 public final void activityIdle(IBinder token) {
5165 final long origId = Binder.clearCallingIdentity();
5166 activityIdleInternal(token, false);
5167 Binder.restoreCallingIdentity(origId);
5168 }
5169
5170 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5171 boolean remove) {
5172 int N = mStoppingActivities.size();
5173 if (N <= 0) return null;
5174
5175 ArrayList<HistoryRecord> stops = null;
5176
5177 final boolean nowVisible = mResumedActivity != null
5178 && mResumedActivity.nowVisible
5179 && !mResumedActivity.waitingVisible;
5180 for (int i=0; i<N; i++) {
5181 HistoryRecord s = mStoppingActivities.get(i);
5182 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5183 + nowVisible + " waitingVisible=" + s.waitingVisible
5184 + " finishing=" + s.finishing);
5185 if (s.waitingVisible && nowVisible) {
5186 mWaitingVisibleActivities.remove(s);
5187 s.waitingVisible = false;
5188 if (s.finishing) {
5189 // If this activity is finishing, it is sitting on top of
5190 // everyone else but we now know it is no longer needed...
5191 // so get rid of it. Otherwise, we need to go through the
5192 // normal flow and hide it once we determine that it is
5193 // hidden by the activities in front of it.
5194 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5195 mWindowManager.setAppVisibility(s, false);
5196 }
5197 }
5198 if (!s.waitingVisible && remove) {
5199 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5200 if (stops == null) {
5201 stops = new ArrayList<HistoryRecord>();
5202 }
5203 stops.add(s);
5204 mStoppingActivities.remove(i);
5205 N--;
5206 i--;
5207 }
5208 }
5209
5210 return stops;
5211 }
5212
5213 void enableScreenAfterBoot() {
5214 mWindowManager.enableScreenAfterBoot();
5215 }
5216
5217 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5218 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5219
5220 ArrayList<HistoryRecord> stops = null;
5221 ArrayList<HistoryRecord> finishes = null;
5222 ArrayList<HistoryRecord> thumbnails = null;
5223 int NS = 0;
5224 int NF = 0;
5225 int NT = 0;
5226 IApplicationThread sendThumbnail = null;
5227 boolean booting = false;
5228 boolean enableScreen = false;
5229
5230 synchronized (this) {
5231 if (token != null) {
5232 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5233 }
5234
5235 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005236 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005237 if (index >= 0) {
5238 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5239
5240 // No longer need to keep the device awake.
5241 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5242 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5243 mLaunchingActivity.release();
5244 }
5245
5246 // We are now idle. If someone is waiting for a thumbnail from
5247 // us, we can now deliver.
5248 r.idle = true;
5249 scheduleAppGcsLocked();
5250 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5251 sendThumbnail = r.app.thread;
5252 r.thumbnailNeeded = false;
5253 }
5254
5255 // If this activity is fullscreen, set up to hide those under it.
5256
5257 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5258 ensureActivitiesVisibleLocked(null, 0);
5259
5260 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5261 if (!mBooted && !fromTimeout) {
5262 mBooted = true;
5263 enableScreen = true;
5264 }
5265 }
5266
5267 // Atomically retrieve all of the other things to do.
5268 stops = processStoppingActivitiesLocked(true);
5269 NS = stops != null ? stops.size() : 0;
5270 if ((NF=mFinishingActivities.size()) > 0) {
5271 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5272 mFinishingActivities.clear();
5273 }
5274 if ((NT=mCancelledThumbnails.size()) > 0) {
5275 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5276 mCancelledThumbnails.clear();
5277 }
5278
5279 booting = mBooting;
5280 mBooting = false;
5281 }
5282
5283 int i;
5284
5285 // Send thumbnail if requested.
5286 if (sendThumbnail != null) {
5287 try {
5288 sendThumbnail.requestThumbnail(token);
5289 } catch (Exception e) {
5290 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5291 sendPendingThumbnail(null, token, null, null, true);
5292 }
5293 }
5294
5295 // Stop any activities that are scheduled to do so but have been
5296 // waiting for the next one to start.
5297 for (i=0; i<NS; i++) {
5298 HistoryRecord r = (HistoryRecord)stops.get(i);
5299 synchronized (this) {
5300 if (r.finishing) {
5301 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5302 } else {
5303 stopActivityLocked(r);
5304 }
5305 }
5306 }
5307
5308 // Finish any activities that are scheduled to do so but have been
5309 // waiting for the next one to start.
5310 for (i=0; i<NF; i++) {
5311 HistoryRecord r = (HistoryRecord)finishes.get(i);
5312 synchronized (this) {
5313 destroyActivityLocked(r, true);
5314 }
5315 }
5316
5317 // Report back to any thumbnail receivers.
5318 for (i=0; i<NT; i++) {
5319 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5320 sendPendingThumbnail(r, null, null, null, true);
5321 }
5322
5323 if (booting) {
5324 // Ensure that any processes we had put on hold are now started
5325 // up.
5326 final int NP = mProcessesOnHold.size();
5327 if (NP > 0) {
5328 ArrayList<ProcessRecord> procs =
5329 new ArrayList<ProcessRecord>(mProcessesOnHold);
5330 for (int ip=0; ip<NP; ip++) {
5331 this.startProcessLocked(procs.get(ip), "on-hold", null);
5332 }
5333 }
5334 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5335 // Tell anyone interested that we are done booting!
5336 synchronized (this) {
5337 broadcastIntentLocked(null, null,
5338 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5339 null, null, 0, null, null,
5340 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5341 false, false, MY_PID, Process.SYSTEM_UID);
5342 }
5343 }
5344 }
5345
5346 trimApplications();
5347 //dump();
5348 //mWindowManager.dump();
5349
5350 if (enableScreen) {
5351 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5352 SystemClock.uptimeMillis());
5353 enableScreenAfterBoot();
5354 }
5355 }
5356
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005357 final void ensureScreenEnabled() {
5358 boolean enableScreen;
5359 synchronized (this) {
5360 enableScreen = !mBooted;
5361 mBooted = true;
5362 }
5363
5364 if (enableScreen) {
5365 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5366 SystemClock.uptimeMillis());
5367 enableScreenAfterBoot();
5368 }
5369 }
5370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005371 public final void activityPaused(IBinder token, Bundle icicle) {
5372 // Refuse possible leaked file descriptors
5373 if (icicle != null && icicle.hasFileDescriptors()) {
5374 throw new IllegalArgumentException("File descriptors passed in Bundle");
5375 }
5376
5377 final long origId = Binder.clearCallingIdentity();
5378 activityPaused(token, icicle, false);
5379 Binder.restoreCallingIdentity(origId);
5380 }
5381
5382 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5383 if (DEBUG_PAUSE) Log.v(
5384 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5385 + ", timeout=" + timeout);
5386
5387 HistoryRecord r = null;
5388
5389 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005390 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005391 if (index >= 0) {
5392 r = (HistoryRecord)mHistory.get(index);
5393 if (!timeout) {
5394 r.icicle = icicle;
5395 r.haveState = true;
5396 }
5397 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5398 if (mPausingActivity == r) {
5399 r.state = ActivityState.PAUSED;
5400 completePauseLocked();
5401 } else {
5402 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5403 System.identityHashCode(r), r.shortComponentName,
5404 mPausingActivity != null
5405 ? mPausingActivity.shortComponentName : "(none)");
5406 }
5407 }
5408 }
5409 }
5410
5411 public final void activityStopped(IBinder token, Bitmap thumbnail,
5412 CharSequence description) {
5413 if (localLOGV) Log.v(
5414 TAG, "Activity stopped: token=" + token);
5415
5416 HistoryRecord r = null;
5417
5418 final long origId = Binder.clearCallingIdentity();
5419
5420 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005421 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005422 if (index >= 0) {
5423 r = (HistoryRecord)mHistory.get(index);
5424 r.thumbnail = thumbnail;
5425 r.description = description;
5426 r.stopped = true;
5427 r.state = ActivityState.STOPPED;
5428 if (!r.finishing) {
5429 if (r.configDestroy) {
5430 destroyActivityLocked(r, true);
5431 resumeTopActivityLocked(null);
5432 }
5433 }
5434 }
5435 }
5436
5437 if (r != null) {
5438 sendPendingThumbnail(r, null, null, null, false);
5439 }
5440
5441 trimApplications();
5442
5443 Binder.restoreCallingIdentity(origId);
5444 }
5445
5446 public final void activityDestroyed(IBinder token) {
5447 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5448 synchronized (this) {
5449 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5450
Dianne Hackborn75b03852009-06-12 15:43:26 -07005451 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005452 if (index >= 0) {
5453 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5454 if (r.state == ActivityState.DESTROYING) {
5455 final long origId = Binder.clearCallingIdentity();
5456 removeActivityFromHistoryLocked(r);
5457 Binder.restoreCallingIdentity(origId);
5458 }
5459 }
5460 }
5461 }
5462
5463 public String getCallingPackage(IBinder token) {
5464 synchronized (this) {
5465 HistoryRecord r = getCallingRecordLocked(token);
5466 return r != null && r.app != null ? r.app.processName : null;
5467 }
5468 }
5469
5470 public ComponentName getCallingActivity(IBinder token) {
5471 synchronized (this) {
5472 HistoryRecord r = getCallingRecordLocked(token);
5473 return r != null ? r.intent.getComponent() : null;
5474 }
5475 }
5476
5477 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005478 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005479 if (index >= 0) {
5480 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5481 if (r != null) {
5482 return r.resultTo;
5483 }
5484 }
5485 return null;
5486 }
5487
5488 public ComponentName getActivityClassForToken(IBinder token) {
5489 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005490 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005491 if (index >= 0) {
5492 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5493 return r.intent.getComponent();
5494 }
5495 return null;
5496 }
5497 }
5498
5499 public String getPackageForToken(IBinder token) {
5500 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005501 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005502 if (index >= 0) {
5503 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5504 return r.packageName;
5505 }
5506 return null;
5507 }
5508 }
5509
5510 public IIntentSender getIntentSender(int type,
5511 String packageName, IBinder token, String resultWho,
5512 int requestCode, Intent intent, String resolvedType, int flags) {
5513 // Refuse possible leaked file descriptors
5514 if (intent != null && intent.hasFileDescriptors() == true) {
5515 throw new IllegalArgumentException("File descriptors passed in Intent");
5516 }
5517
5518 synchronized(this) {
5519 int callingUid = Binder.getCallingUid();
5520 try {
5521 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5522 Process.supportsProcesses()) {
5523 int uid = ActivityThread.getPackageManager()
5524 .getPackageUid(packageName);
5525 if (uid != Binder.getCallingUid()) {
5526 String msg = "Permission Denial: getIntentSender() from pid="
5527 + Binder.getCallingPid()
5528 + ", uid=" + Binder.getCallingUid()
5529 + ", (need uid=" + uid + ")"
5530 + " is not allowed to send as package " + packageName;
5531 Log.w(TAG, msg);
5532 throw new SecurityException(msg);
5533 }
5534 }
5535 } catch (RemoteException e) {
5536 throw new SecurityException(e);
5537 }
5538 HistoryRecord activity = null;
5539 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005540 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005541 if (index < 0) {
5542 return null;
5543 }
5544 activity = (HistoryRecord)mHistory.get(index);
5545 if (activity.finishing) {
5546 return null;
5547 }
5548 }
5549
5550 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5551 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5552 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5553 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5554 |PendingIntent.FLAG_UPDATE_CURRENT);
5555
5556 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5557 type, packageName, activity, resultWho,
5558 requestCode, intent, resolvedType, flags);
5559 WeakReference<PendingIntentRecord> ref;
5560 ref = mIntentSenderRecords.get(key);
5561 PendingIntentRecord rec = ref != null ? ref.get() : null;
5562 if (rec != null) {
5563 if (!cancelCurrent) {
5564 if (updateCurrent) {
5565 rec.key.requestIntent.replaceExtras(intent);
5566 }
5567 return rec;
5568 }
5569 rec.canceled = true;
5570 mIntentSenderRecords.remove(key);
5571 }
5572 if (noCreate) {
5573 return rec;
5574 }
5575 rec = new PendingIntentRecord(this, key, callingUid);
5576 mIntentSenderRecords.put(key, rec.ref);
5577 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5578 if (activity.pendingResults == null) {
5579 activity.pendingResults
5580 = new HashSet<WeakReference<PendingIntentRecord>>();
5581 }
5582 activity.pendingResults.add(rec.ref);
5583 }
5584 return rec;
5585 }
5586 }
5587
5588 public void cancelIntentSender(IIntentSender sender) {
5589 if (!(sender instanceof PendingIntentRecord)) {
5590 return;
5591 }
5592 synchronized(this) {
5593 PendingIntentRecord rec = (PendingIntentRecord)sender;
5594 try {
5595 int uid = ActivityThread.getPackageManager()
5596 .getPackageUid(rec.key.packageName);
5597 if (uid != Binder.getCallingUid()) {
5598 String msg = "Permission Denial: cancelIntentSender() from pid="
5599 + Binder.getCallingPid()
5600 + ", uid=" + Binder.getCallingUid()
5601 + " is not allowed to cancel packges "
5602 + rec.key.packageName;
5603 Log.w(TAG, msg);
5604 throw new SecurityException(msg);
5605 }
5606 } catch (RemoteException e) {
5607 throw new SecurityException(e);
5608 }
5609 cancelIntentSenderLocked(rec, true);
5610 }
5611 }
5612
5613 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5614 rec.canceled = true;
5615 mIntentSenderRecords.remove(rec.key);
5616 if (cleanActivity && rec.key.activity != null) {
5617 rec.key.activity.pendingResults.remove(rec.ref);
5618 }
5619 }
5620
5621 public String getPackageForIntentSender(IIntentSender pendingResult) {
5622 if (!(pendingResult instanceof PendingIntentRecord)) {
5623 return null;
5624 }
5625 synchronized(this) {
5626 try {
5627 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5628 return res.key.packageName;
5629 } catch (ClassCastException e) {
5630 }
5631 }
5632 return null;
5633 }
5634
5635 public void setProcessLimit(int max) {
5636 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5637 "setProcessLimit()");
5638 mProcessLimit = max;
5639 }
5640
5641 public int getProcessLimit() {
5642 return mProcessLimit;
5643 }
5644
5645 void foregroundTokenDied(ForegroundToken token) {
5646 synchronized (ActivityManagerService.this) {
5647 synchronized (mPidsSelfLocked) {
5648 ForegroundToken cur
5649 = mForegroundProcesses.get(token.pid);
5650 if (cur != token) {
5651 return;
5652 }
5653 mForegroundProcesses.remove(token.pid);
5654 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5655 if (pr == null) {
5656 return;
5657 }
5658 pr.forcingToForeground = null;
5659 pr.foregroundServices = false;
5660 }
5661 updateOomAdjLocked();
5662 }
5663 }
5664
5665 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5666 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5667 "setProcessForeground()");
5668 synchronized(this) {
5669 boolean changed = false;
5670
5671 synchronized (mPidsSelfLocked) {
5672 ProcessRecord pr = mPidsSelfLocked.get(pid);
5673 if (pr == null) {
5674 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5675 return;
5676 }
5677 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5678 if (oldToken != null) {
5679 oldToken.token.unlinkToDeath(oldToken, 0);
5680 mForegroundProcesses.remove(pid);
5681 pr.forcingToForeground = null;
5682 changed = true;
5683 }
5684 if (isForeground && token != null) {
5685 ForegroundToken newToken = new ForegroundToken() {
5686 public void binderDied() {
5687 foregroundTokenDied(this);
5688 }
5689 };
5690 newToken.pid = pid;
5691 newToken.token = token;
5692 try {
5693 token.linkToDeath(newToken, 0);
5694 mForegroundProcesses.put(pid, newToken);
5695 pr.forcingToForeground = token;
5696 changed = true;
5697 } catch (RemoteException e) {
5698 // If the process died while doing this, we will later
5699 // do the cleanup with the process death link.
5700 }
5701 }
5702 }
5703
5704 if (changed) {
5705 updateOomAdjLocked();
5706 }
5707 }
5708 }
5709
5710 // =========================================================
5711 // PERMISSIONS
5712 // =========================================================
5713
5714 static class PermissionController extends IPermissionController.Stub {
5715 ActivityManagerService mActivityManagerService;
5716 PermissionController(ActivityManagerService activityManagerService) {
5717 mActivityManagerService = activityManagerService;
5718 }
5719
5720 public boolean checkPermission(String permission, int pid, int uid) {
5721 return mActivityManagerService.checkPermission(permission, pid,
5722 uid) == PackageManager.PERMISSION_GRANTED;
5723 }
5724 }
5725
5726 /**
5727 * This can be called with or without the global lock held.
5728 */
5729 int checkComponentPermission(String permission, int pid, int uid,
5730 int reqUid) {
5731 // We might be performing an operation on behalf of an indirect binder
5732 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5733 // client identity accordingly before proceeding.
5734 Identity tlsIdentity = sCallerIdentity.get();
5735 if (tlsIdentity != null) {
5736 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5737 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5738 uid = tlsIdentity.uid;
5739 pid = tlsIdentity.pid;
5740 }
5741
5742 // Root, system server and our own process get to do everything.
5743 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5744 !Process.supportsProcesses()) {
5745 return PackageManager.PERMISSION_GRANTED;
5746 }
5747 // If the target requires a specific UID, always fail for others.
5748 if (reqUid >= 0 && uid != reqUid) {
5749 return PackageManager.PERMISSION_DENIED;
5750 }
5751 if (permission == null) {
5752 return PackageManager.PERMISSION_GRANTED;
5753 }
5754 try {
5755 return ActivityThread.getPackageManager()
5756 .checkUidPermission(permission, uid);
5757 } catch (RemoteException e) {
5758 // Should never happen, but if it does... deny!
5759 Log.e(TAG, "PackageManager is dead?!?", e);
5760 }
5761 return PackageManager.PERMISSION_DENIED;
5762 }
5763
5764 /**
5765 * As the only public entry point for permissions checking, this method
5766 * can enforce the semantic that requesting a check on a null global
5767 * permission is automatically denied. (Internally a null permission
5768 * string is used when calling {@link #checkComponentPermission} in cases
5769 * when only uid-based security is needed.)
5770 *
5771 * This can be called with or without the global lock held.
5772 */
5773 public int checkPermission(String permission, int pid, int uid) {
5774 if (permission == null) {
5775 return PackageManager.PERMISSION_DENIED;
5776 }
5777 return checkComponentPermission(permission, pid, uid, -1);
5778 }
5779
5780 /**
5781 * Binder IPC calls go through the public entry point.
5782 * This can be called with or without the global lock held.
5783 */
5784 int checkCallingPermission(String permission) {
5785 return checkPermission(permission,
5786 Binder.getCallingPid(),
5787 Binder.getCallingUid());
5788 }
5789
5790 /**
5791 * This can be called with or without the global lock held.
5792 */
5793 void enforceCallingPermission(String permission, String func) {
5794 if (checkCallingPermission(permission)
5795 == PackageManager.PERMISSION_GRANTED) {
5796 return;
5797 }
5798
5799 String msg = "Permission Denial: " + func + " from pid="
5800 + Binder.getCallingPid()
5801 + ", uid=" + Binder.getCallingUid()
5802 + " requires " + permission;
5803 Log.w(TAG, msg);
5804 throw new SecurityException(msg);
5805 }
5806
5807 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5808 ProviderInfo pi, int uid, int modeFlags) {
5809 try {
5810 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5811 if ((pi.readPermission != null) &&
5812 (pm.checkUidPermission(pi.readPermission, uid)
5813 != PackageManager.PERMISSION_GRANTED)) {
5814 return false;
5815 }
5816 }
5817 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5818 if ((pi.writePermission != null) &&
5819 (pm.checkUidPermission(pi.writePermission, uid)
5820 != PackageManager.PERMISSION_GRANTED)) {
5821 return false;
5822 }
5823 }
5824 return true;
5825 } catch (RemoteException e) {
5826 return false;
5827 }
5828 }
5829
5830 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5831 int modeFlags) {
5832 // Root gets to do everything.
5833 if (uid == 0 || !Process.supportsProcesses()) {
5834 return true;
5835 }
5836 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5837 if (perms == null) return false;
5838 UriPermission perm = perms.get(uri);
5839 if (perm == null) return false;
5840 return (modeFlags&perm.modeFlags) == modeFlags;
5841 }
5842
5843 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5844 // Another redirected-binder-call permissions check as in
5845 // {@link checkComponentPermission}.
5846 Identity tlsIdentity = sCallerIdentity.get();
5847 if (tlsIdentity != null) {
5848 uid = tlsIdentity.uid;
5849 pid = tlsIdentity.pid;
5850 }
5851
5852 // Our own process gets to do everything.
5853 if (pid == MY_PID) {
5854 return PackageManager.PERMISSION_GRANTED;
5855 }
5856 synchronized(this) {
5857 return checkUriPermissionLocked(uri, uid, modeFlags)
5858 ? PackageManager.PERMISSION_GRANTED
5859 : PackageManager.PERMISSION_DENIED;
5860 }
5861 }
5862
5863 private void grantUriPermissionLocked(int callingUid,
5864 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5865 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5866 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5867 if (modeFlags == 0) {
5868 return;
5869 }
5870
5871 final IPackageManager pm = ActivityThread.getPackageManager();
5872
5873 // If this is not a content: uri, we can't do anything with it.
5874 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5875 return;
5876 }
5877
5878 String name = uri.getAuthority();
5879 ProviderInfo pi = null;
5880 ContentProviderRecord cpr
5881 = (ContentProviderRecord)mProvidersByName.get(name);
5882 if (cpr != null) {
5883 pi = cpr.info;
5884 } else {
5885 try {
5886 pi = pm.resolveContentProvider(name,
5887 PackageManager.GET_URI_PERMISSION_PATTERNS);
5888 } catch (RemoteException ex) {
5889 }
5890 }
5891 if (pi == null) {
5892 Log.w(TAG, "No content provider found for: " + name);
5893 return;
5894 }
5895
5896 int targetUid;
5897 try {
5898 targetUid = pm.getPackageUid(targetPkg);
5899 if (targetUid < 0) {
5900 return;
5901 }
5902 } catch (RemoteException ex) {
5903 return;
5904 }
5905
5906 // First... does the target actually need this permission?
5907 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5908 // No need to grant the target this permission.
5909 return;
5910 }
5911
5912 // Second... maybe someone else has already granted the
5913 // permission?
5914 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5915 // No need to grant the target this permission.
5916 return;
5917 }
5918
5919 // Third... is the provider allowing granting of URI permissions?
5920 if (!pi.grantUriPermissions) {
5921 throw new SecurityException("Provider " + pi.packageName
5922 + "/" + pi.name
5923 + " does not allow granting of Uri permissions (uri "
5924 + uri + ")");
5925 }
5926 if (pi.uriPermissionPatterns != null) {
5927 final int N = pi.uriPermissionPatterns.length;
5928 boolean allowed = false;
5929 for (int i=0; i<N; i++) {
5930 if (pi.uriPermissionPatterns[i] != null
5931 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5932 allowed = true;
5933 break;
5934 }
5935 }
5936 if (!allowed) {
5937 throw new SecurityException("Provider " + pi.packageName
5938 + "/" + pi.name
5939 + " does not allow granting of permission to path of Uri "
5940 + uri);
5941 }
5942 }
5943
5944 // Fourth... does the caller itself have permission to access
5945 // this uri?
5946 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5947 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5948 throw new SecurityException("Uid " + callingUid
5949 + " does not have permission to uri " + uri);
5950 }
5951 }
5952
5953 // Okay! So here we are: the caller has the assumed permission
5954 // to the uri, and the target doesn't. Let's now give this to
5955 // the target.
5956
5957 HashMap<Uri, UriPermission> targetUris
5958 = mGrantedUriPermissions.get(targetUid);
5959 if (targetUris == null) {
5960 targetUris = new HashMap<Uri, UriPermission>();
5961 mGrantedUriPermissions.put(targetUid, targetUris);
5962 }
5963
5964 UriPermission perm = targetUris.get(uri);
5965 if (perm == null) {
5966 perm = new UriPermission(targetUid, uri);
5967 targetUris.put(uri, perm);
5968
5969 }
5970 perm.modeFlags |= modeFlags;
5971 if (activity == null) {
5972 perm.globalModeFlags |= modeFlags;
5973 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5974 perm.readActivities.add(activity);
5975 if (activity.readUriPermissions == null) {
5976 activity.readUriPermissions = new HashSet<UriPermission>();
5977 }
5978 activity.readUriPermissions.add(perm);
5979 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5980 perm.writeActivities.add(activity);
5981 if (activity.writeUriPermissions == null) {
5982 activity.writeUriPermissions = new HashSet<UriPermission>();
5983 }
5984 activity.writeUriPermissions.add(perm);
5985 }
5986 }
5987
5988 private void grantUriPermissionFromIntentLocked(int callingUid,
5989 String targetPkg, Intent intent, HistoryRecord activity) {
5990 if (intent == null) {
5991 return;
5992 }
5993 Uri data = intent.getData();
5994 if (data == null) {
5995 return;
5996 }
5997 grantUriPermissionLocked(callingUid, targetPkg, data,
5998 intent.getFlags(), activity);
5999 }
6000
6001 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6002 Uri uri, int modeFlags) {
6003 synchronized(this) {
6004 final ProcessRecord r = getRecordForAppLocked(caller);
6005 if (r == null) {
6006 throw new SecurityException("Unable to find app for caller "
6007 + caller
6008 + " when granting permission to uri " + uri);
6009 }
6010 if (targetPkg == null) {
6011 Log.w(TAG, "grantUriPermission: null target");
6012 return;
6013 }
6014 if (uri == null) {
6015 Log.w(TAG, "grantUriPermission: null uri");
6016 return;
6017 }
6018
6019 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6020 null);
6021 }
6022 }
6023
6024 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6025 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6026 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6027 HashMap<Uri, UriPermission> perms
6028 = mGrantedUriPermissions.get(perm.uid);
6029 if (perms != null) {
6030 perms.remove(perm.uri);
6031 if (perms.size() == 0) {
6032 mGrantedUriPermissions.remove(perm.uid);
6033 }
6034 }
6035 }
6036 }
6037
6038 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6039 if (activity.readUriPermissions != null) {
6040 for (UriPermission perm : activity.readUriPermissions) {
6041 perm.readActivities.remove(activity);
6042 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6043 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6044 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6045 removeUriPermissionIfNeededLocked(perm);
6046 }
6047 }
6048 }
6049 if (activity.writeUriPermissions != null) {
6050 for (UriPermission perm : activity.writeUriPermissions) {
6051 perm.writeActivities.remove(activity);
6052 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6053 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6054 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6055 removeUriPermissionIfNeededLocked(perm);
6056 }
6057 }
6058 }
6059 }
6060
6061 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6062 int modeFlags) {
6063 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6064 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6065 if (modeFlags == 0) {
6066 return;
6067 }
6068
6069 final IPackageManager pm = ActivityThread.getPackageManager();
6070
6071 final String authority = uri.getAuthority();
6072 ProviderInfo pi = null;
6073 ContentProviderRecord cpr
6074 = (ContentProviderRecord)mProvidersByName.get(authority);
6075 if (cpr != null) {
6076 pi = cpr.info;
6077 } else {
6078 try {
6079 pi = pm.resolveContentProvider(authority,
6080 PackageManager.GET_URI_PERMISSION_PATTERNS);
6081 } catch (RemoteException ex) {
6082 }
6083 }
6084 if (pi == null) {
6085 Log.w(TAG, "No content provider found for: " + authority);
6086 return;
6087 }
6088
6089 // Does the caller have this permission on the URI?
6090 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6091 // Right now, if you are not the original owner of the permission,
6092 // you are not allowed to revoke it.
6093 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6094 throw new SecurityException("Uid " + callingUid
6095 + " does not have permission to uri " + uri);
6096 //}
6097 }
6098
6099 // Go through all of the permissions and remove any that match.
6100 final List<String> SEGMENTS = uri.getPathSegments();
6101 if (SEGMENTS != null) {
6102 final int NS = SEGMENTS.size();
6103 int N = mGrantedUriPermissions.size();
6104 for (int i=0; i<N; i++) {
6105 HashMap<Uri, UriPermission> perms
6106 = mGrantedUriPermissions.valueAt(i);
6107 Iterator<UriPermission> it = perms.values().iterator();
6108 toploop:
6109 while (it.hasNext()) {
6110 UriPermission perm = it.next();
6111 Uri targetUri = perm.uri;
6112 if (!authority.equals(targetUri.getAuthority())) {
6113 continue;
6114 }
6115 List<String> targetSegments = targetUri.getPathSegments();
6116 if (targetSegments == null) {
6117 continue;
6118 }
6119 if (targetSegments.size() < NS) {
6120 continue;
6121 }
6122 for (int j=0; j<NS; j++) {
6123 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6124 continue toploop;
6125 }
6126 }
6127 perm.clearModes(modeFlags);
6128 if (perm.modeFlags == 0) {
6129 it.remove();
6130 }
6131 }
6132 if (perms.size() == 0) {
6133 mGrantedUriPermissions.remove(
6134 mGrantedUriPermissions.keyAt(i));
6135 N--;
6136 i--;
6137 }
6138 }
6139 }
6140 }
6141
6142 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6143 int modeFlags) {
6144 synchronized(this) {
6145 final ProcessRecord r = getRecordForAppLocked(caller);
6146 if (r == null) {
6147 throw new SecurityException("Unable to find app for caller "
6148 + caller
6149 + " when revoking permission to uri " + uri);
6150 }
6151 if (uri == null) {
6152 Log.w(TAG, "revokeUriPermission: null uri");
6153 return;
6154 }
6155
6156 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6157 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6158 if (modeFlags == 0) {
6159 return;
6160 }
6161
6162 final IPackageManager pm = ActivityThread.getPackageManager();
6163
6164 final String authority = uri.getAuthority();
6165 ProviderInfo pi = null;
6166 ContentProviderRecord cpr
6167 = (ContentProviderRecord)mProvidersByName.get(authority);
6168 if (cpr != null) {
6169 pi = cpr.info;
6170 } else {
6171 try {
6172 pi = pm.resolveContentProvider(authority,
6173 PackageManager.GET_URI_PERMISSION_PATTERNS);
6174 } catch (RemoteException ex) {
6175 }
6176 }
6177 if (pi == null) {
6178 Log.w(TAG, "No content provider found for: " + authority);
6179 return;
6180 }
6181
6182 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6183 }
6184 }
6185
6186 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6187 synchronized (this) {
6188 ProcessRecord app =
6189 who != null ? getRecordForAppLocked(who) : null;
6190 if (app == null) return;
6191
6192 Message msg = Message.obtain();
6193 msg.what = WAIT_FOR_DEBUGGER_MSG;
6194 msg.obj = app;
6195 msg.arg1 = waiting ? 1 : 0;
6196 mHandler.sendMessage(msg);
6197 }
6198 }
6199
6200 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6201 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006202 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006203 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006204 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006205 }
6206
6207 // =========================================================
6208 // TASK MANAGEMENT
6209 // =========================================================
6210
6211 public List getTasks(int maxNum, int flags,
6212 IThumbnailReceiver receiver) {
6213 ArrayList list = new ArrayList();
6214
6215 PendingThumbnailsRecord pending = null;
6216 IApplicationThread topThumbnail = null;
6217 HistoryRecord topRecord = null;
6218
6219 synchronized(this) {
6220 if (localLOGV) Log.v(
6221 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6222 + ", receiver=" + receiver);
6223
6224 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6225 != PackageManager.PERMISSION_GRANTED) {
6226 if (receiver != null) {
6227 // If the caller wants to wait for pending thumbnails,
6228 // it ain't gonna get them.
6229 try {
6230 receiver.finished();
6231 } catch (RemoteException ex) {
6232 }
6233 }
6234 String msg = "Permission Denial: getTasks() from pid="
6235 + Binder.getCallingPid()
6236 + ", uid=" + Binder.getCallingUid()
6237 + " requires " + android.Manifest.permission.GET_TASKS;
6238 Log.w(TAG, msg);
6239 throw new SecurityException(msg);
6240 }
6241
6242 int pos = mHistory.size()-1;
6243 HistoryRecord next =
6244 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6245 HistoryRecord top = null;
6246 CharSequence topDescription = null;
6247 TaskRecord curTask = null;
6248 int numActivities = 0;
6249 int numRunning = 0;
6250 while (pos >= 0 && maxNum > 0) {
6251 final HistoryRecord r = next;
6252 pos--;
6253 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6254
6255 // Initialize state for next task if needed.
6256 if (top == null ||
6257 (top.state == ActivityState.INITIALIZING
6258 && top.task == r.task)) {
6259 top = r;
6260 topDescription = r.description;
6261 curTask = r.task;
6262 numActivities = numRunning = 0;
6263 }
6264
6265 // Add 'r' into the current task.
6266 numActivities++;
6267 if (r.app != null && r.app.thread != null) {
6268 numRunning++;
6269 }
6270 if (topDescription == null) {
6271 topDescription = r.description;
6272 }
6273
6274 if (localLOGV) Log.v(
6275 TAG, r.intent.getComponent().flattenToShortString()
6276 + ": task=" + r.task);
6277
6278 // If the next one is a different task, generate a new
6279 // TaskInfo entry for what we have.
6280 if (next == null || next.task != curTask) {
6281 ActivityManager.RunningTaskInfo ci
6282 = new ActivityManager.RunningTaskInfo();
6283 ci.id = curTask.taskId;
6284 ci.baseActivity = r.intent.getComponent();
6285 ci.topActivity = top.intent.getComponent();
6286 ci.thumbnail = top.thumbnail;
6287 ci.description = topDescription;
6288 ci.numActivities = numActivities;
6289 ci.numRunning = numRunning;
6290 //System.out.println(
6291 // "#" + maxNum + ": " + " descr=" + ci.description);
6292 if (ci.thumbnail == null && receiver != null) {
6293 if (localLOGV) Log.v(
6294 TAG, "State=" + top.state + "Idle=" + top.idle
6295 + " app=" + top.app
6296 + " thr=" + (top.app != null ? top.app.thread : null));
6297 if (top.state == ActivityState.RESUMED
6298 || top.state == ActivityState.PAUSING) {
6299 if (top.idle && top.app != null
6300 && top.app.thread != null) {
6301 topRecord = top;
6302 topThumbnail = top.app.thread;
6303 } else {
6304 top.thumbnailNeeded = true;
6305 }
6306 }
6307 if (pending == null) {
6308 pending = new PendingThumbnailsRecord(receiver);
6309 }
6310 pending.pendingRecords.add(top);
6311 }
6312 list.add(ci);
6313 maxNum--;
6314 top = null;
6315 }
6316 }
6317
6318 if (pending != null) {
6319 mPendingThumbnails.add(pending);
6320 }
6321 }
6322
6323 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6324
6325 if (topThumbnail != null) {
6326 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6327 try {
6328 topThumbnail.requestThumbnail(topRecord);
6329 } catch (Exception e) {
6330 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6331 sendPendingThumbnail(null, topRecord, null, null, true);
6332 }
6333 }
6334
6335 if (pending == null && receiver != null) {
6336 // In this case all thumbnails were available and the client
6337 // is being asked to be told when the remaining ones come in...
6338 // which is unusually, since the top-most currently running
6339 // activity should never have a canned thumbnail! Oh well.
6340 try {
6341 receiver.finished();
6342 } catch (RemoteException ex) {
6343 }
6344 }
6345
6346 return list;
6347 }
6348
6349 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6350 int flags) {
6351 synchronized (this) {
6352 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6353 "getRecentTasks()");
6354
6355 final int N = mRecentTasks.size();
6356 ArrayList<ActivityManager.RecentTaskInfo> res
6357 = new ArrayList<ActivityManager.RecentTaskInfo>(
6358 maxNum < N ? maxNum : N);
6359 for (int i=0; i<N && maxNum > 0; i++) {
6360 TaskRecord tr = mRecentTasks.get(i);
6361 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6362 || (tr.intent == null)
6363 || ((tr.intent.getFlags()
6364 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6365 ActivityManager.RecentTaskInfo rti
6366 = new ActivityManager.RecentTaskInfo();
6367 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6368 rti.baseIntent = new Intent(
6369 tr.intent != null ? tr.intent : tr.affinityIntent);
6370 rti.origActivity = tr.origActivity;
6371 res.add(rti);
6372 maxNum--;
6373 }
6374 }
6375 return res;
6376 }
6377 }
6378
6379 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6380 int j;
6381 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6382 TaskRecord jt = startTask;
6383
6384 // First look backwards
6385 for (j=startIndex-1; j>=0; j--) {
6386 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6387 if (r.task != jt) {
6388 jt = r.task;
6389 if (affinity.equals(jt.affinity)) {
6390 return j;
6391 }
6392 }
6393 }
6394
6395 // Now look forwards
6396 final int N = mHistory.size();
6397 jt = startTask;
6398 for (j=startIndex+1; j<N; j++) {
6399 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6400 if (r.task != jt) {
6401 if (affinity.equals(jt.affinity)) {
6402 return j;
6403 }
6404 jt = r.task;
6405 }
6406 }
6407
6408 // Might it be at the top?
6409 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6410 return N-1;
6411 }
6412
6413 return -1;
6414 }
6415
6416 /**
6417 * Perform a reset of the given task, if needed as part of launching it.
6418 * Returns the new HistoryRecord at the top of the task.
6419 */
6420 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6421 HistoryRecord newActivity) {
6422 boolean forceReset = (newActivity.info.flags
6423 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6424 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6425 if ((newActivity.info.flags
6426 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6427 forceReset = true;
6428 }
6429 }
6430
6431 final TaskRecord task = taskTop.task;
6432
6433 // We are going to move through the history list so that we can look
6434 // at each activity 'target' with 'below' either the interesting
6435 // activity immediately below it in the stack or null.
6436 HistoryRecord target = null;
6437 int targetI = 0;
6438 int taskTopI = -1;
6439 int replyChainEnd = -1;
6440 int lastReparentPos = -1;
6441 for (int i=mHistory.size()-1; i>=-1; i--) {
6442 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6443
6444 if (below != null && below.finishing) {
6445 continue;
6446 }
6447 if (target == null) {
6448 target = below;
6449 targetI = i;
6450 // If we were in the middle of a reply chain before this
6451 // task, it doesn't appear like the root of the chain wants
6452 // anything interesting, so drop it.
6453 replyChainEnd = -1;
6454 continue;
6455 }
6456
6457 final int flags = target.info.flags;
6458
6459 final boolean finishOnTaskLaunch =
6460 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6461 final boolean allowTaskReparenting =
6462 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6463
6464 if (target.task == task) {
6465 // We are inside of the task being reset... we'll either
6466 // finish this activity, push it out for another task,
6467 // or leave it as-is. We only do this
6468 // for activities that are not the root of the task (since
6469 // if we finish the root, we may no longer have the task!).
6470 if (taskTopI < 0) {
6471 taskTopI = targetI;
6472 }
6473 if (below != null && below.task == task) {
6474 final boolean clearWhenTaskReset =
6475 (target.intent.getFlags()
6476 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006477 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006478 // If this activity is sending a reply to a previous
6479 // activity, we can't do anything with it now until
6480 // we reach the start of the reply chain.
6481 // XXX note that we are assuming the result is always
6482 // to the previous activity, which is almost always
6483 // the case but we really shouldn't count on.
6484 if (replyChainEnd < 0) {
6485 replyChainEnd = targetI;
6486 }
Ed Heyl73798232009-03-24 21:32:21 -07006487 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006488 && target.taskAffinity != null
6489 && !target.taskAffinity.equals(task.affinity)) {
6490 // If this activity has an affinity for another
6491 // task, then we need to move it out of here. We will
6492 // move it as far out of the way as possible, to the
6493 // bottom of the activity stack. This also keeps it
6494 // correctly ordered with any activities we previously
6495 // moved.
6496 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6497 if (target.taskAffinity != null
6498 && target.taskAffinity.equals(p.task.affinity)) {
6499 // If the activity currently at the bottom has the
6500 // same task affinity as the one we are moving,
6501 // then merge it into the same task.
6502 target.task = p.task;
6503 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6504 + " out to bottom task " + p.task);
6505 } else {
6506 mCurTask++;
6507 if (mCurTask <= 0) {
6508 mCurTask = 1;
6509 }
6510 target.task = new TaskRecord(mCurTask, target.info, null,
6511 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6512 target.task.affinityIntent = target.intent;
6513 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6514 + " out to new task " + target.task);
6515 }
6516 mWindowManager.setAppGroupId(target, task.taskId);
6517 if (replyChainEnd < 0) {
6518 replyChainEnd = targetI;
6519 }
6520 int dstPos = 0;
6521 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6522 p = (HistoryRecord)mHistory.get(srcPos);
6523 if (p.finishing) {
6524 continue;
6525 }
6526 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6527 + " out to target's task " + target.task);
6528 task.numActivities--;
6529 p.task = target.task;
6530 target.task.numActivities++;
6531 mHistory.remove(srcPos);
6532 mHistory.add(dstPos, p);
6533 mWindowManager.moveAppToken(dstPos, p);
6534 mWindowManager.setAppGroupId(p, p.task.taskId);
6535 dstPos++;
6536 if (VALIDATE_TOKENS) {
6537 mWindowManager.validateAppTokens(mHistory);
6538 }
6539 i++;
6540 }
6541 if (taskTop == p) {
6542 taskTop = below;
6543 }
6544 if (taskTopI == replyChainEnd) {
6545 taskTopI = -1;
6546 }
6547 replyChainEnd = -1;
6548 addRecentTask(target.task);
6549 } else if (forceReset || finishOnTaskLaunch
6550 || clearWhenTaskReset) {
6551 // If the activity should just be removed -- either
6552 // because it asks for it, or the task should be
6553 // cleared -- then finish it and anything that is
6554 // part of its reply chain.
6555 if (clearWhenTaskReset) {
6556 // In this case, we want to finish this activity
6557 // and everything above it, so be sneaky and pretend
6558 // like these are all in the reply chain.
6559 replyChainEnd = targetI+1;
6560 while (replyChainEnd < mHistory.size() &&
6561 ((HistoryRecord)mHistory.get(
6562 replyChainEnd)).task == task) {
6563 replyChainEnd++;
6564 }
6565 replyChainEnd--;
6566 } else if (replyChainEnd < 0) {
6567 replyChainEnd = targetI;
6568 }
6569 HistoryRecord p = null;
6570 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6571 p = (HistoryRecord)mHistory.get(srcPos);
6572 if (p.finishing) {
6573 continue;
6574 }
6575 if (finishActivityLocked(p, srcPos,
6576 Activity.RESULT_CANCELED, null, "reset")) {
6577 replyChainEnd--;
6578 srcPos--;
6579 }
6580 }
6581 if (taskTop == p) {
6582 taskTop = below;
6583 }
6584 if (taskTopI == replyChainEnd) {
6585 taskTopI = -1;
6586 }
6587 replyChainEnd = -1;
6588 } else {
6589 // If we were in the middle of a chain, well the
6590 // activity that started it all doesn't want anything
6591 // special, so leave it all as-is.
6592 replyChainEnd = -1;
6593 }
6594 } else {
6595 // Reached the bottom of the task -- any reply chain
6596 // should be left as-is.
6597 replyChainEnd = -1;
6598 }
6599
6600 } else if (target.resultTo != null) {
6601 // If this activity is sending a reply to a previous
6602 // activity, we can't do anything with it now until
6603 // we reach the start of the reply chain.
6604 // XXX note that we are assuming the result is always
6605 // to the previous activity, which is almost always
6606 // the case but we really shouldn't count on.
6607 if (replyChainEnd < 0) {
6608 replyChainEnd = targetI;
6609 }
6610
6611 } else if (taskTopI >= 0 && allowTaskReparenting
6612 && task.affinity != null
6613 && task.affinity.equals(target.taskAffinity)) {
6614 // We are inside of another task... if this activity has
6615 // an affinity for our task, then either remove it if we are
6616 // clearing or move it over to our task. Note that
6617 // we currently punt on the case where we are resetting a
6618 // task that is not at the top but who has activities above
6619 // with an affinity to it... this is really not a normal
6620 // case, and we will need to later pull that task to the front
6621 // and usually at that point we will do the reset and pick
6622 // up those remaining activities. (This only happens if
6623 // someone starts an activity in a new task from an activity
6624 // in a task that is not currently on top.)
6625 if (forceReset || finishOnTaskLaunch) {
6626 if (replyChainEnd < 0) {
6627 replyChainEnd = targetI;
6628 }
6629 HistoryRecord p = null;
6630 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6631 p = (HistoryRecord)mHistory.get(srcPos);
6632 if (p.finishing) {
6633 continue;
6634 }
6635 if (finishActivityLocked(p, srcPos,
6636 Activity.RESULT_CANCELED, null, "reset")) {
6637 taskTopI--;
6638 lastReparentPos--;
6639 replyChainEnd--;
6640 srcPos--;
6641 }
6642 }
6643 replyChainEnd = -1;
6644 } else {
6645 if (replyChainEnd < 0) {
6646 replyChainEnd = targetI;
6647 }
6648 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6649 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6650 if (p.finishing) {
6651 continue;
6652 }
6653 if (lastReparentPos < 0) {
6654 lastReparentPos = taskTopI;
6655 taskTop = p;
6656 } else {
6657 lastReparentPos--;
6658 }
6659 mHistory.remove(srcPos);
6660 p.task.numActivities--;
6661 p.task = task;
6662 mHistory.add(lastReparentPos, p);
6663 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6664 + " in to resetting task " + task);
6665 task.numActivities++;
6666 mWindowManager.moveAppToken(lastReparentPos, p);
6667 mWindowManager.setAppGroupId(p, p.task.taskId);
6668 if (VALIDATE_TOKENS) {
6669 mWindowManager.validateAppTokens(mHistory);
6670 }
6671 }
6672 replyChainEnd = -1;
6673
6674 // Now we've moved it in to place... but what if this is
6675 // a singleTop activity and we have put it on top of another
6676 // instance of the same activity? Then we drop the instance
6677 // below so it remains singleTop.
6678 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6679 for (int j=lastReparentPos-1; j>=0; j--) {
6680 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6681 if (p.finishing) {
6682 continue;
6683 }
6684 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6685 if (finishActivityLocked(p, j,
6686 Activity.RESULT_CANCELED, null, "replace")) {
6687 taskTopI--;
6688 lastReparentPos--;
6689 }
6690 }
6691 }
6692 }
6693 }
6694 }
6695
6696 target = below;
6697 targetI = i;
6698 }
6699
6700 return taskTop;
6701 }
6702
6703 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006704 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006705 */
6706 public void moveTaskToFront(int task) {
6707 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6708 "moveTaskToFront()");
6709
6710 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006711 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6712 Binder.getCallingUid(), "Task to front")) {
6713 return;
6714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006715 final long origId = Binder.clearCallingIdentity();
6716 try {
6717 int N = mRecentTasks.size();
6718 for (int i=0; i<N; i++) {
6719 TaskRecord tr = mRecentTasks.get(i);
6720 if (tr.taskId == task) {
6721 moveTaskToFrontLocked(tr);
6722 return;
6723 }
6724 }
6725 for (int i=mHistory.size()-1; i>=0; i--) {
6726 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6727 if (hr.task.taskId == task) {
6728 moveTaskToFrontLocked(hr.task);
6729 return;
6730 }
6731 }
6732 } finally {
6733 Binder.restoreCallingIdentity(origId);
6734 }
6735 }
6736 }
6737
6738 private final void moveTaskToFrontLocked(TaskRecord tr) {
6739 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6740
6741 final int task = tr.taskId;
6742 int top = mHistory.size()-1;
6743
6744 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6745 // nothing to do!
6746 return;
6747 }
6748
6749 if (DEBUG_TRANSITION) Log.v(TAG,
6750 "Prepare to front transition: task=" + tr);
6751 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6752
6753 ArrayList moved = new ArrayList();
6754
6755 // Applying the affinities may have removed entries from the history,
6756 // so get the size again.
6757 top = mHistory.size()-1;
6758 int pos = top;
6759
6760 // Shift all activities with this task up to the top
6761 // of the stack, keeping them in the same internal order.
6762 while (pos >= 0) {
6763 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6764 if (localLOGV) Log.v(
6765 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6766 boolean first = true;
6767 if (r.task.taskId == task) {
6768 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6769 mHistory.remove(pos);
6770 mHistory.add(top, r);
6771 moved.add(0, r);
6772 top--;
6773 if (first) {
6774 addRecentTask(r.task);
6775 first = false;
6776 }
6777 }
6778 pos--;
6779 }
6780
6781 mWindowManager.moveAppTokensToTop(moved);
6782 if (VALIDATE_TOKENS) {
6783 mWindowManager.validateAppTokens(mHistory);
6784 }
6785
6786 finishTaskMove(task);
6787 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6788 }
6789
6790 private final void finishTaskMove(int task) {
6791 resumeTopActivityLocked(null);
6792 }
6793
6794 public void moveTaskToBack(int task) {
6795 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6796 "moveTaskToBack()");
6797
6798 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006799 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6800 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6801 Binder.getCallingUid(), "Task to back")) {
6802 return;
6803 }
6804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006805 final long origId = Binder.clearCallingIdentity();
6806 moveTaskToBackLocked(task);
6807 Binder.restoreCallingIdentity(origId);
6808 }
6809 }
6810
6811 /**
6812 * Moves an activity, and all of the other activities within the same task, to the bottom
6813 * of the history stack. The activity's order within the task is unchanged.
6814 *
6815 * @param token A reference to the activity we wish to move
6816 * @param nonRoot If false then this only works if the activity is the root
6817 * of a task; if true it will work for any activity in a task.
6818 * @return Returns true if the move completed, false if not.
6819 */
6820 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6821 synchronized(this) {
6822 final long origId = Binder.clearCallingIdentity();
6823 int taskId = getTaskForActivityLocked(token, !nonRoot);
6824 if (taskId >= 0) {
6825 return moveTaskToBackLocked(taskId);
6826 }
6827 Binder.restoreCallingIdentity(origId);
6828 }
6829 return false;
6830 }
6831
6832 /**
6833 * Worker method for rearranging history stack. Implements the function of moving all
6834 * activities for a specific task (gathering them if disjoint) into a single group at the
6835 * bottom of the stack.
6836 *
6837 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6838 * to premeptively cancel the move.
6839 *
6840 * @param task The taskId to collect and move to the bottom.
6841 * @return Returns true if the move completed, false if not.
6842 */
6843 private final boolean moveTaskToBackLocked(int task) {
6844 Log.i(TAG, "moveTaskToBack: " + task);
6845
6846 // If we have a watcher, preflight the move before committing to it. First check
6847 // for *other* available tasks, but if none are available, then try again allowing the
6848 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006849 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006850 HistoryRecord next = topRunningActivityLocked(null, task);
6851 if (next == null) {
6852 next = topRunningActivityLocked(null, 0);
6853 }
6854 if (next != null) {
6855 // ask watcher if this is allowed
6856 boolean moveOK = true;
6857 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006858 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006859 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006860 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006861 }
6862 if (!moveOK) {
6863 return false;
6864 }
6865 }
6866 }
6867
6868 ArrayList moved = new ArrayList();
6869
6870 if (DEBUG_TRANSITION) Log.v(TAG,
6871 "Prepare to back transition: task=" + task);
6872 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6873
6874 final int N = mHistory.size();
6875 int bottom = 0;
6876 int pos = 0;
6877
6878 // Shift all activities with this task down to the bottom
6879 // of the stack, keeping them in the same internal order.
6880 while (pos < N) {
6881 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6882 if (localLOGV) Log.v(
6883 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6884 if (r.task.taskId == task) {
6885 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6886 mHistory.remove(pos);
6887 mHistory.add(bottom, r);
6888 moved.add(r);
6889 bottom++;
6890 }
6891 pos++;
6892 }
6893
6894 mWindowManager.moveAppTokensToBottom(moved);
6895 if (VALIDATE_TOKENS) {
6896 mWindowManager.validateAppTokens(mHistory);
6897 }
6898
6899 finishTaskMove(task);
6900 return true;
6901 }
6902
6903 public void moveTaskBackwards(int task) {
6904 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6905 "moveTaskBackwards()");
6906
6907 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006908 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6909 Binder.getCallingUid(), "Task backwards")) {
6910 return;
6911 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006912 final long origId = Binder.clearCallingIdentity();
6913 moveTaskBackwardsLocked(task);
6914 Binder.restoreCallingIdentity(origId);
6915 }
6916 }
6917
6918 private final void moveTaskBackwardsLocked(int task) {
6919 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6920 }
6921
6922 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6923 synchronized(this) {
6924 return getTaskForActivityLocked(token, onlyRoot);
6925 }
6926 }
6927
6928 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6929 final int N = mHistory.size();
6930 TaskRecord lastTask = null;
6931 for (int i=0; i<N; i++) {
6932 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6933 if (r == token) {
6934 if (!onlyRoot || lastTask != r.task) {
6935 return r.task.taskId;
6936 }
6937 return -1;
6938 }
6939 lastTask = r.task;
6940 }
6941
6942 return -1;
6943 }
6944
6945 /**
6946 * Returns the top activity in any existing task matching the given
6947 * Intent. Returns null if no such task is found.
6948 */
6949 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6950 ComponentName cls = intent.getComponent();
6951 if (info.targetActivity != null) {
6952 cls = new ComponentName(info.packageName, info.targetActivity);
6953 }
6954
6955 TaskRecord cp = null;
6956
6957 final int N = mHistory.size();
6958 for (int i=(N-1); i>=0; i--) {
6959 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6960 if (!r.finishing && r.task != cp
6961 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6962 cp = r.task;
6963 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6964 // + "/aff=" + r.task.affinity + " to new cls="
6965 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6966 if (r.task.affinity != null) {
6967 if (r.task.affinity.equals(info.taskAffinity)) {
6968 //Log.i(TAG, "Found matching affinity!");
6969 return r;
6970 }
6971 } else if (r.task.intent != null
6972 && r.task.intent.getComponent().equals(cls)) {
6973 //Log.i(TAG, "Found matching class!");
6974 //dump();
6975 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6976 return r;
6977 } else if (r.task.affinityIntent != null
6978 && r.task.affinityIntent.getComponent().equals(cls)) {
6979 //Log.i(TAG, "Found matching class!");
6980 //dump();
6981 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6982 return r;
6983 }
6984 }
6985 }
6986
6987 return null;
6988 }
6989
6990 /**
6991 * Returns the first activity (starting from the top of the stack) that
6992 * is the same as the given activity. Returns null if no such activity
6993 * is found.
6994 */
6995 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6996 ComponentName cls = intent.getComponent();
6997 if (info.targetActivity != null) {
6998 cls = new ComponentName(info.packageName, info.targetActivity);
6999 }
7000
7001 final int N = mHistory.size();
7002 for (int i=(N-1); i>=0; i--) {
7003 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7004 if (!r.finishing) {
7005 if (r.intent.getComponent().equals(cls)) {
7006 //Log.i(TAG, "Found matching class!");
7007 //dump();
7008 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7009 return r;
7010 }
7011 }
7012 }
7013
7014 return null;
7015 }
7016
7017 public void finishOtherInstances(IBinder token, ComponentName className) {
7018 synchronized(this) {
7019 final long origId = Binder.clearCallingIdentity();
7020
7021 int N = mHistory.size();
7022 TaskRecord lastTask = null;
7023 for (int i=0; i<N; i++) {
7024 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7025 if (r.realActivity.equals(className)
7026 && r != token && lastTask != r.task) {
7027 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7028 null, "others")) {
7029 i--;
7030 N--;
7031 }
7032 }
7033 lastTask = r.task;
7034 }
7035
7036 Binder.restoreCallingIdentity(origId);
7037 }
7038 }
7039
7040 // =========================================================
7041 // THUMBNAILS
7042 // =========================================================
7043
7044 public void reportThumbnail(IBinder token,
7045 Bitmap thumbnail, CharSequence description) {
7046 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7047 final long origId = Binder.clearCallingIdentity();
7048 sendPendingThumbnail(null, token, thumbnail, description, true);
7049 Binder.restoreCallingIdentity(origId);
7050 }
7051
7052 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7053 Bitmap thumbnail, CharSequence description, boolean always) {
7054 TaskRecord task = null;
7055 ArrayList receivers = null;
7056
7057 //System.out.println("Send pending thumbnail: " + r);
7058
7059 synchronized(this) {
7060 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007061 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007062 if (index < 0) {
7063 return;
7064 }
7065 r = (HistoryRecord)mHistory.get(index);
7066 }
7067 if (thumbnail == null) {
7068 thumbnail = r.thumbnail;
7069 description = r.description;
7070 }
7071 if (thumbnail == null && !always) {
7072 // If there is no thumbnail, and this entry is not actually
7073 // going away, then abort for now and pick up the next
7074 // thumbnail we get.
7075 return;
7076 }
7077 task = r.task;
7078
7079 int N = mPendingThumbnails.size();
7080 int i=0;
7081 while (i<N) {
7082 PendingThumbnailsRecord pr =
7083 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7084 //System.out.println("Looking in " + pr.pendingRecords);
7085 if (pr.pendingRecords.remove(r)) {
7086 if (receivers == null) {
7087 receivers = new ArrayList();
7088 }
7089 receivers.add(pr);
7090 if (pr.pendingRecords.size() == 0) {
7091 pr.finished = true;
7092 mPendingThumbnails.remove(i);
7093 N--;
7094 continue;
7095 }
7096 }
7097 i++;
7098 }
7099 }
7100
7101 if (receivers != null) {
7102 final int N = receivers.size();
7103 for (int i=0; i<N; i++) {
7104 try {
7105 PendingThumbnailsRecord pr =
7106 (PendingThumbnailsRecord)receivers.get(i);
7107 pr.receiver.newThumbnail(
7108 task != null ? task.taskId : -1, thumbnail, description);
7109 if (pr.finished) {
7110 pr.receiver.finished();
7111 }
7112 } catch (Exception e) {
7113 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7114 }
7115 }
7116 }
7117 }
7118
7119 // =========================================================
7120 // CONTENT PROVIDERS
7121 // =========================================================
7122
7123 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7124 List providers = null;
7125 try {
7126 providers = ActivityThread.getPackageManager().
7127 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007128 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007129 } catch (RemoteException ex) {
7130 }
7131 if (providers != null) {
7132 final int N = providers.size();
7133 for (int i=0; i<N; i++) {
7134 ProviderInfo cpi =
7135 (ProviderInfo)providers.get(i);
7136 ContentProviderRecord cpr =
7137 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7138 if (cpr == null) {
7139 cpr = new ContentProviderRecord(cpi, app.info);
7140 mProvidersByClass.put(cpi.name, cpr);
7141 }
7142 app.pubProviders.put(cpi.name, cpr);
7143 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007144 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007145 }
7146 }
7147 return providers;
7148 }
7149
7150 private final String checkContentProviderPermissionLocked(
7151 ProviderInfo cpi, ProcessRecord r, int mode) {
7152 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7153 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7154 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7155 cpi.exported ? -1 : cpi.applicationInfo.uid)
7156 == PackageManager.PERMISSION_GRANTED
7157 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7158 return null;
7159 }
7160 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7161 cpi.exported ? -1 : cpi.applicationInfo.uid)
7162 == PackageManager.PERMISSION_GRANTED) {
7163 return null;
7164 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007165
7166 PathPermission[] pps = cpi.pathPermissions;
7167 if (pps != null) {
7168 int i = pps.length;
7169 while (i > 0) {
7170 i--;
7171 PathPermission pp = pps[i];
7172 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7173 cpi.exported ? -1 : cpi.applicationInfo.uid)
7174 == PackageManager.PERMISSION_GRANTED
7175 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7176 return null;
7177 }
7178 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7179 cpi.exported ? -1 : cpi.applicationInfo.uid)
7180 == PackageManager.PERMISSION_GRANTED) {
7181 return null;
7182 }
7183 }
7184 }
7185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007186 String msg = "Permission Denial: opening provider " + cpi.name
7187 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7188 + ", uid=" + callingUid + ") requires "
7189 + cpi.readPermission + " or " + cpi.writePermission;
7190 Log.w(TAG, msg);
7191 return msg;
7192 }
7193
7194 private final ContentProviderHolder getContentProviderImpl(
7195 IApplicationThread caller, String name) {
7196 ContentProviderRecord cpr;
7197 ProviderInfo cpi = null;
7198
7199 synchronized(this) {
7200 ProcessRecord r = null;
7201 if (caller != null) {
7202 r = getRecordForAppLocked(caller);
7203 if (r == null) {
7204 throw new SecurityException(
7205 "Unable to find app for caller " + caller
7206 + " (pid=" + Binder.getCallingPid()
7207 + ") when getting content provider " + name);
7208 }
7209 }
7210
7211 // First check if this content provider has been published...
7212 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7213 if (cpr != null) {
7214 cpi = cpr.info;
7215 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7216 return new ContentProviderHolder(cpi,
7217 cpi.readPermission != null
7218 ? cpi.readPermission : cpi.writePermission);
7219 }
7220
7221 if (r != null && cpr.canRunHere(r)) {
7222 // This provider has been published or is in the process
7223 // of being published... but it is also allowed to run
7224 // in the caller's process, so don't make a connection
7225 // and just let the caller instantiate its own instance.
7226 if (cpr.provider != null) {
7227 // don't give caller the provider object, it needs
7228 // to make its own.
7229 cpr = new ContentProviderRecord(cpr);
7230 }
7231 return cpr;
7232 }
7233
7234 final long origId = Binder.clearCallingIdentity();
7235
7236 // In this case the provider is a single instance, so we can
7237 // return it right away.
7238 if (r != null) {
7239 r.conProviders.add(cpr);
7240 cpr.clients.add(r);
7241 } else {
7242 cpr.externals++;
7243 }
7244
7245 if (cpr.app != null) {
7246 updateOomAdjLocked(cpr.app);
7247 }
7248
7249 Binder.restoreCallingIdentity(origId);
7250
7251 } else {
7252 try {
7253 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007254 resolveContentProvider(name,
7255 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007256 } catch (RemoteException ex) {
7257 }
7258 if (cpi == null) {
7259 return null;
7260 }
7261
7262 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7263 return new ContentProviderHolder(cpi,
7264 cpi.readPermission != null
7265 ? cpi.readPermission : cpi.writePermission);
7266 }
7267
7268 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7269 final boolean firstClass = cpr == null;
7270 if (firstClass) {
7271 try {
7272 ApplicationInfo ai =
7273 ActivityThread.getPackageManager().
7274 getApplicationInfo(
7275 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007276 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007277 if (ai == null) {
7278 Log.w(TAG, "No package info for content provider "
7279 + cpi.name);
7280 return null;
7281 }
7282 cpr = new ContentProviderRecord(cpi, ai);
7283 } catch (RemoteException ex) {
7284 // pm is in same process, this will never happen.
7285 }
7286 }
7287
7288 if (r != null && cpr.canRunHere(r)) {
7289 // If this is a multiprocess provider, then just return its
7290 // info and allow the caller to instantiate it. Only do
7291 // this if the provider is the same user as the caller's
7292 // process, or can run as root (so can be in any process).
7293 return cpr;
7294 }
7295
7296 if (false) {
7297 RuntimeException e = new RuntimeException("foo");
7298 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7299 // + " pruid " + ai.uid + "): " + cpi.className, e);
7300 }
7301
7302 // This is single process, and our app is now connecting to it.
7303 // See if we are already in the process of launching this
7304 // provider.
7305 final int N = mLaunchingProviders.size();
7306 int i;
7307 for (i=0; i<N; i++) {
7308 if (mLaunchingProviders.get(i) == cpr) {
7309 break;
7310 }
7311 if (false) {
7312 final ContentProviderRecord rec =
7313 (ContentProviderRecord)mLaunchingProviders.get(i);
7314 if (rec.info.name.equals(cpr.info.name)) {
7315 cpr = rec;
7316 break;
7317 }
7318 }
7319 }
7320
7321 // If the provider is not already being launched, then get it
7322 // started.
7323 if (i >= N) {
7324 final long origId = Binder.clearCallingIdentity();
7325 ProcessRecord proc = startProcessLocked(cpi.processName,
7326 cpr.appInfo, false, 0, "content provider",
7327 new ComponentName(cpi.applicationInfo.packageName,
7328 cpi.name));
7329 if (proc == null) {
7330 Log.w(TAG, "Unable to launch app "
7331 + cpi.applicationInfo.packageName + "/"
7332 + cpi.applicationInfo.uid + " for provider "
7333 + name + ": process is bad");
7334 return null;
7335 }
7336 cpr.launchingApp = proc;
7337 mLaunchingProviders.add(cpr);
7338 Binder.restoreCallingIdentity(origId);
7339 }
7340
7341 // Make sure the provider is published (the same provider class
7342 // may be published under multiple names).
7343 if (firstClass) {
7344 mProvidersByClass.put(cpi.name, cpr);
7345 }
7346 mProvidersByName.put(name, cpr);
7347
7348 if (r != null) {
7349 r.conProviders.add(cpr);
7350 cpr.clients.add(r);
7351 } else {
7352 cpr.externals++;
7353 }
7354 }
7355 }
7356
7357 // Wait for the provider to be published...
7358 synchronized (cpr) {
7359 while (cpr.provider == null) {
7360 if (cpr.launchingApp == null) {
7361 Log.w(TAG, "Unable to launch app "
7362 + cpi.applicationInfo.packageName + "/"
7363 + cpi.applicationInfo.uid + " for provider "
7364 + name + ": launching app became null");
7365 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7366 cpi.applicationInfo.packageName,
7367 cpi.applicationInfo.uid, name);
7368 return null;
7369 }
7370 try {
7371 cpr.wait();
7372 } catch (InterruptedException ex) {
7373 }
7374 }
7375 }
7376 return cpr;
7377 }
7378
7379 public final ContentProviderHolder getContentProvider(
7380 IApplicationThread caller, String name) {
7381 if (caller == null) {
7382 String msg = "null IApplicationThread when getting content provider "
7383 + name;
7384 Log.w(TAG, msg);
7385 throw new SecurityException(msg);
7386 }
7387
7388 return getContentProviderImpl(caller, name);
7389 }
7390
7391 private ContentProviderHolder getContentProviderExternal(String name) {
7392 return getContentProviderImpl(null, name);
7393 }
7394
7395 /**
7396 * Drop a content provider from a ProcessRecord's bookkeeping
7397 * @param cpr
7398 */
7399 public void removeContentProvider(IApplicationThread caller, String name) {
7400 synchronized (this) {
7401 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7402 if(cpr == null) {
7403 //remove from mProvidersByClass
7404 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7405 return;
7406 }
7407 final ProcessRecord r = getRecordForAppLocked(caller);
7408 if (r == null) {
7409 throw new SecurityException(
7410 "Unable to find app for caller " + caller +
7411 " when removing content provider " + name);
7412 }
7413 //update content provider record entry info
7414 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7415 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7416 r.info.processName+" from process "+localCpr.appInfo.processName);
7417 if(localCpr.appInfo.processName == r.info.processName) {
7418 //should not happen. taken care of as a local provider
7419 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7420 return;
7421 } else {
7422 localCpr.clients.remove(r);
7423 r.conProviders.remove(localCpr);
7424 }
7425 updateOomAdjLocked();
7426 }
7427 }
7428
7429 private void removeContentProviderExternal(String name) {
7430 synchronized (this) {
7431 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7432 if(cpr == null) {
7433 //remove from mProvidersByClass
7434 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7435 return;
7436 }
7437
7438 //update content provider record entry info
7439 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7440 localCpr.externals--;
7441 if (localCpr.externals < 0) {
7442 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7443 }
7444 updateOomAdjLocked();
7445 }
7446 }
7447
7448 public final void publishContentProviders(IApplicationThread caller,
7449 List<ContentProviderHolder> providers) {
7450 if (providers == null) {
7451 return;
7452 }
7453
7454 synchronized(this) {
7455 final ProcessRecord r = getRecordForAppLocked(caller);
7456 if (r == null) {
7457 throw new SecurityException(
7458 "Unable to find app for caller " + caller
7459 + " (pid=" + Binder.getCallingPid()
7460 + ") when publishing content providers");
7461 }
7462
7463 final long origId = Binder.clearCallingIdentity();
7464
7465 final int N = providers.size();
7466 for (int i=0; i<N; i++) {
7467 ContentProviderHolder src = providers.get(i);
7468 if (src == null || src.info == null || src.provider == null) {
7469 continue;
7470 }
7471 ContentProviderRecord dst =
7472 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7473 if (dst != null) {
7474 mProvidersByClass.put(dst.info.name, dst);
7475 String names[] = dst.info.authority.split(";");
7476 for (int j = 0; j < names.length; j++) {
7477 mProvidersByName.put(names[j], dst);
7478 }
7479
7480 int NL = mLaunchingProviders.size();
7481 int j;
7482 for (j=0; j<NL; j++) {
7483 if (mLaunchingProviders.get(j) == dst) {
7484 mLaunchingProviders.remove(j);
7485 j--;
7486 NL--;
7487 }
7488 }
7489 synchronized (dst) {
7490 dst.provider = src.provider;
7491 dst.app = r;
7492 dst.notifyAll();
7493 }
7494 updateOomAdjLocked(r);
7495 }
7496 }
7497
7498 Binder.restoreCallingIdentity(origId);
7499 }
7500 }
7501
7502 public static final void installSystemProviders() {
7503 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7504 List providers = mSelf.generateApplicationProvidersLocked(app);
7505 mSystemThread.installSystemProviders(providers);
7506 }
7507
7508 // =========================================================
7509 // GLOBAL MANAGEMENT
7510 // =========================================================
7511
7512 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7513 ApplicationInfo info, String customProcess) {
7514 String proc = customProcess != null ? customProcess : info.processName;
7515 BatteryStatsImpl.Uid.Proc ps = null;
7516 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7517 synchronized (stats) {
7518 ps = stats.getProcessStatsLocked(info.uid, proc);
7519 }
7520 return new ProcessRecord(ps, thread, info, proc);
7521 }
7522
7523 final ProcessRecord addAppLocked(ApplicationInfo info) {
7524 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7525
7526 if (app == null) {
7527 app = newProcessRecordLocked(null, info, null);
7528 mProcessNames.put(info.processName, info.uid, app);
7529 updateLRUListLocked(app, true);
7530 }
7531
7532 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7533 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7534 app.persistent = true;
7535 app.maxAdj = CORE_SERVER_ADJ;
7536 }
7537 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7538 mPersistentStartingProcesses.add(app);
7539 startProcessLocked(app, "added application", app.processName);
7540 }
7541
7542 return app;
7543 }
7544
7545 public void unhandledBack() {
7546 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7547 "unhandledBack()");
7548
7549 synchronized(this) {
7550 int count = mHistory.size();
7551 if (Config.LOGD) Log.d(
7552 TAG, "Performing unhandledBack(): stack size = " + count);
7553 if (count > 1) {
7554 final long origId = Binder.clearCallingIdentity();
7555 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7556 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7557 Binder.restoreCallingIdentity(origId);
7558 }
7559 }
7560 }
7561
7562 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7563 String name = uri.getAuthority();
7564 ContentProviderHolder cph = getContentProviderExternal(name);
7565 ParcelFileDescriptor pfd = null;
7566 if (cph != null) {
7567 // We record the binder invoker's uid in thread-local storage before
7568 // going to the content provider to open the file. Later, in the code
7569 // that handles all permissions checks, we look for this uid and use
7570 // that rather than the Activity Manager's own uid. The effect is that
7571 // we do the check against the caller's permissions even though it looks
7572 // to the content provider like the Activity Manager itself is making
7573 // the request.
7574 sCallerIdentity.set(new Identity(
7575 Binder.getCallingPid(), Binder.getCallingUid()));
7576 try {
7577 pfd = cph.provider.openFile(uri, "r");
7578 } catch (FileNotFoundException e) {
7579 // do nothing; pfd will be returned null
7580 } finally {
7581 // Ensure that whatever happens, we clean up the identity state
7582 sCallerIdentity.remove();
7583 }
7584
7585 // We've got the fd now, so we're done with the provider.
7586 removeContentProviderExternal(name);
7587 } else {
7588 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7589 }
7590 return pfd;
7591 }
7592
7593 public void goingToSleep() {
7594 synchronized(this) {
7595 mSleeping = true;
7596 mWindowManager.setEventDispatching(false);
7597
7598 if (mResumedActivity != null) {
7599 pauseIfSleepingLocked();
7600 } else {
7601 Log.w(TAG, "goingToSleep with no resumed activity!");
7602 }
7603 }
7604 }
7605
Dianne Hackborn55280a92009-05-07 15:53:46 -07007606 public boolean shutdown(int timeout) {
7607 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7608 != PackageManager.PERMISSION_GRANTED) {
7609 throw new SecurityException("Requires permission "
7610 + android.Manifest.permission.SHUTDOWN);
7611 }
7612
7613 boolean timedout = false;
7614
7615 synchronized(this) {
7616 mShuttingDown = true;
7617 mWindowManager.setEventDispatching(false);
7618
7619 if (mResumedActivity != null) {
7620 pauseIfSleepingLocked();
7621 final long endTime = System.currentTimeMillis() + timeout;
7622 while (mResumedActivity != null || mPausingActivity != null) {
7623 long delay = endTime - System.currentTimeMillis();
7624 if (delay <= 0) {
7625 Log.w(TAG, "Activity manager shutdown timed out");
7626 timedout = true;
7627 break;
7628 }
7629 try {
7630 this.wait();
7631 } catch (InterruptedException e) {
7632 }
7633 }
7634 }
7635 }
7636
7637 mUsageStatsService.shutdown();
7638 mBatteryStatsService.shutdown();
7639
7640 return timedout;
7641 }
7642
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007643 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007644 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007645 if (!mGoingToSleep.isHeld()) {
7646 mGoingToSleep.acquire();
7647 if (mLaunchingActivity.isHeld()) {
7648 mLaunchingActivity.release();
7649 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7650 }
7651 }
7652
7653 // If we are not currently pausing an activity, get the current
7654 // one to pause. If we are pausing one, we will just let that stuff
7655 // run and release the wake lock when all done.
7656 if (mPausingActivity == null) {
7657 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7658 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7659 startPausingLocked(false, true);
7660 }
7661 }
7662 }
7663
7664 public void wakingUp() {
7665 synchronized(this) {
7666 if (mGoingToSleep.isHeld()) {
7667 mGoingToSleep.release();
7668 }
7669 mWindowManager.setEventDispatching(true);
7670 mSleeping = false;
7671 resumeTopActivityLocked(null);
7672 }
7673 }
7674
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007675 public void stopAppSwitches() {
7676 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7677 != PackageManager.PERMISSION_GRANTED) {
7678 throw new SecurityException("Requires permission "
7679 + android.Manifest.permission.STOP_APP_SWITCHES);
7680 }
7681
7682 synchronized(this) {
7683 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7684 + APP_SWITCH_DELAY_TIME;
7685 mDidAppSwitch = false;
7686 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7687 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7688 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7689 }
7690 }
7691
7692 public void resumeAppSwitches() {
7693 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7694 != PackageManager.PERMISSION_GRANTED) {
7695 throw new SecurityException("Requires permission "
7696 + android.Manifest.permission.STOP_APP_SWITCHES);
7697 }
7698
7699 synchronized(this) {
7700 // Note that we don't execute any pending app switches... we will
7701 // let those wait until either the timeout, or the next start
7702 // activity request.
7703 mAppSwitchesAllowedTime = 0;
7704 }
7705 }
7706
7707 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7708 String name) {
7709 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7710 return true;
7711 }
7712
7713 final int perm = checkComponentPermission(
7714 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7715 callingUid, -1);
7716 if (perm == PackageManager.PERMISSION_GRANTED) {
7717 return true;
7718 }
7719
7720 Log.w(TAG, name + " request from " + callingUid + " stopped");
7721 return false;
7722 }
7723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007724 public void setDebugApp(String packageName, boolean waitForDebugger,
7725 boolean persistent) {
7726 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7727 "setDebugApp()");
7728
7729 // Note that this is not really thread safe if there are multiple
7730 // callers into it at the same time, but that's not a situation we
7731 // care about.
7732 if (persistent) {
7733 final ContentResolver resolver = mContext.getContentResolver();
7734 Settings.System.putString(
7735 resolver, Settings.System.DEBUG_APP,
7736 packageName);
7737 Settings.System.putInt(
7738 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7739 waitForDebugger ? 1 : 0);
7740 }
7741
7742 synchronized (this) {
7743 if (!persistent) {
7744 mOrigDebugApp = mDebugApp;
7745 mOrigWaitForDebugger = mWaitForDebugger;
7746 }
7747 mDebugApp = packageName;
7748 mWaitForDebugger = waitForDebugger;
7749 mDebugTransient = !persistent;
7750 if (packageName != null) {
7751 final long origId = Binder.clearCallingIdentity();
7752 uninstallPackageLocked(packageName, -1, false);
7753 Binder.restoreCallingIdentity(origId);
7754 }
7755 }
7756 }
7757
7758 public void setAlwaysFinish(boolean enabled) {
7759 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7760 "setAlwaysFinish()");
7761
7762 Settings.System.putInt(
7763 mContext.getContentResolver(),
7764 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7765
7766 synchronized (this) {
7767 mAlwaysFinishActivities = enabled;
7768 }
7769 }
7770
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007771 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007772 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007773 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007774 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007775 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007776 }
7777 }
7778
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007779 public void registerActivityWatcher(IActivityWatcher watcher) {
7780 mWatchers.register(watcher);
7781 }
7782
7783 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7784 mWatchers.unregister(watcher);
7785 }
7786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007787 public final void enterSafeMode() {
7788 synchronized(this) {
7789 // It only makes sense to do this before the system is ready
7790 // and started launching other packages.
7791 if (!mSystemReady) {
7792 try {
7793 ActivityThread.getPackageManager().enterSafeMode();
7794 } catch (RemoteException e) {
7795 }
7796
7797 View v = LayoutInflater.from(mContext).inflate(
7798 com.android.internal.R.layout.safe_mode, null);
7799 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7800 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7801 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7802 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7803 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7804 lp.format = v.getBackground().getOpacity();
7805 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7806 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7807 ((WindowManager)mContext.getSystemService(
7808 Context.WINDOW_SERVICE)).addView(v, lp);
7809 }
7810 }
7811 }
7812
7813 public void noteWakeupAlarm(IIntentSender sender) {
7814 if (!(sender instanceof PendingIntentRecord)) {
7815 return;
7816 }
7817 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7818 synchronized (stats) {
7819 if (mBatteryStatsService.isOnBattery()) {
7820 mBatteryStatsService.enforceCallingPermission();
7821 PendingIntentRecord rec = (PendingIntentRecord)sender;
7822 int MY_UID = Binder.getCallingUid();
7823 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7824 BatteryStatsImpl.Uid.Pkg pkg =
7825 stats.getPackageStatsLocked(uid, rec.key.packageName);
7826 pkg.incWakeupsLocked();
7827 }
7828 }
7829 }
7830
7831 public boolean killPidsForMemory(int[] pids) {
7832 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7833 throw new SecurityException("killPidsForMemory only available to the system");
7834 }
7835
7836 // XXX Note: don't acquire main activity lock here, because the window
7837 // manager calls in with its locks held.
7838
7839 boolean killed = false;
7840 synchronized (mPidsSelfLocked) {
7841 int[] types = new int[pids.length];
7842 int worstType = 0;
7843 for (int i=0; i<pids.length; i++) {
7844 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7845 if (proc != null) {
7846 int type = proc.setAdj;
7847 types[i] = type;
7848 if (type > worstType) {
7849 worstType = type;
7850 }
7851 }
7852 }
7853
7854 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7855 // then constrain it so we will kill all hidden procs.
7856 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7857 worstType = HIDDEN_APP_MIN_ADJ;
7858 }
7859 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7860 for (int i=0; i<pids.length; i++) {
7861 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7862 if (proc == null) {
7863 continue;
7864 }
7865 int adj = proc.setAdj;
7866 if (adj >= worstType) {
7867 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7868 + adj + ")");
7869 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7870 proc.processName, adj);
7871 killed = true;
7872 Process.killProcess(pids[i]);
7873 }
7874 }
7875 }
7876 return killed;
7877 }
7878
7879 public void reportPss(IApplicationThread caller, int pss) {
7880 Watchdog.PssRequestor req;
7881 String name;
7882 ProcessRecord callerApp;
7883 synchronized (this) {
7884 if (caller == null) {
7885 return;
7886 }
7887 callerApp = getRecordForAppLocked(caller);
7888 if (callerApp == null) {
7889 return;
7890 }
7891 callerApp.lastPss = pss;
7892 req = callerApp;
7893 name = callerApp.processName;
7894 }
7895 Watchdog.getInstance().reportPss(req, name, pss);
7896 if (!callerApp.persistent) {
7897 removeRequestedPss(callerApp);
7898 }
7899 }
7900
7901 public void requestPss(Runnable completeCallback) {
7902 ArrayList<ProcessRecord> procs;
7903 synchronized (this) {
7904 mRequestPssCallback = completeCallback;
7905 mRequestPssList.clear();
7906 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7907 ProcessRecord proc = mLRUProcesses.get(i);
7908 if (!proc.persistent) {
7909 mRequestPssList.add(proc);
7910 }
7911 }
7912 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7913 }
7914
7915 int oldPri = Process.getThreadPriority(Process.myTid());
7916 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7917 for (int i=procs.size()-1; i>=0; i--) {
7918 ProcessRecord proc = procs.get(i);
7919 proc.lastPss = 0;
7920 proc.requestPss();
7921 }
7922 Process.setThreadPriority(oldPri);
7923 }
7924
7925 void removeRequestedPss(ProcessRecord proc) {
7926 Runnable callback = null;
7927 synchronized (this) {
7928 if (mRequestPssList.remove(proc)) {
7929 if (mRequestPssList.size() == 0) {
7930 callback = mRequestPssCallback;
7931 mRequestPssCallback = null;
7932 }
7933 }
7934 }
7935
7936 if (callback != null) {
7937 callback.run();
7938 }
7939 }
7940
7941 public void collectPss(Watchdog.PssStats stats) {
7942 stats.mEmptyPss = 0;
7943 stats.mEmptyCount = 0;
7944 stats.mBackgroundPss = 0;
7945 stats.mBackgroundCount = 0;
7946 stats.mServicePss = 0;
7947 stats.mServiceCount = 0;
7948 stats.mVisiblePss = 0;
7949 stats.mVisibleCount = 0;
7950 stats.mForegroundPss = 0;
7951 stats.mForegroundCount = 0;
7952 stats.mNoPssCount = 0;
7953 synchronized (this) {
7954 int i;
7955 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7956 ? mProcDeaths.length : stats.mProcDeaths.length;
7957 int aggr = 0;
7958 for (i=0; i<NPD; i++) {
7959 aggr += mProcDeaths[i];
7960 stats.mProcDeaths[i] = aggr;
7961 }
7962 while (i<stats.mProcDeaths.length) {
7963 stats.mProcDeaths[i] = 0;
7964 i++;
7965 }
7966
7967 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7968 ProcessRecord proc = mLRUProcesses.get(i);
7969 if (proc.persistent) {
7970 continue;
7971 }
7972 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7973 if (proc.lastPss == 0) {
7974 stats.mNoPssCount++;
7975 continue;
7976 }
7977 if (proc.setAdj == EMPTY_APP_ADJ) {
7978 stats.mEmptyPss += proc.lastPss;
7979 stats.mEmptyCount++;
7980 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7981 stats.mEmptyPss += proc.lastPss;
7982 stats.mEmptyCount++;
7983 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7984 stats.mBackgroundPss += proc.lastPss;
7985 stats.mBackgroundCount++;
7986 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7987 stats.mVisiblePss += proc.lastPss;
7988 stats.mVisibleCount++;
7989 } else {
7990 stats.mForegroundPss += proc.lastPss;
7991 stats.mForegroundCount++;
7992 }
7993 }
7994 }
7995 }
7996
7997 public final void startRunning(String pkg, String cls, String action,
7998 String data) {
7999 synchronized(this) {
8000 if (mStartRunning) {
8001 return;
8002 }
8003 mStartRunning = true;
8004 mTopComponent = pkg != null && cls != null
8005 ? new ComponentName(pkg, cls) : null;
8006 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8007 mTopData = data;
8008 if (!mSystemReady) {
8009 return;
8010 }
8011 }
8012
8013 systemReady();
8014 }
8015
8016 private void retrieveSettings() {
8017 final ContentResolver resolver = mContext.getContentResolver();
8018 String debugApp = Settings.System.getString(
8019 resolver, Settings.System.DEBUG_APP);
8020 boolean waitForDebugger = Settings.System.getInt(
8021 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8022 boolean alwaysFinishActivities = Settings.System.getInt(
8023 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8024
8025 Configuration configuration = new Configuration();
8026 Settings.System.getConfiguration(resolver, configuration);
8027
8028 synchronized (this) {
8029 mDebugApp = mOrigDebugApp = debugApp;
8030 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8031 mAlwaysFinishActivities = alwaysFinishActivities;
8032 // This happens before any activities are started, so we can
8033 // change mConfiguration in-place.
8034 mConfiguration.updateFrom(configuration);
8035 }
8036 }
8037
8038 public boolean testIsSystemReady() {
8039 // no need to synchronize(this) just to read & return the value
8040 return mSystemReady;
8041 }
8042
8043 public void systemReady() {
8044 // In the simulator, startRunning will never have been called, which
8045 // normally sets a few crucial variables. Do it here instead.
8046 if (!Process.supportsProcesses()) {
8047 mStartRunning = true;
8048 mTopAction = Intent.ACTION_MAIN;
8049 }
8050
8051 synchronized(this) {
8052 if (mSystemReady) {
8053 return;
8054 }
8055 mSystemReady = true;
8056 if (!mStartRunning) {
8057 return;
8058 }
8059 }
8060
8061 if (Config.LOGD) Log.d(TAG, "Start running!");
8062 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8063 SystemClock.uptimeMillis());
8064
8065 synchronized(this) {
8066 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8067 ResolveInfo ri = mContext.getPackageManager()
8068 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008069 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008070 CharSequence errorMsg = null;
8071 if (ri != null) {
8072 ActivityInfo ai = ri.activityInfo;
8073 ApplicationInfo app = ai.applicationInfo;
8074 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8075 mTopAction = Intent.ACTION_FACTORY_TEST;
8076 mTopData = null;
8077 mTopComponent = new ComponentName(app.packageName,
8078 ai.name);
8079 } else {
8080 errorMsg = mContext.getResources().getText(
8081 com.android.internal.R.string.factorytest_not_system);
8082 }
8083 } else {
8084 errorMsg = mContext.getResources().getText(
8085 com.android.internal.R.string.factorytest_no_action);
8086 }
8087 if (errorMsg != null) {
8088 mTopAction = null;
8089 mTopData = null;
8090 mTopComponent = null;
8091 Message msg = Message.obtain();
8092 msg.what = SHOW_FACTORY_ERROR_MSG;
8093 msg.getData().putCharSequence("msg", errorMsg);
8094 mHandler.sendMessage(msg);
8095 }
8096 }
8097 }
8098
8099 retrieveSettings();
8100
8101 synchronized (this) {
8102 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8103 try {
8104 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008105 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008106 if (apps != null) {
8107 int N = apps.size();
8108 int i;
8109 for (i=0; i<N; i++) {
8110 ApplicationInfo info
8111 = (ApplicationInfo)apps.get(i);
8112 if (info != null &&
8113 !info.packageName.equals("android")) {
8114 addAppLocked(info);
8115 }
8116 }
8117 }
8118 } catch (RemoteException ex) {
8119 // pm is in same process, this will never happen.
8120 }
8121 }
8122
8123 try {
8124 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8125 Message msg = Message.obtain();
8126 msg.what = SHOW_UID_ERROR_MSG;
8127 mHandler.sendMessage(msg);
8128 }
8129 } catch (RemoteException e) {
8130 }
8131
8132 // Start up initial activity.
8133 mBooting = true;
8134 resumeTopActivityLocked(null);
8135 }
8136 }
8137
8138 boolean makeAppCrashingLocked(ProcessRecord app,
8139 String tag, String shortMsg, String longMsg, byte[] crashData) {
8140 app.crashing = true;
8141 app.crashingReport = generateProcessError(app,
8142 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8143 startAppProblemLocked(app);
8144 app.stopFreezingAllLocked();
8145 return handleAppCrashLocked(app);
8146 }
8147
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008148 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8149 IPackageManager pm = ActivityThread.getPackageManager();
8150 try {
8151 // was an installer package name specified when this app was
8152 // installed?
8153 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8154 if (installerPackageName == null) {
8155 return null;
8156 }
8157
8158 // is there an Activity in this package that handles ACTION_APP_ERROR?
8159 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008160 intent.setPackage(installerPackageName);
8161 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008162 if (info == null || info.activityInfo == null) {
8163 return null;
8164 }
8165
8166 return new ComponentName(installerPackageName, info.activityInfo.name);
8167 } catch (RemoteException e) {
8168 // will return null and no error report will be delivered
8169 }
8170 return null;
8171 }
8172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008173 void makeAppNotRespondingLocked(ProcessRecord app,
8174 String tag, String shortMsg, String longMsg, byte[] crashData) {
8175 app.notResponding = true;
8176 app.notRespondingReport = generateProcessError(app,
8177 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8178 crashData);
8179 startAppProblemLocked(app);
8180 app.stopFreezingAllLocked();
8181 }
8182
8183 /**
8184 * Generate a process error record, suitable for attachment to a ProcessRecord.
8185 *
8186 * @param app The ProcessRecord in which the error occurred.
8187 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8188 * ActivityManager.AppErrorStateInfo
8189 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8190 * @param shortMsg Short message describing the crash.
8191 * @param longMsg Long message describing the crash.
8192 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8193 *
8194 * @return Returns a fully-formed AppErrorStateInfo record.
8195 */
8196 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8197 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8198 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8199
8200 report.condition = condition;
8201 report.processName = app.processName;
8202 report.pid = app.pid;
8203 report.uid = app.info.uid;
8204 report.tag = tag;
8205 report.shortMsg = shortMsg;
8206 report.longMsg = longMsg;
8207 report.crashData = crashData;
8208
8209 return report;
8210 }
8211
8212 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8213 boolean crashed) {
8214 synchronized (this) {
8215 app.crashing = false;
8216 app.crashingReport = null;
8217 app.notResponding = false;
8218 app.notRespondingReport = null;
8219 if (app.anrDialog == fromDialog) {
8220 app.anrDialog = null;
8221 }
8222 if (app.waitDialog == fromDialog) {
8223 app.waitDialog = null;
8224 }
8225 if (app.pid > 0 && app.pid != MY_PID) {
8226 if (crashed) {
8227 handleAppCrashLocked(app);
8228 }
8229 Log.i(ActivityManagerService.TAG, "Killing process "
8230 + app.processName
8231 + " (pid=" + app.pid + ") at user's request");
8232 Process.killProcess(app.pid);
8233 }
8234
8235 }
8236 }
8237
8238 boolean handleAppCrashLocked(ProcessRecord app) {
8239 long now = SystemClock.uptimeMillis();
8240
8241 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8242 app.info.uid);
8243 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8244 // This process loses!
8245 Log.w(TAG, "Process " + app.info.processName
8246 + " has crashed too many times: killing!");
8247 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8248 app.info.processName, app.info.uid);
8249 killServicesLocked(app, false);
8250 for (int i=mHistory.size()-1; i>=0; i--) {
8251 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8252 if (r.app == app) {
8253 if (Config.LOGD) Log.d(
8254 TAG, " Force finishing activity "
8255 + r.intent.getComponent().flattenToShortString());
8256 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8257 }
8258 }
8259 if (!app.persistent) {
8260 // We don't want to start this process again until the user
8261 // explicitly does so... but for persistent process, we really
8262 // need to keep it running. If a persistent process is actually
8263 // repeatedly crashing, then badness for everyone.
8264 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8265 app.info.processName);
8266 mBadProcesses.put(app.info.processName, app.info.uid, now);
8267 app.bad = true;
8268 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8269 app.removed = true;
8270 removeProcessLocked(app, false);
8271 return false;
8272 }
8273 }
8274
8275 // Bump up the crash count of any services currently running in the proc.
8276 if (app.services.size() != 0) {
8277 // Any services running in the application need to be placed
8278 // back in the pending list.
8279 Iterator it = app.services.iterator();
8280 while (it.hasNext()) {
8281 ServiceRecord sr = (ServiceRecord)it.next();
8282 sr.crashCount++;
8283 }
8284 }
8285
8286 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8287 return true;
8288 }
8289
8290 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008291 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008292 skipCurrentReceiverLocked(app);
8293 }
8294
8295 void skipCurrentReceiverLocked(ProcessRecord app) {
8296 boolean reschedule = false;
8297 BroadcastRecord r = app.curReceiver;
8298 if (r != null) {
8299 // The current broadcast is waiting for this app's receiver
8300 // to be finished. Looks like that's not going to happen, so
8301 // let the broadcast continue.
8302 logBroadcastReceiverDiscard(r);
8303 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8304 r.resultExtras, r.resultAbort, true);
8305 reschedule = true;
8306 }
8307 r = mPendingBroadcast;
8308 if (r != null && r.curApp == app) {
8309 if (DEBUG_BROADCAST) Log.v(TAG,
8310 "skip & discard pending app " + r);
8311 logBroadcastReceiverDiscard(r);
8312 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8313 r.resultExtras, r.resultAbort, true);
8314 reschedule = true;
8315 }
8316 if (reschedule) {
8317 scheduleBroadcastsLocked();
8318 }
8319 }
8320
8321 public int handleApplicationError(IBinder app, int flags,
8322 String tag, String shortMsg, String longMsg, byte[] crashData) {
8323 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008324 ProcessRecord r = null;
8325 synchronized (this) {
8326 if (app != null) {
8327 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8328 final int NA = apps.size();
8329 for (int ia=0; ia<NA; ia++) {
8330 ProcessRecord p = apps.valueAt(ia);
8331 if (p.thread != null && p.thread.asBinder() == app) {
8332 r = p;
8333 break;
8334 }
8335 }
8336 }
8337 }
8338
8339 if (r != null) {
8340 // The application has crashed. Send the SIGQUIT to the process so
8341 // that it can dump its state.
8342 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8343 //Log.i(TAG, "Current system threads:");
8344 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8345 }
8346
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008347 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008348 try {
8349 String name = r != null ? r.processName : null;
8350 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008351 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008352 shortMsg, longMsg, crashData)) {
8353 Log.w(TAG, "Force-killing crashed app " + name
8354 + " at watcher's request");
8355 Process.killProcess(pid);
8356 return 0;
8357 }
8358 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008359 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008360 }
8361 }
8362
8363 final long origId = Binder.clearCallingIdentity();
8364
8365 // If this process is running instrumentation, finish it.
8366 if (r != null && r.instrumentationClass != null) {
8367 Log.w(TAG, "Error in app " + r.processName
8368 + " running instrumentation " + r.instrumentationClass + ":");
8369 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8370 if (longMsg != null) Log.w(TAG, " " + longMsg);
8371 Bundle info = new Bundle();
8372 info.putString("shortMsg", shortMsg);
8373 info.putString("longMsg", longMsg);
8374 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8375 Binder.restoreCallingIdentity(origId);
8376 return 0;
8377 }
8378
8379 if (r != null) {
8380 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8381 return 0;
8382 }
8383 } else {
8384 Log.w(TAG, "Some application object " + app + " tag " + tag
8385 + " has crashed, but I don't know who it is.");
8386 Log.w(TAG, "ShortMsg:" + shortMsg);
8387 Log.w(TAG, "LongMsg:" + longMsg);
8388 Binder.restoreCallingIdentity(origId);
8389 return 0;
8390 }
8391
8392 Message msg = Message.obtain();
8393 msg.what = SHOW_ERROR_MSG;
8394 HashMap data = new HashMap();
8395 data.put("result", result);
8396 data.put("app", r);
8397 data.put("flags", flags);
8398 data.put("shortMsg", shortMsg);
8399 data.put("longMsg", longMsg);
8400 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8401 // For system processes, submit crash data to the server.
8402 data.put("crashData", crashData);
8403 }
8404 msg.obj = data;
8405 mHandler.sendMessage(msg);
8406
8407 Binder.restoreCallingIdentity(origId);
8408 }
8409
8410 int res = result.get();
8411
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008412 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 synchronized (this) {
8414 if (r != null) {
8415 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8416 SystemClock.uptimeMillis());
8417 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008418 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8419 appErrorIntent = createAppErrorIntentLocked(r);
8420 res = AppErrorDialog.FORCE_QUIT;
8421 }
8422 }
8423
8424 if (appErrorIntent != null) {
8425 try {
8426 mContext.startActivity(appErrorIntent);
8427 } catch (ActivityNotFoundException e) {
8428 Log.w(TAG, "bug report receiver dissappeared", e);
8429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008430 }
8431
8432 return res;
8433 }
8434
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008435 Intent createAppErrorIntentLocked(ProcessRecord r) {
8436 ApplicationErrorReport report = createAppErrorReportLocked(r);
8437 if (report == null) {
8438 return null;
8439 }
8440 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8441 result.setComponent(r.errorReportReceiver);
8442 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8443 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8444 return result;
8445 }
8446
8447 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8448 if (r.errorReportReceiver == null) {
8449 return null;
8450 }
8451
8452 if (!r.crashing && !r.notResponding) {
8453 return null;
8454 }
8455
8456 try {
8457 ApplicationErrorReport report = new ApplicationErrorReport();
8458 report.packageName = r.info.packageName;
8459 report.installerPackageName = r.errorReportReceiver.getPackageName();
8460 report.processName = r.processName;
8461
8462 if (r.crashing) {
8463 report.type = ApplicationErrorReport.TYPE_CRASH;
8464 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8465
8466 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8467 r.crashingReport.crashData);
8468 DataInputStream dataStream = new DataInputStream(byteStream);
8469 CrashData crashData = new CrashData(dataStream);
8470 ThrowableData throwData = crashData.getThrowableData();
8471
8472 report.time = crashData.getTime();
8473 report.crashInfo.stackTrace = throwData.toString();
8474
Jacek Surazskif829a782009-06-11 22:47:02 +02008475 // Extract the source of the exception, useful for report
8476 // clustering. Also extract the "deepest" non-null exception
8477 // message.
8478 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008479 while (throwData.getCause() != null) {
8480 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008481 String msg = throwData.getMessage();
8482 if (msg != null && msg.length() > 0) {
8483 exceptionMessage = msg;
8484 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008485 }
8486 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008487 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008488 report.crashInfo.exceptionClassName = throwData.getType();
8489 report.crashInfo.throwFileName = trace.getFileName();
8490 report.crashInfo.throwClassName = trace.getClassName();
8491 report.crashInfo.throwMethodName = trace.getMethodName();
8492 } else if (r.notResponding) {
8493 report.type = ApplicationErrorReport.TYPE_ANR;
8494 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8495
8496 report.anrInfo.activity = r.notRespondingReport.tag;
8497 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8498 report.anrInfo.info = r.notRespondingReport.longMsg;
8499 }
8500
8501 return report;
8502 } catch (IOException e) {
8503 // we don't send it
8504 }
8505
8506 return null;
8507 }
8508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8510 // assume our apps are happy - lazy create the list
8511 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8512
8513 synchronized (this) {
8514
8515 // iterate across all processes
8516 final int N = mLRUProcesses.size();
8517 for (int i = 0; i < N; i++) {
8518 ProcessRecord app = mLRUProcesses.get(i);
8519 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8520 // This one's in trouble, so we'll generate a report for it
8521 // crashes are higher priority (in case there's a crash *and* an anr)
8522 ActivityManager.ProcessErrorStateInfo report = null;
8523 if (app.crashing) {
8524 report = app.crashingReport;
8525 } else if (app.notResponding) {
8526 report = app.notRespondingReport;
8527 }
8528
8529 if (report != null) {
8530 if (errList == null) {
8531 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8532 }
8533 errList.add(report);
8534 } else {
8535 Log.w(TAG, "Missing app error report, app = " + app.processName +
8536 " crashing = " + app.crashing +
8537 " notResponding = " + app.notResponding);
8538 }
8539 }
8540 }
8541 }
8542
8543 return errList;
8544 }
8545
8546 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8547 // Lazy instantiation of list
8548 List<ActivityManager.RunningAppProcessInfo> runList = null;
8549 synchronized (this) {
8550 // Iterate across all processes
8551 final int N = mLRUProcesses.size();
8552 for (int i = 0; i < N; i++) {
8553 ProcessRecord app = mLRUProcesses.get(i);
8554 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8555 // Generate process state info for running application
8556 ActivityManager.RunningAppProcessInfo currApp =
8557 new ActivityManager.RunningAppProcessInfo(app.processName,
8558 app.pid, app.getPackageList());
8559 int adj = app.curAdj;
8560 if (adj >= CONTENT_PROVIDER_ADJ) {
8561 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8562 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8563 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008564 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8565 } else if (adj >= HOME_APP_ADJ) {
8566 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8567 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008568 } else if (adj >= SECONDARY_SERVER_ADJ) {
8569 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8570 } else if (adj >= VISIBLE_APP_ADJ) {
8571 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8572 } else {
8573 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8574 }
8575 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8576 // + " lru=" + currApp.lru);
8577 if (runList == null) {
8578 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8579 }
8580 runList.add(currApp);
8581 }
8582 }
8583 }
8584 return runList;
8585 }
8586
8587 @Override
8588 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8589 synchronized (this) {
8590 if (checkCallingPermission(android.Manifest.permission.DUMP)
8591 != PackageManager.PERMISSION_GRANTED) {
8592 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8593 + Binder.getCallingPid()
8594 + ", uid=" + Binder.getCallingUid()
8595 + " without permission "
8596 + android.Manifest.permission.DUMP);
8597 return;
8598 }
8599 if (args.length != 0 && "service".equals(args[0])) {
8600 dumpService(fd, pw, args);
8601 return;
8602 }
8603 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008604 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008605 pw.println(" ");
8606 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008607 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008608 if (mWaitingVisibleActivities.size() > 0) {
8609 pw.println(" ");
8610 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008611 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008612 }
8613 if (mStoppingActivities.size() > 0) {
8614 pw.println(" ");
8615 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008616 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 }
8618 if (mFinishingActivities.size() > 0) {
8619 pw.println(" ");
8620 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008621 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008622 }
8623
8624 pw.println(" ");
8625 pw.println(" mPausingActivity: " + mPausingActivity);
8626 pw.println(" mResumedActivity: " + mResumedActivity);
8627 pw.println(" mFocusedActivity: " + mFocusedActivity);
8628 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8629
8630 if (mRecentTasks.size() > 0) {
8631 pw.println(" ");
8632 pw.println("Recent tasks in Current Activity Manager State:");
8633
8634 final int N = mRecentTasks.size();
8635 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008636 TaskRecord tr = mRecentTasks.get(i);
8637 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8638 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008639 mRecentTasks.get(i).dump(pw, " ");
8640 }
8641 }
8642
8643 pw.println(" ");
8644 pw.println(" mCurTask: " + mCurTask);
8645
8646 pw.println(" ");
8647 pw.println("Processes in Current Activity Manager State:");
8648
8649 boolean needSep = false;
8650 int numPers = 0;
8651
8652 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8653 final int NA = procs.size();
8654 for (int ia=0; ia<NA; ia++) {
8655 if (!needSep) {
8656 pw.println(" All known processes:");
8657 needSep = true;
8658 }
8659 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008660 pw.print(r.persistent ? " *PERS*" : " *APP*");
8661 pw.print(" UID "); pw.print(procs.keyAt(ia));
8662 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008663 r.dump(pw, " ");
8664 if (r.persistent) {
8665 numPers++;
8666 }
8667 }
8668 }
8669
8670 if (mLRUProcesses.size() > 0) {
8671 if (needSep) pw.println(" ");
8672 needSep = true;
8673 pw.println(" Running processes (most recent first):");
8674 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008675 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008676 needSep = true;
8677 }
8678
8679 synchronized (mPidsSelfLocked) {
8680 if (mPidsSelfLocked.size() > 0) {
8681 if (needSep) pw.println(" ");
8682 needSep = true;
8683 pw.println(" PID mappings:");
8684 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008685 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8686 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008687 }
8688 }
8689 }
8690
8691 if (mForegroundProcesses.size() > 0) {
8692 if (needSep) pw.println(" ");
8693 needSep = true;
8694 pw.println(" Foreground Processes:");
8695 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008696 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8697 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008698 }
8699 }
8700
8701 if (mPersistentStartingProcesses.size() > 0) {
8702 if (needSep) pw.println(" ");
8703 needSep = true;
8704 pw.println(" Persisent processes that are starting:");
8705 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008706 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008707 }
8708
8709 if (mStartingProcesses.size() > 0) {
8710 if (needSep) pw.println(" ");
8711 needSep = true;
8712 pw.println(" Processes that are starting:");
8713 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008714 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008715 }
8716
8717 if (mRemovedProcesses.size() > 0) {
8718 if (needSep) pw.println(" ");
8719 needSep = true;
8720 pw.println(" Processes that are being removed:");
8721 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008722 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008723 }
8724
8725 if (mProcessesOnHold.size() > 0) {
8726 if (needSep) pw.println(" ");
8727 needSep = true;
8728 pw.println(" Processes that are on old until the system is ready:");
8729 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008730 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008731 }
8732
8733 if (mProcessCrashTimes.getMap().size() > 0) {
8734 if (needSep) pw.println(" ");
8735 needSep = true;
8736 pw.println(" Time since processes crashed:");
8737 long now = SystemClock.uptimeMillis();
8738 for (Map.Entry<String, SparseArray<Long>> procs
8739 : mProcessCrashTimes.getMap().entrySet()) {
8740 SparseArray<Long> uids = procs.getValue();
8741 final int N = uids.size();
8742 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008743 pw.print(" Process "); pw.print(procs.getKey());
8744 pw.print(" uid "); pw.print(uids.keyAt(i));
8745 pw.print(": last crashed ");
8746 pw.print((now-uids.valueAt(i)));
8747 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008748 }
8749 }
8750 }
8751
8752 if (mBadProcesses.getMap().size() > 0) {
8753 if (needSep) pw.println(" ");
8754 needSep = true;
8755 pw.println(" Bad processes:");
8756 for (Map.Entry<String, SparseArray<Long>> procs
8757 : mBadProcesses.getMap().entrySet()) {
8758 SparseArray<Long> uids = procs.getValue();
8759 final int N = uids.size();
8760 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008761 pw.print(" Bad process "); pw.print(procs.getKey());
8762 pw.print(" uid "); pw.print(uids.keyAt(i));
8763 pw.print(": crashed at time ");
8764 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008765 }
8766 }
8767 }
8768
8769 pw.println(" ");
8770 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008771 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 pw.println(" mConfiguration: " + mConfiguration);
8773 pw.println(" mStartRunning=" + mStartRunning
8774 + " mSystemReady=" + mSystemReady
8775 + " mBooting=" + mBooting
8776 + " mBooted=" + mBooted
8777 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008778 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008779 pw.println(" mGoingToSleep=" + mGoingToSleep);
8780 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8781 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8782 + " mDebugTransient=" + mDebugTransient
8783 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8784 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008785 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008786 }
8787 }
8788
8789 /**
8790 * There are three ways to call this:
8791 * - no service specified: dump all the services
8792 * - a flattened component name that matched an existing service was specified as the
8793 * first arg: dump that one service
8794 * - the first arg isn't the flattened component name of an existing service:
8795 * dump all services whose component contains the first arg as a substring
8796 */
8797 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8798 String[] newArgs;
8799 String componentNameString;
8800 ServiceRecord r;
8801 if (args.length == 1) {
8802 componentNameString = null;
8803 newArgs = EMPTY_STRING_ARRAY;
8804 r = null;
8805 } else {
8806 componentNameString = args[1];
8807 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8808 r = componentName != null ? mServices.get(componentName) : null;
8809 newArgs = new String[args.length - 2];
8810 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8811 }
8812
8813 if (r != null) {
8814 dumpService(fd, pw, r, newArgs);
8815 } else {
8816 for (ServiceRecord r1 : mServices.values()) {
8817 if (componentNameString == null
8818 || r1.name.flattenToString().contains(componentNameString)) {
8819 dumpService(fd, pw, r1, newArgs);
8820 }
8821 }
8822 }
8823 }
8824
8825 /**
8826 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8827 * there is a thread associated with the service.
8828 */
8829 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8830 pw.println(" Service " + r.name.flattenToString());
8831 if (r.app != null && r.app.thread != null) {
8832 try {
8833 // flush anything that is already in the PrintWriter since the thread is going
8834 // to write to the file descriptor directly
8835 pw.flush();
8836 r.app.thread.dumpService(fd, r, args);
8837 pw.print("\n");
8838 } catch (RemoteException e) {
8839 pw.println("got a RemoteException while dumping the service");
8840 }
8841 }
8842 }
8843
8844 void dumpBroadcasts(PrintWriter pw) {
8845 synchronized (this) {
8846 if (checkCallingPermission(android.Manifest.permission.DUMP)
8847 != PackageManager.PERMISSION_GRANTED) {
8848 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8849 + Binder.getCallingPid()
8850 + ", uid=" + Binder.getCallingUid()
8851 + " without permission "
8852 + android.Manifest.permission.DUMP);
8853 return;
8854 }
8855 pw.println("Broadcasts in Current Activity Manager State:");
8856
8857 if (mRegisteredReceivers.size() > 0) {
8858 pw.println(" ");
8859 pw.println(" Registered Receivers:");
8860 Iterator it = mRegisteredReceivers.values().iterator();
8861 while (it.hasNext()) {
8862 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008863 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008864 r.dump(pw, " ");
8865 }
8866 }
8867
8868 pw.println(" ");
8869 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008870 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008871
8872 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8873 || mPendingBroadcast != null) {
8874 if (mParallelBroadcasts.size() > 0) {
8875 pw.println(" ");
8876 pw.println(" Active broadcasts:");
8877 }
8878 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8879 pw.println(" Broadcast #" + i + ":");
8880 mParallelBroadcasts.get(i).dump(pw, " ");
8881 }
8882 if (mOrderedBroadcasts.size() > 0) {
8883 pw.println(" ");
8884 pw.println(" Active serialized broadcasts:");
8885 }
8886 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8887 pw.println(" Serialized Broadcast #" + i + ":");
8888 mOrderedBroadcasts.get(i).dump(pw, " ");
8889 }
8890 pw.println(" ");
8891 pw.println(" Pending broadcast:");
8892 if (mPendingBroadcast != null) {
8893 mPendingBroadcast.dump(pw, " ");
8894 } else {
8895 pw.println(" (null)");
8896 }
8897 }
8898
8899 pw.println(" ");
8900 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8901 if (mStickyBroadcasts != null) {
8902 pw.println(" ");
8903 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008904 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008905 for (Map.Entry<String, ArrayList<Intent>> ent
8906 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008907 pw.print(" * Sticky action "); pw.print(ent.getKey());
8908 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008909 ArrayList<Intent> intents = ent.getValue();
8910 final int N = intents.size();
8911 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008912 sb.setLength(0);
8913 sb.append(" Intent: ");
8914 intents.get(i).toShortString(sb, true, false);
8915 pw.println(sb.toString());
8916 Bundle bundle = intents.get(i).getExtras();
8917 if (bundle != null) {
8918 pw.print(" ");
8919 pw.println(bundle.toString());
8920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008921 }
8922 }
8923 }
8924
8925 pw.println(" ");
8926 pw.println(" mHandler:");
8927 mHandler.dump(new PrintWriterPrinter(pw), " ");
8928 }
8929 }
8930
8931 void dumpServices(PrintWriter pw) {
8932 synchronized (this) {
8933 if (checkCallingPermission(android.Manifest.permission.DUMP)
8934 != PackageManager.PERMISSION_GRANTED) {
8935 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8936 + Binder.getCallingPid()
8937 + ", uid=" + Binder.getCallingUid()
8938 + " without permission "
8939 + android.Manifest.permission.DUMP);
8940 return;
8941 }
8942 pw.println("Services in Current Activity Manager State:");
8943
8944 boolean needSep = false;
8945
8946 if (mServices.size() > 0) {
8947 pw.println(" Active services:");
8948 Iterator<ServiceRecord> it = mServices.values().iterator();
8949 while (it.hasNext()) {
8950 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008951 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008952 r.dump(pw, " ");
8953 }
8954 needSep = true;
8955 }
8956
8957 if (mPendingServices.size() > 0) {
8958 if (needSep) pw.println(" ");
8959 pw.println(" Pending services:");
8960 for (int i=0; i<mPendingServices.size(); i++) {
8961 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008962 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008963 r.dump(pw, " ");
8964 }
8965 needSep = true;
8966 }
8967
8968 if (mRestartingServices.size() > 0) {
8969 if (needSep) pw.println(" ");
8970 pw.println(" Restarting services:");
8971 for (int i=0; i<mRestartingServices.size(); i++) {
8972 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008973 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008974 r.dump(pw, " ");
8975 }
8976 needSep = true;
8977 }
8978
8979 if (mStoppingServices.size() > 0) {
8980 if (needSep) pw.println(" ");
8981 pw.println(" Stopping services:");
8982 for (int i=0; i<mStoppingServices.size(); i++) {
8983 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008984 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008985 r.dump(pw, " ");
8986 }
8987 needSep = true;
8988 }
8989
8990 if (mServiceConnections.size() > 0) {
8991 if (needSep) pw.println(" ");
8992 pw.println(" Connection bindings to services:");
8993 Iterator<ConnectionRecord> it
8994 = mServiceConnections.values().iterator();
8995 while (it.hasNext()) {
8996 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008997 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008998 r.dump(pw, " ");
8999 }
9000 }
9001 }
9002 }
9003
9004 void dumpProviders(PrintWriter pw) {
9005 synchronized (this) {
9006 if (checkCallingPermission(android.Manifest.permission.DUMP)
9007 != PackageManager.PERMISSION_GRANTED) {
9008 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9009 + Binder.getCallingPid()
9010 + ", uid=" + Binder.getCallingUid()
9011 + " without permission "
9012 + android.Manifest.permission.DUMP);
9013 return;
9014 }
9015
9016 pw.println("Content Providers in Current Activity Manager State:");
9017
9018 boolean needSep = false;
9019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009020 if (mProvidersByClass.size() > 0) {
9021 if (needSep) pw.println(" ");
9022 pw.println(" Published content providers (by class):");
9023 Iterator it = mProvidersByClass.entrySet().iterator();
9024 while (it.hasNext()) {
9025 Map.Entry e = (Map.Entry)it.next();
9026 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009027 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009028 r.dump(pw, " ");
9029 }
9030 needSep = true;
9031 }
9032
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009033 if (mProvidersByName.size() > 0) {
9034 pw.println(" ");
9035 pw.println(" Authority to provider mappings:");
9036 Iterator it = mProvidersByName.entrySet().iterator();
9037 while (it.hasNext()) {
9038 Map.Entry e = (Map.Entry)it.next();
9039 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9040 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9041 pw.println(r);
9042 }
9043 needSep = true;
9044 }
9045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009046 if (mLaunchingProviders.size() > 0) {
9047 if (needSep) pw.println(" ");
9048 pw.println(" Launching content providers:");
9049 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009050 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9051 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009052 }
9053 needSep = true;
9054 }
9055
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009056 if (mGrantedUriPermissions.size() > 0) {
9057 pw.println();
9058 pw.println("Granted Uri Permissions:");
9059 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9060 int uid = mGrantedUriPermissions.keyAt(i);
9061 HashMap<Uri, UriPermission> perms
9062 = mGrantedUriPermissions.valueAt(i);
9063 pw.print(" * UID "); pw.print(uid);
9064 pw.println(" holds:");
9065 for (UriPermission perm : perms.values()) {
9066 pw.print(" "); pw.println(perm);
9067 perm.dump(pw, " ");
9068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009069 }
9070 }
9071 }
9072 }
9073
9074 void dumpSenders(PrintWriter pw) {
9075 synchronized (this) {
9076 if (checkCallingPermission(android.Manifest.permission.DUMP)
9077 != PackageManager.PERMISSION_GRANTED) {
9078 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9079 + Binder.getCallingPid()
9080 + ", uid=" + Binder.getCallingUid()
9081 + " without permission "
9082 + android.Manifest.permission.DUMP);
9083 return;
9084 }
9085
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009086 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009087
9088 if (this.mIntentSenderRecords.size() > 0) {
9089 Iterator<WeakReference<PendingIntentRecord>> it
9090 = mIntentSenderRecords.values().iterator();
9091 while (it.hasNext()) {
9092 WeakReference<PendingIntentRecord> ref = it.next();
9093 PendingIntentRecord rec = ref != null ? ref.get(): null;
9094 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009095 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009096 rec.dump(pw, " ");
9097 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009098 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009099 }
9100 }
9101 }
9102 }
9103 }
9104
9105 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009106 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009107 TaskRecord lastTask = null;
9108 for (int i=list.size()-1; i>=0; i--) {
9109 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009110 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009111 if (lastTask != r.task) {
9112 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009113 pw.print(prefix);
9114 pw.print(full ? "* " : " ");
9115 pw.println(lastTask);
9116 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009117 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009119 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009120 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9121 pw.print(" #"); pw.print(i); pw.print(": ");
9122 pw.println(r);
9123 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009124 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009126 }
9127 }
9128
9129 private static final int dumpProcessList(PrintWriter pw, List list,
9130 String prefix, String normalLabel, String persistentLabel,
9131 boolean inclOomAdj) {
9132 int numPers = 0;
9133 for (int i=list.size()-1; i>=0; i--) {
9134 ProcessRecord r = (ProcessRecord)list.get(i);
9135 if (false) {
9136 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9137 + " #" + i + ":");
9138 r.dump(pw, prefix + " ");
9139 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009140 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009141 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009142 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009143 } else {
9144 pw.println(String.format("%s%s #%2d: %s",
9145 prefix, (r.persistent ? persistentLabel : normalLabel),
9146 i, r.toString()));
9147 }
9148 if (r.persistent) {
9149 numPers++;
9150 }
9151 }
9152 return numPers;
9153 }
9154
9155 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9156 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009157 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009158 long uptime = SystemClock.uptimeMillis();
9159 long realtime = SystemClock.elapsedRealtime();
9160
9161 if (isCheckinRequest) {
9162 // short checkin version
9163 pw.println(uptime + "," + realtime);
9164 pw.flush();
9165 } else {
9166 pw.println("Applications Memory Usage (kB):");
9167 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9168 }
9169 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9170 ProcessRecord r = (ProcessRecord)list.get(i);
9171 if (r.thread != null) {
9172 if (!isCheckinRequest) {
9173 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9174 pw.flush();
9175 }
9176 try {
9177 r.thread.asBinder().dump(fd, args);
9178 } catch (RemoteException e) {
9179 if (!isCheckinRequest) {
9180 pw.println("Got RemoteException!");
9181 pw.flush();
9182 }
9183 }
9184 }
9185 }
9186 }
9187
9188 /**
9189 * Searches array of arguments for the specified string
9190 * @param args array of argument strings
9191 * @param value value to search for
9192 * @return true if the value is contained in the array
9193 */
9194 private static boolean scanArgs(String[] args, String value) {
9195 if (args != null) {
9196 for (String arg : args) {
9197 if (value.equals(arg)) {
9198 return true;
9199 }
9200 }
9201 }
9202 return false;
9203 }
9204
Dianne Hackborn75b03852009-06-12 15:43:26 -07009205 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009206 int count = mHistory.size();
9207
9208 // convert the token to an entry in the history.
9209 HistoryRecord r = null;
9210 int index = -1;
9211 for (int i=count-1; i>=0; i--) {
9212 Object o = mHistory.get(i);
9213 if (o == token) {
9214 r = (HistoryRecord)o;
9215 index = i;
9216 break;
9217 }
9218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009219
9220 return index;
9221 }
9222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009223 private final void killServicesLocked(ProcessRecord app,
9224 boolean allowRestart) {
9225 // Report disconnected services.
9226 if (false) {
9227 // XXX we are letting the client link to the service for
9228 // death notifications.
9229 if (app.services.size() > 0) {
9230 Iterator it = app.services.iterator();
9231 while (it.hasNext()) {
9232 ServiceRecord r = (ServiceRecord)it.next();
9233 if (r.connections.size() > 0) {
9234 Iterator<ConnectionRecord> jt
9235 = r.connections.values().iterator();
9236 while (jt.hasNext()) {
9237 ConnectionRecord c = jt.next();
9238 if (c.binding.client != app) {
9239 try {
9240 //c.conn.connected(r.className, null);
9241 } catch (Exception e) {
9242 // todo: this should be asynchronous!
9243 Log.w(TAG, "Exception thrown disconnected servce "
9244 + r.shortName
9245 + " from app " + app.processName, e);
9246 }
9247 }
9248 }
9249 }
9250 }
9251 }
9252 }
9253
9254 // Clean up any connections this application has to other services.
9255 if (app.connections.size() > 0) {
9256 Iterator<ConnectionRecord> it = app.connections.iterator();
9257 while (it.hasNext()) {
9258 ConnectionRecord r = it.next();
9259 removeConnectionLocked(r, app, null);
9260 }
9261 }
9262 app.connections.clear();
9263
9264 if (app.services.size() != 0) {
9265 // Any services running in the application need to be placed
9266 // back in the pending list.
9267 Iterator it = app.services.iterator();
9268 while (it.hasNext()) {
9269 ServiceRecord sr = (ServiceRecord)it.next();
9270 synchronized (sr.stats.getBatteryStats()) {
9271 sr.stats.stopLaunchedLocked();
9272 }
9273 sr.app = null;
9274 sr.executeNesting = 0;
9275 mStoppingServices.remove(sr);
9276 if (sr.bindings.size() > 0) {
9277 Iterator<IntentBindRecord> bindings
9278 = sr.bindings.values().iterator();
9279 while (bindings.hasNext()) {
9280 IntentBindRecord b = bindings.next();
9281 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9282 + ": shouldUnbind=" + b.hasBound);
9283 b.binder = null;
9284 b.requested = b.received = b.hasBound = false;
9285 }
9286 }
9287
9288 if (sr.crashCount >= 2) {
9289 Log.w(TAG, "Service crashed " + sr.crashCount
9290 + " times, stopping: " + sr);
9291 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9292 sr.crashCount, sr.shortName, app.pid);
9293 bringDownServiceLocked(sr, true);
9294 } else if (!allowRestart) {
9295 bringDownServiceLocked(sr, true);
9296 } else {
9297 scheduleServiceRestartLocked(sr);
9298 }
9299 }
9300
9301 if (!allowRestart) {
9302 app.services.clear();
9303 }
9304 }
9305
9306 app.executingServices.clear();
9307 }
9308
9309 private final void removeDyingProviderLocked(ProcessRecord proc,
9310 ContentProviderRecord cpr) {
9311 synchronized (cpr) {
9312 cpr.launchingApp = null;
9313 cpr.notifyAll();
9314 }
9315
9316 mProvidersByClass.remove(cpr.info.name);
9317 String names[] = cpr.info.authority.split(";");
9318 for (int j = 0; j < names.length; j++) {
9319 mProvidersByName.remove(names[j]);
9320 }
9321
9322 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9323 while (cit.hasNext()) {
9324 ProcessRecord capp = cit.next();
9325 if (!capp.persistent && capp.thread != null
9326 && capp.pid != 0
9327 && capp.pid != MY_PID) {
9328 Log.i(TAG, "Killing app " + capp.processName
9329 + " (pid " + capp.pid
9330 + ") because provider " + cpr.info.name
9331 + " is in dying process " + proc.processName);
9332 Process.killProcess(capp.pid);
9333 }
9334 }
9335
9336 mLaunchingProviders.remove(cpr);
9337 }
9338
9339 /**
9340 * Main code for cleaning up a process when it has gone away. This is
9341 * called both as a result of the process dying, or directly when stopping
9342 * a process when running in single process mode.
9343 */
9344 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9345 boolean restarting, int index) {
9346 if (index >= 0) {
9347 mLRUProcesses.remove(index);
9348 }
9349
9350 // Dismiss any open dialogs.
9351 if (app.crashDialog != null) {
9352 app.crashDialog.dismiss();
9353 app.crashDialog = null;
9354 }
9355 if (app.anrDialog != null) {
9356 app.anrDialog.dismiss();
9357 app.anrDialog = null;
9358 }
9359 if (app.waitDialog != null) {
9360 app.waitDialog.dismiss();
9361 app.waitDialog = null;
9362 }
9363
9364 app.crashing = false;
9365 app.notResponding = false;
9366
9367 app.resetPackageList();
9368 app.thread = null;
9369 app.forcingToForeground = null;
9370 app.foregroundServices = false;
9371
9372 killServicesLocked(app, true);
9373
9374 boolean restart = false;
9375
9376 int NL = mLaunchingProviders.size();
9377
9378 // Remove published content providers.
9379 if (!app.pubProviders.isEmpty()) {
9380 Iterator it = app.pubProviders.values().iterator();
9381 while (it.hasNext()) {
9382 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9383 cpr.provider = null;
9384 cpr.app = null;
9385
9386 // See if someone is waiting for this provider... in which
9387 // case we don't remove it, but just let it restart.
9388 int i = 0;
9389 if (!app.bad) {
9390 for (; i<NL; i++) {
9391 if (mLaunchingProviders.get(i) == cpr) {
9392 restart = true;
9393 break;
9394 }
9395 }
9396 } else {
9397 i = NL;
9398 }
9399
9400 if (i >= NL) {
9401 removeDyingProviderLocked(app, cpr);
9402 NL = mLaunchingProviders.size();
9403 }
9404 }
9405 app.pubProviders.clear();
9406 }
9407
9408 // Look through the content providers we are waiting to have launched,
9409 // and if any run in this process then either schedule a restart of
9410 // the process or kill the client waiting for it if this process has
9411 // gone bad.
9412 for (int i=0; i<NL; i++) {
9413 ContentProviderRecord cpr = (ContentProviderRecord)
9414 mLaunchingProviders.get(i);
9415 if (cpr.launchingApp == app) {
9416 if (!app.bad) {
9417 restart = true;
9418 } else {
9419 removeDyingProviderLocked(app, cpr);
9420 NL = mLaunchingProviders.size();
9421 }
9422 }
9423 }
9424
9425 // Unregister from connected content providers.
9426 if (!app.conProviders.isEmpty()) {
9427 Iterator it = app.conProviders.iterator();
9428 while (it.hasNext()) {
9429 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9430 cpr.clients.remove(app);
9431 }
9432 app.conProviders.clear();
9433 }
9434
9435 skipCurrentReceiverLocked(app);
9436
9437 // Unregister any receivers.
9438 if (app.receivers.size() > 0) {
9439 Iterator<ReceiverList> it = app.receivers.iterator();
9440 while (it.hasNext()) {
9441 removeReceiverLocked(it.next());
9442 }
9443 app.receivers.clear();
9444 }
9445
Christopher Tate181fafa2009-05-14 11:12:14 -07009446 // If the app is undergoing backup, tell the backup manager about it
9447 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9448 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9449 try {
9450 IBackupManager bm = IBackupManager.Stub.asInterface(
9451 ServiceManager.getService(Context.BACKUP_SERVICE));
9452 bm.agentDisconnected(app.info.packageName);
9453 } catch (RemoteException e) {
9454 // can't happen; backup manager is local
9455 }
9456 }
9457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009458 // If the caller is restarting this app, then leave it in its
9459 // current lists and let the caller take care of it.
9460 if (restarting) {
9461 return;
9462 }
9463
9464 if (!app.persistent) {
9465 if (DEBUG_PROCESSES) Log.v(TAG,
9466 "Removing non-persistent process during cleanup: " + app);
9467 mProcessNames.remove(app.processName, app.info.uid);
9468 } else if (!app.removed) {
9469 // This app is persistent, so we need to keep its record around.
9470 // If it is not already on the pending app list, add it there
9471 // and start a new process for it.
9472 app.thread = null;
9473 app.forcingToForeground = null;
9474 app.foregroundServices = false;
9475 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9476 mPersistentStartingProcesses.add(app);
9477 restart = true;
9478 }
9479 }
9480 mProcessesOnHold.remove(app);
9481
The Android Open Source Project4df24232009-03-05 14:34:35 -08009482 if (app == mHomeProcess) {
9483 mHomeProcess = null;
9484 }
9485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009486 if (restart) {
9487 // We have components that still need to be running in the
9488 // process, so re-launch it.
9489 mProcessNames.put(app.processName, app.info.uid, app);
9490 startProcessLocked(app, "restart", app.processName);
9491 } else if (app.pid > 0 && app.pid != MY_PID) {
9492 // Goodbye!
9493 synchronized (mPidsSelfLocked) {
9494 mPidsSelfLocked.remove(app.pid);
9495 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9496 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009497 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009498 }
9499 }
9500
9501 // =========================================================
9502 // SERVICES
9503 // =========================================================
9504
9505 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9506 ActivityManager.RunningServiceInfo info =
9507 new ActivityManager.RunningServiceInfo();
9508 info.service = r.name;
9509 if (r.app != null) {
9510 info.pid = r.app.pid;
9511 }
9512 info.process = r.processName;
9513 info.foreground = r.isForeground;
9514 info.activeSince = r.createTime;
9515 info.started = r.startRequested;
9516 info.clientCount = r.connections.size();
9517 info.crashCount = r.crashCount;
9518 info.lastActivityTime = r.lastActivity;
9519 return info;
9520 }
9521
9522 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9523 int flags) {
9524 synchronized (this) {
9525 ArrayList<ActivityManager.RunningServiceInfo> res
9526 = new ArrayList<ActivityManager.RunningServiceInfo>();
9527
9528 if (mServices.size() > 0) {
9529 Iterator<ServiceRecord> it = mServices.values().iterator();
9530 while (it.hasNext() && res.size() < maxNum) {
9531 res.add(makeRunningServiceInfoLocked(it.next()));
9532 }
9533 }
9534
9535 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9536 ServiceRecord r = mRestartingServices.get(i);
9537 ActivityManager.RunningServiceInfo info =
9538 makeRunningServiceInfoLocked(r);
9539 info.restarting = r.nextRestartTime;
9540 res.add(info);
9541 }
9542
9543 return res;
9544 }
9545 }
9546
9547 private final ServiceRecord findServiceLocked(ComponentName name,
9548 IBinder token) {
9549 ServiceRecord r = mServices.get(name);
9550 return r == token ? r : null;
9551 }
9552
9553 private final class ServiceLookupResult {
9554 final ServiceRecord record;
9555 final String permission;
9556
9557 ServiceLookupResult(ServiceRecord _record, String _permission) {
9558 record = _record;
9559 permission = _permission;
9560 }
9561 };
9562
9563 private ServiceLookupResult findServiceLocked(Intent service,
9564 String resolvedType) {
9565 ServiceRecord r = null;
9566 if (service.getComponent() != null) {
9567 r = mServices.get(service.getComponent());
9568 }
9569 if (r == null) {
9570 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9571 r = mServicesByIntent.get(filter);
9572 }
9573
9574 if (r == null) {
9575 try {
9576 ResolveInfo rInfo =
9577 ActivityThread.getPackageManager().resolveService(
9578 service, resolvedType, 0);
9579 ServiceInfo sInfo =
9580 rInfo != null ? rInfo.serviceInfo : null;
9581 if (sInfo == null) {
9582 return null;
9583 }
9584
9585 ComponentName name = new ComponentName(
9586 sInfo.applicationInfo.packageName, sInfo.name);
9587 r = mServices.get(name);
9588 } catch (RemoteException ex) {
9589 // pm is in same process, this will never happen.
9590 }
9591 }
9592 if (r != null) {
9593 int callingPid = Binder.getCallingPid();
9594 int callingUid = Binder.getCallingUid();
9595 if (checkComponentPermission(r.permission,
9596 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9597 != PackageManager.PERMISSION_GRANTED) {
9598 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9599 + " from pid=" + callingPid
9600 + ", uid=" + callingUid
9601 + " requires " + r.permission);
9602 return new ServiceLookupResult(null, r.permission);
9603 }
9604 return new ServiceLookupResult(r, null);
9605 }
9606 return null;
9607 }
9608
9609 private class ServiceRestarter implements Runnable {
9610 private ServiceRecord mService;
9611
9612 void setService(ServiceRecord service) {
9613 mService = service;
9614 }
9615
9616 public void run() {
9617 synchronized(ActivityManagerService.this) {
9618 performServiceRestartLocked(mService);
9619 }
9620 }
9621 }
9622
9623 private ServiceLookupResult retrieveServiceLocked(Intent service,
9624 String resolvedType, int callingPid, int callingUid) {
9625 ServiceRecord r = null;
9626 if (service.getComponent() != null) {
9627 r = mServices.get(service.getComponent());
9628 }
9629 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9630 r = mServicesByIntent.get(filter);
9631 if (r == null) {
9632 try {
9633 ResolveInfo rInfo =
9634 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009635 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009636 ServiceInfo sInfo =
9637 rInfo != null ? rInfo.serviceInfo : null;
9638 if (sInfo == null) {
9639 Log.w(TAG, "Unable to start service " + service +
9640 ": not found");
9641 return null;
9642 }
9643
9644 ComponentName name = new ComponentName(
9645 sInfo.applicationInfo.packageName, sInfo.name);
9646 r = mServices.get(name);
9647 if (r == null) {
9648 filter = new Intent.FilterComparison(service.cloneFilter());
9649 ServiceRestarter res = new ServiceRestarter();
9650 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9651 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9652 synchronized (stats) {
9653 ss = stats.getServiceStatsLocked(
9654 sInfo.applicationInfo.uid, sInfo.packageName,
9655 sInfo.name);
9656 }
9657 r = new ServiceRecord(ss, name, filter, sInfo, res);
9658 res.setService(r);
9659 mServices.put(name, r);
9660 mServicesByIntent.put(filter, r);
9661
9662 // Make sure this component isn't in the pending list.
9663 int N = mPendingServices.size();
9664 for (int i=0; i<N; i++) {
9665 ServiceRecord pr = mPendingServices.get(i);
9666 if (pr.name.equals(name)) {
9667 mPendingServices.remove(i);
9668 i--;
9669 N--;
9670 }
9671 }
9672 }
9673 } catch (RemoteException ex) {
9674 // pm is in same process, this will never happen.
9675 }
9676 }
9677 if (r != null) {
9678 if (checkComponentPermission(r.permission,
9679 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9680 != PackageManager.PERMISSION_GRANTED) {
9681 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9682 + " from pid=" + Binder.getCallingPid()
9683 + ", uid=" + Binder.getCallingUid()
9684 + " requires " + r.permission);
9685 return new ServiceLookupResult(null, r.permission);
9686 }
9687 return new ServiceLookupResult(r, null);
9688 }
9689 return null;
9690 }
9691
9692 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9693 long now = SystemClock.uptimeMillis();
9694 if (r.executeNesting == 0 && r.app != null) {
9695 if (r.app.executingServices.size() == 0) {
9696 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9697 msg.obj = r.app;
9698 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9699 }
9700 r.app.executingServices.add(r);
9701 }
9702 r.executeNesting++;
9703 r.executingStart = now;
9704 }
9705
9706 private final void sendServiceArgsLocked(ServiceRecord r,
9707 boolean oomAdjusted) {
9708 final int N = r.startArgs.size();
9709 if (N == 0) {
9710 return;
9711 }
9712
9713 final int BASEID = r.lastStartId - N + 1;
9714 int i = 0;
9715 while (i < N) {
9716 try {
9717 Intent args = r.startArgs.get(i);
9718 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9719 + r.name + " " + r.intent + " args=" + args);
9720 bumpServiceExecutingLocked(r);
9721 if (!oomAdjusted) {
9722 oomAdjusted = true;
9723 updateOomAdjLocked(r.app);
9724 }
9725 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9726 i++;
9727 } catch (Exception e) {
9728 break;
9729 }
9730 }
9731 if (i == N) {
9732 r.startArgs.clear();
9733 } else {
9734 while (i > 0) {
9735 r.startArgs.remove(0);
9736 i--;
9737 }
9738 }
9739 }
9740
9741 private final boolean requestServiceBindingLocked(ServiceRecord r,
9742 IntentBindRecord i, boolean rebind) {
9743 if (r.app == null || r.app.thread == null) {
9744 // If service is not currently running, can't yet bind.
9745 return false;
9746 }
9747 if ((!i.requested || rebind) && i.apps.size() > 0) {
9748 try {
9749 bumpServiceExecutingLocked(r);
9750 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9751 + ": shouldUnbind=" + i.hasBound);
9752 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9753 if (!rebind) {
9754 i.requested = true;
9755 }
9756 i.hasBound = true;
9757 i.doRebind = false;
9758 } catch (RemoteException e) {
9759 return false;
9760 }
9761 }
9762 return true;
9763 }
9764
9765 private final void requestServiceBindingsLocked(ServiceRecord r) {
9766 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9767 while (bindings.hasNext()) {
9768 IntentBindRecord i = bindings.next();
9769 if (!requestServiceBindingLocked(r, i, false)) {
9770 break;
9771 }
9772 }
9773 }
9774
9775 private final void realStartServiceLocked(ServiceRecord r,
9776 ProcessRecord app) throws RemoteException {
9777 if (app.thread == null) {
9778 throw new RemoteException();
9779 }
9780
9781 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009782 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009783
9784 app.services.add(r);
9785 bumpServiceExecutingLocked(r);
9786 updateLRUListLocked(app, true);
9787
9788 boolean created = false;
9789 try {
9790 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9791 + r.name + " " + r.intent);
9792 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9793 System.identityHashCode(r), r.shortName,
9794 r.intent.getIntent().toString(), r.app.pid);
9795 synchronized (r.stats.getBatteryStats()) {
9796 r.stats.startLaunchedLocked();
9797 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009798 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009799 app.thread.scheduleCreateService(r, r.serviceInfo);
9800 created = true;
9801 } finally {
9802 if (!created) {
9803 app.services.remove(r);
9804 scheduleServiceRestartLocked(r);
9805 }
9806 }
9807
9808 requestServiceBindingsLocked(r);
9809 sendServiceArgsLocked(r, true);
9810 }
9811
9812 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9813 r.totalRestartCount++;
9814 if (r.restartDelay == 0) {
9815 r.restartCount++;
9816 r.restartDelay = SERVICE_RESTART_DURATION;
9817 } else {
9818 // If it has been a "reasonably long time" since the service
9819 // was started, then reset our restart duration back to
9820 // the beginning, so we don't infinitely increase the duration
9821 // on a service that just occasionally gets killed (which is
9822 // a normal case, due to process being killed to reclaim memory).
9823 long now = SystemClock.uptimeMillis();
9824 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9825 r.restartCount = 1;
9826 r.restartDelay = SERVICE_RESTART_DURATION;
9827 } else {
9828 r.restartDelay *= 2;
9829 }
9830 }
9831 if (!mRestartingServices.contains(r)) {
9832 mRestartingServices.add(r);
9833 }
9834 mHandler.removeCallbacks(r.restarter);
9835 mHandler.postDelayed(r.restarter, r.restartDelay);
9836 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9837 Log.w(TAG, "Scheduling restart of crashed service "
9838 + r.shortName + " in " + r.restartDelay + "ms");
9839 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9840 r.shortName, r.restartDelay);
9841
9842 Message msg = Message.obtain();
9843 msg.what = SERVICE_ERROR_MSG;
9844 msg.obj = r;
9845 mHandler.sendMessage(msg);
9846 }
9847
9848 final void performServiceRestartLocked(ServiceRecord r) {
9849 if (!mRestartingServices.contains(r)) {
9850 return;
9851 }
9852 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9853 }
9854
9855 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9856 if (r.restartDelay == 0) {
9857 return false;
9858 }
9859 r.resetRestartCounter();
9860 mRestartingServices.remove(r);
9861 mHandler.removeCallbacks(r.restarter);
9862 return true;
9863 }
9864
9865 private final boolean bringUpServiceLocked(ServiceRecord r,
9866 int intentFlags, boolean whileRestarting) {
9867 //Log.i(TAG, "Bring up service:");
9868 //r.dump(" ");
9869
9870 if (r.app != null) {
9871 sendServiceArgsLocked(r, false);
9872 return true;
9873 }
9874
9875 if (!whileRestarting && r.restartDelay > 0) {
9876 // If waiting for a restart, then do nothing.
9877 return true;
9878 }
9879
9880 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9881 + " " + r.intent);
9882
9883 final String appName = r.processName;
9884 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9885 if (app != null && app.thread != null) {
9886 try {
9887 realStartServiceLocked(r, app);
9888 return true;
9889 } catch (RemoteException e) {
9890 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9891 }
9892
9893 // If a dead object exception was thrown -- fall through to
9894 // restart the application.
9895 }
9896
9897 if (!mPendingServices.contains(r)) {
9898 // Not running -- get it started, and enqueue this service record
9899 // to be executed when the app comes up.
9900 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9901 "service", r.name) == null) {
9902 Log.w(TAG, "Unable to launch app "
9903 + r.appInfo.packageName + "/"
9904 + r.appInfo.uid + " for service "
9905 + r.intent.getIntent() + ": process is bad");
9906 bringDownServiceLocked(r, true);
9907 return false;
9908 }
9909 mPendingServices.add(r);
9910 }
9911 return true;
9912 }
9913
9914 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9915 //Log.i(TAG, "Bring down service:");
9916 //r.dump(" ");
9917
9918 // Does it still need to run?
9919 if (!force && r.startRequested) {
9920 return;
9921 }
9922 if (r.connections.size() > 0) {
9923 if (!force) {
9924 // XXX should probably keep a count of the number of auto-create
9925 // connections directly in the service.
9926 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9927 while (it.hasNext()) {
9928 ConnectionRecord cr = it.next();
9929 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9930 return;
9931 }
9932 }
9933 }
9934
9935 // Report to all of the connections that the service is no longer
9936 // available.
9937 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9938 while (it.hasNext()) {
9939 ConnectionRecord c = it.next();
9940 try {
9941 // todo: shouldn't be a synchronous call!
9942 c.conn.connected(r.name, null);
9943 } catch (Exception e) {
9944 Log.w(TAG, "Failure disconnecting service " + r.name +
9945 " to connection " + c.conn.asBinder() +
9946 " (in " + c.binding.client.processName + ")", e);
9947 }
9948 }
9949 }
9950
9951 // Tell the service that it has been unbound.
9952 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9953 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9954 while (it.hasNext()) {
9955 IntentBindRecord ibr = it.next();
9956 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9957 + ": hasBound=" + ibr.hasBound);
9958 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9959 try {
9960 bumpServiceExecutingLocked(r);
9961 updateOomAdjLocked(r.app);
9962 ibr.hasBound = false;
9963 r.app.thread.scheduleUnbindService(r,
9964 ibr.intent.getIntent());
9965 } catch (Exception e) {
9966 Log.w(TAG, "Exception when unbinding service "
9967 + r.shortName, e);
9968 serviceDoneExecutingLocked(r, true);
9969 }
9970 }
9971 }
9972 }
9973
9974 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9975 + " " + r.intent);
9976 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9977 System.identityHashCode(r), r.shortName,
9978 (r.app != null) ? r.app.pid : -1);
9979
9980 mServices.remove(r.name);
9981 mServicesByIntent.remove(r.intent);
9982 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9983 r.totalRestartCount = 0;
9984 unscheduleServiceRestartLocked(r);
9985
9986 // Also make sure it is not on the pending list.
9987 int N = mPendingServices.size();
9988 for (int i=0; i<N; i++) {
9989 if (mPendingServices.get(i) == r) {
9990 mPendingServices.remove(i);
9991 if (DEBUG_SERVICE) Log.v(
9992 TAG, "Removed pending service: " + r.shortName);
9993 i--;
9994 N--;
9995 }
9996 }
9997
9998 if (r.app != null) {
9999 synchronized (r.stats.getBatteryStats()) {
10000 r.stats.stopLaunchedLocked();
10001 }
10002 r.app.services.remove(r);
10003 if (r.app.thread != null) {
10004 updateServiceForegroundLocked(r.app, false);
10005 try {
10006 Log.i(TAG, "Stopping service: " + r.shortName);
10007 bumpServiceExecutingLocked(r);
10008 mStoppingServices.add(r);
10009 updateOomAdjLocked(r.app);
10010 r.app.thread.scheduleStopService(r);
10011 } catch (Exception e) {
10012 Log.w(TAG, "Exception when stopping service "
10013 + r.shortName, e);
10014 serviceDoneExecutingLocked(r, true);
10015 }
10016 } else {
10017 if (DEBUG_SERVICE) Log.v(
10018 TAG, "Removed service that has no process: " + r.shortName);
10019 }
10020 } else {
10021 if (DEBUG_SERVICE) Log.v(
10022 TAG, "Removed service that is not running: " + r.shortName);
10023 }
10024 }
10025
10026 ComponentName startServiceLocked(IApplicationThread caller,
10027 Intent service, String resolvedType,
10028 int callingPid, int callingUid) {
10029 synchronized(this) {
10030 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10031 + " type=" + resolvedType + " args=" + service.getExtras());
10032
10033 if (caller != null) {
10034 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10035 if (callerApp == null) {
10036 throw new SecurityException(
10037 "Unable to find app for caller " + caller
10038 + " (pid=" + Binder.getCallingPid()
10039 + ") when starting service " + service);
10040 }
10041 }
10042
10043 ServiceLookupResult res =
10044 retrieveServiceLocked(service, resolvedType,
10045 callingPid, callingUid);
10046 if (res == null) {
10047 return null;
10048 }
10049 if (res.record == null) {
10050 return new ComponentName("!", res.permission != null
10051 ? res.permission : "private to package");
10052 }
10053 ServiceRecord r = res.record;
10054 if (unscheduleServiceRestartLocked(r)) {
10055 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10056 + r.shortName);
10057 }
10058 r.startRequested = true;
10059 r.startArgs.add(service);
10060 r.lastStartId++;
10061 if (r.lastStartId < 1) {
10062 r.lastStartId = 1;
10063 }
10064 r.lastActivity = SystemClock.uptimeMillis();
10065 synchronized (r.stats.getBatteryStats()) {
10066 r.stats.startRunningLocked();
10067 }
10068 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10069 return new ComponentName("!", "Service process is bad");
10070 }
10071 return r.name;
10072 }
10073 }
10074
10075 public ComponentName startService(IApplicationThread caller, Intent service,
10076 String resolvedType) {
10077 // Refuse possible leaked file descriptors
10078 if (service != null && service.hasFileDescriptors() == true) {
10079 throw new IllegalArgumentException("File descriptors passed in Intent");
10080 }
10081
10082 synchronized(this) {
10083 final int callingPid = Binder.getCallingPid();
10084 final int callingUid = Binder.getCallingUid();
10085 final long origId = Binder.clearCallingIdentity();
10086 ComponentName res = startServiceLocked(caller, service,
10087 resolvedType, callingPid, callingUid);
10088 Binder.restoreCallingIdentity(origId);
10089 return res;
10090 }
10091 }
10092
10093 ComponentName startServiceInPackage(int uid,
10094 Intent service, String resolvedType) {
10095 synchronized(this) {
10096 final long origId = Binder.clearCallingIdentity();
10097 ComponentName res = startServiceLocked(null, service,
10098 resolvedType, -1, uid);
10099 Binder.restoreCallingIdentity(origId);
10100 return res;
10101 }
10102 }
10103
10104 public int stopService(IApplicationThread caller, Intent service,
10105 String resolvedType) {
10106 // Refuse possible leaked file descriptors
10107 if (service != null && service.hasFileDescriptors() == true) {
10108 throw new IllegalArgumentException("File descriptors passed in Intent");
10109 }
10110
10111 synchronized(this) {
10112 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10113 + " type=" + resolvedType);
10114
10115 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10116 if (caller != null && callerApp == null) {
10117 throw new SecurityException(
10118 "Unable to find app for caller " + caller
10119 + " (pid=" + Binder.getCallingPid()
10120 + ") when stopping service " + service);
10121 }
10122
10123 // If this service is active, make sure it is stopped.
10124 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10125 if (r != null) {
10126 if (r.record != null) {
10127 synchronized (r.record.stats.getBatteryStats()) {
10128 r.record.stats.stopRunningLocked();
10129 }
10130 r.record.startRequested = false;
10131 final long origId = Binder.clearCallingIdentity();
10132 bringDownServiceLocked(r.record, false);
10133 Binder.restoreCallingIdentity(origId);
10134 return 1;
10135 }
10136 return -1;
10137 }
10138 }
10139
10140 return 0;
10141 }
10142
10143 public IBinder peekService(Intent service, String resolvedType) {
10144 // Refuse possible leaked file descriptors
10145 if (service != null && service.hasFileDescriptors() == true) {
10146 throw new IllegalArgumentException("File descriptors passed in Intent");
10147 }
10148
10149 IBinder ret = null;
10150
10151 synchronized(this) {
10152 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10153
10154 if (r != null) {
10155 // r.record is null if findServiceLocked() failed the caller permission check
10156 if (r.record == null) {
10157 throw new SecurityException(
10158 "Permission Denial: Accessing service " + r.record.name
10159 + " from pid=" + Binder.getCallingPid()
10160 + ", uid=" + Binder.getCallingUid()
10161 + " requires " + r.permission);
10162 }
10163 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10164 if (ib != null) {
10165 ret = ib.binder;
10166 }
10167 }
10168 }
10169
10170 return ret;
10171 }
10172
10173 public boolean stopServiceToken(ComponentName className, IBinder token,
10174 int startId) {
10175 synchronized(this) {
10176 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10177 + " " + token + " startId=" + startId);
10178 ServiceRecord r = findServiceLocked(className, token);
10179 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10180 synchronized (r.stats.getBatteryStats()) {
10181 r.stats.stopRunningLocked();
10182 r.startRequested = false;
10183 }
10184 final long origId = Binder.clearCallingIdentity();
10185 bringDownServiceLocked(r, false);
10186 Binder.restoreCallingIdentity(origId);
10187 return true;
10188 }
10189 }
10190 return false;
10191 }
10192
10193 public void setServiceForeground(ComponentName className, IBinder token,
10194 boolean isForeground) {
10195 synchronized(this) {
10196 ServiceRecord r = findServiceLocked(className, token);
10197 if (r != null) {
10198 if (r.isForeground != isForeground) {
10199 final long origId = Binder.clearCallingIdentity();
10200 r.isForeground = isForeground;
10201 if (r.app != null) {
10202 updateServiceForegroundLocked(r.app, true);
10203 }
10204 Binder.restoreCallingIdentity(origId);
10205 }
10206 }
10207 }
10208 }
10209
10210 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10211 boolean anyForeground = false;
10212 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10213 if (sr.isForeground) {
10214 anyForeground = true;
10215 break;
10216 }
10217 }
10218 if (anyForeground != proc.foregroundServices) {
10219 proc.foregroundServices = anyForeground;
10220 if (oomAdj) {
10221 updateOomAdjLocked();
10222 }
10223 }
10224 }
10225
10226 public int bindService(IApplicationThread caller, IBinder token,
10227 Intent service, String resolvedType,
10228 IServiceConnection connection, int flags) {
10229 // Refuse possible leaked file descriptors
10230 if (service != null && service.hasFileDescriptors() == true) {
10231 throw new IllegalArgumentException("File descriptors passed in Intent");
10232 }
10233
10234 synchronized(this) {
10235 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10236 + " type=" + resolvedType + " conn=" + connection.asBinder()
10237 + " flags=0x" + Integer.toHexString(flags));
10238 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10239 if (callerApp == null) {
10240 throw new SecurityException(
10241 "Unable to find app for caller " + caller
10242 + " (pid=" + Binder.getCallingPid()
10243 + ") when binding service " + service);
10244 }
10245
10246 HistoryRecord activity = null;
10247 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010248 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010249 if (aindex < 0) {
10250 Log.w(TAG, "Binding with unknown activity: " + token);
10251 return 0;
10252 }
10253 activity = (HistoryRecord)mHistory.get(aindex);
10254 }
10255
10256 ServiceLookupResult res =
10257 retrieveServiceLocked(service, resolvedType,
10258 Binder.getCallingPid(), Binder.getCallingUid());
10259 if (res == null) {
10260 return 0;
10261 }
10262 if (res.record == null) {
10263 return -1;
10264 }
10265 ServiceRecord s = res.record;
10266
10267 final long origId = Binder.clearCallingIdentity();
10268
10269 if (unscheduleServiceRestartLocked(s)) {
10270 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10271 + s.shortName);
10272 }
10273
10274 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10275 ConnectionRecord c = new ConnectionRecord(b, activity,
10276 connection, flags);
10277
10278 IBinder binder = connection.asBinder();
10279 s.connections.put(binder, c);
10280 b.connections.add(c);
10281 if (activity != null) {
10282 if (activity.connections == null) {
10283 activity.connections = new HashSet<ConnectionRecord>();
10284 }
10285 activity.connections.add(c);
10286 }
10287 b.client.connections.add(c);
10288 mServiceConnections.put(binder, c);
10289
10290 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10291 s.lastActivity = SystemClock.uptimeMillis();
10292 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10293 return 0;
10294 }
10295 }
10296
10297 if (s.app != null) {
10298 // This could have made the service more important.
10299 updateOomAdjLocked(s.app);
10300 }
10301
10302 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10303 + ": received=" + b.intent.received
10304 + " apps=" + b.intent.apps.size()
10305 + " doRebind=" + b.intent.doRebind);
10306
10307 if (s.app != null && b.intent.received) {
10308 // Service is already running, so we can immediately
10309 // publish the connection.
10310 try {
10311 c.conn.connected(s.name, b.intent.binder);
10312 } catch (Exception e) {
10313 Log.w(TAG, "Failure sending service " + s.shortName
10314 + " to connection " + c.conn.asBinder()
10315 + " (in " + c.binding.client.processName + ")", e);
10316 }
10317
10318 // If this is the first app connected back to this binding,
10319 // and the service had previously asked to be told when
10320 // rebound, then do so.
10321 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10322 requestServiceBindingLocked(s, b.intent, true);
10323 }
10324 } else if (!b.intent.requested) {
10325 requestServiceBindingLocked(s, b.intent, false);
10326 }
10327
10328 Binder.restoreCallingIdentity(origId);
10329 }
10330
10331 return 1;
10332 }
10333
10334 private void removeConnectionLocked(
10335 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10336 IBinder binder = c.conn.asBinder();
10337 AppBindRecord b = c.binding;
10338 ServiceRecord s = b.service;
10339 s.connections.remove(binder);
10340 b.connections.remove(c);
10341 if (c.activity != null && c.activity != skipAct) {
10342 if (c.activity.connections != null) {
10343 c.activity.connections.remove(c);
10344 }
10345 }
10346 if (b.client != skipApp) {
10347 b.client.connections.remove(c);
10348 }
10349 mServiceConnections.remove(binder);
10350
10351 if (b.connections.size() == 0) {
10352 b.intent.apps.remove(b.client);
10353 }
10354
10355 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10356 + ": shouldUnbind=" + b.intent.hasBound);
10357 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10358 && b.intent.hasBound) {
10359 try {
10360 bumpServiceExecutingLocked(s);
10361 updateOomAdjLocked(s.app);
10362 b.intent.hasBound = false;
10363 // Assume the client doesn't want to know about a rebind;
10364 // we will deal with that later if it asks for one.
10365 b.intent.doRebind = false;
10366 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10367 } catch (Exception e) {
10368 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10369 serviceDoneExecutingLocked(s, true);
10370 }
10371 }
10372
10373 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10374 bringDownServiceLocked(s, false);
10375 }
10376 }
10377
10378 public boolean unbindService(IServiceConnection connection) {
10379 synchronized (this) {
10380 IBinder binder = connection.asBinder();
10381 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10382 ConnectionRecord r = mServiceConnections.get(binder);
10383 if (r == null) {
10384 Log.w(TAG, "Unbind failed: could not find connection for "
10385 + connection.asBinder());
10386 return false;
10387 }
10388
10389 final long origId = Binder.clearCallingIdentity();
10390
10391 removeConnectionLocked(r, null, null);
10392
10393 if (r.binding.service.app != null) {
10394 // This could have made the service less important.
10395 updateOomAdjLocked(r.binding.service.app);
10396 }
10397
10398 Binder.restoreCallingIdentity(origId);
10399 }
10400
10401 return true;
10402 }
10403
10404 public void publishService(IBinder token, Intent intent, IBinder service) {
10405 // Refuse possible leaked file descriptors
10406 if (intent != null && intent.hasFileDescriptors() == true) {
10407 throw new IllegalArgumentException("File descriptors passed in Intent");
10408 }
10409
10410 synchronized(this) {
10411 if (!(token instanceof ServiceRecord)) {
10412 throw new IllegalArgumentException("Invalid service token");
10413 }
10414 ServiceRecord r = (ServiceRecord)token;
10415
10416 final long origId = Binder.clearCallingIdentity();
10417
10418 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10419 + " " + intent + ": " + service);
10420 if (r != null) {
10421 Intent.FilterComparison filter
10422 = new Intent.FilterComparison(intent);
10423 IntentBindRecord b = r.bindings.get(filter);
10424 if (b != null && !b.received) {
10425 b.binder = service;
10426 b.requested = true;
10427 b.received = true;
10428 if (r.connections.size() > 0) {
10429 Iterator<ConnectionRecord> it
10430 = r.connections.values().iterator();
10431 while (it.hasNext()) {
10432 ConnectionRecord c = it.next();
10433 if (!filter.equals(c.binding.intent.intent)) {
10434 if (DEBUG_SERVICE) Log.v(
10435 TAG, "Not publishing to: " + c);
10436 if (DEBUG_SERVICE) Log.v(
10437 TAG, "Bound intent: " + c.binding.intent.intent);
10438 if (DEBUG_SERVICE) Log.v(
10439 TAG, "Published intent: " + intent);
10440 continue;
10441 }
10442 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10443 try {
10444 c.conn.connected(r.name, service);
10445 } catch (Exception e) {
10446 Log.w(TAG, "Failure sending service " + r.name +
10447 " to connection " + c.conn.asBinder() +
10448 " (in " + c.binding.client.processName + ")", e);
10449 }
10450 }
10451 }
10452 }
10453
10454 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10455
10456 Binder.restoreCallingIdentity(origId);
10457 }
10458 }
10459 }
10460
10461 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10462 // Refuse possible leaked file descriptors
10463 if (intent != null && intent.hasFileDescriptors() == true) {
10464 throw new IllegalArgumentException("File descriptors passed in Intent");
10465 }
10466
10467 synchronized(this) {
10468 if (!(token instanceof ServiceRecord)) {
10469 throw new IllegalArgumentException("Invalid service token");
10470 }
10471 ServiceRecord r = (ServiceRecord)token;
10472
10473 final long origId = Binder.clearCallingIdentity();
10474
10475 if (r != null) {
10476 Intent.FilterComparison filter
10477 = new Intent.FilterComparison(intent);
10478 IntentBindRecord b = r.bindings.get(filter);
10479 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10480 + " at " + b + ": apps="
10481 + (b != null ? b.apps.size() : 0));
10482 if (b != null) {
10483 if (b.apps.size() > 0) {
10484 // Applications have already bound since the last
10485 // unbind, so just rebind right here.
10486 requestServiceBindingLocked(r, b, true);
10487 } else {
10488 // Note to tell the service the next time there is
10489 // a new client.
10490 b.doRebind = true;
10491 }
10492 }
10493
10494 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10495
10496 Binder.restoreCallingIdentity(origId);
10497 }
10498 }
10499 }
10500
10501 public void serviceDoneExecuting(IBinder token) {
10502 synchronized(this) {
10503 if (!(token instanceof ServiceRecord)) {
10504 throw new IllegalArgumentException("Invalid service token");
10505 }
10506 ServiceRecord r = (ServiceRecord)token;
10507 boolean inStopping = mStoppingServices.contains(token);
10508 if (r != null) {
10509 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10510 + ": nesting=" + r.executeNesting
10511 + ", inStopping=" + inStopping);
10512 if (r != token) {
10513 Log.w(TAG, "Done executing service " + r.name
10514 + " with incorrect token: given " + token
10515 + ", expected " + r);
10516 return;
10517 }
10518
10519 final long origId = Binder.clearCallingIdentity();
10520 serviceDoneExecutingLocked(r, inStopping);
10521 Binder.restoreCallingIdentity(origId);
10522 } else {
10523 Log.w(TAG, "Done executing unknown service " + r.name
10524 + " with token " + token);
10525 }
10526 }
10527 }
10528
10529 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10530 r.executeNesting--;
10531 if (r.executeNesting <= 0 && r.app != null) {
10532 r.app.executingServices.remove(r);
10533 if (r.app.executingServices.size() == 0) {
10534 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10535 }
10536 if (inStopping) {
10537 mStoppingServices.remove(r);
10538 }
10539 updateOomAdjLocked(r.app);
10540 }
10541 }
10542
10543 void serviceTimeout(ProcessRecord proc) {
10544 synchronized(this) {
10545 if (proc.executingServices.size() == 0 || proc.thread == null) {
10546 return;
10547 }
10548 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10549 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10550 ServiceRecord timeout = null;
10551 long nextTime = 0;
10552 while (it.hasNext()) {
10553 ServiceRecord sr = it.next();
10554 if (sr.executingStart < maxTime) {
10555 timeout = sr;
10556 break;
10557 }
10558 if (sr.executingStart > nextTime) {
10559 nextTime = sr.executingStart;
10560 }
10561 }
10562 if (timeout != null && mLRUProcesses.contains(proc)) {
10563 Log.w(TAG, "Timeout executing service: " + timeout);
10564 appNotRespondingLocked(proc, null, "Executing service "
10565 + timeout.name);
10566 } else {
10567 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10568 msg.obj = proc;
10569 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10570 }
10571 }
10572 }
10573
10574 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010575 // BACKUP AND RESTORE
10576 // =========================================================
10577
10578 // Cause the target app to be launched if necessary and its backup agent
10579 // instantiated. The backup agent will invoke backupAgentCreated() on the
10580 // activity manager to announce its creation.
10581 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10582 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10583 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10584
10585 synchronized(this) {
10586 // !!! TODO: currently no check here that we're already bound
10587 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10588 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10589 synchronized (stats) {
10590 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10591 }
10592
10593 BackupRecord r = new BackupRecord(ss, app, backupMode);
10594 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10595 // startProcessLocked() returns existing proc's record if it's already running
10596 ProcessRecord proc = startProcessLocked(app.processName, app,
10597 false, 0, "backup", hostingName);
10598 if (proc == null) {
10599 Log.e(TAG, "Unable to start backup agent process " + r);
10600 return false;
10601 }
10602
10603 r.app = proc;
10604 mBackupTarget = r;
10605 mBackupAppName = app.packageName;
10606
Christopher Tate6fa95972009-06-05 18:43:55 -070010607 // Try not to kill the process during backup
10608 updateOomAdjLocked(proc);
10609
Christopher Tate181fafa2009-05-14 11:12:14 -070010610 // If the process is already attached, schedule the creation of the backup agent now.
10611 // If it is not yet live, this will be done when it attaches to the framework.
10612 if (proc.thread != null) {
10613 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10614 try {
10615 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10616 } catch (RemoteException e) {
10617 // !!! TODO: notify the backup manager that we crashed, or rely on
10618 // death notices, or...?
10619 }
10620 } else {
10621 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10622 }
10623 // Invariants: at this point, the target app process exists and the application
10624 // is either already running or in the process of coming up. mBackupTarget and
10625 // mBackupAppName describe the app, so that when it binds back to the AM we
10626 // know that it's scheduled for a backup-agent operation.
10627 }
10628
10629 return true;
10630 }
10631
10632 // A backup agent has just come up
10633 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10634 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10635 + " = " + agent);
10636
10637 synchronized(this) {
10638 if (!agentPackageName.equals(mBackupAppName)) {
10639 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10640 return;
10641 }
10642
Christopher Tate043dadc2009-06-02 16:11:00 -070010643 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010644 try {
10645 IBackupManager bm = IBackupManager.Stub.asInterface(
10646 ServiceManager.getService(Context.BACKUP_SERVICE));
10647 bm.agentConnected(agentPackageName, agent);
10648 } catch (RemoteException e) {
10649 // can't happen; the backup manager service is local
10650 } catch (Exception e) {
10651 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10652 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010653 } finally {
10654 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010655 }
10656 }
10657 }
10658
10659 // done with this agent
10660 public void unbindBackupAgent(ApplicationInfo appInfo) {
10661 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010662 if (appInfo == null) {
10663 Log.w(TAG, "unbind backup agent for null app");
10664 return;
10665 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010666
10667 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010668 if (mBackupAppName == null) {
10669 Log.w(TAG, "Unbinding backup agent with no active backup");
10670 return;
10671 }
10672
Christopher Tate181fafa2009-05-14 11:12:14 -070010673 if (!mBackupAppName.equals(appInfo.packageName)) {
10674 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10675 return;
10676 }
10677
Christopher Tate6fa95972009-06-05 18:43:55 -070010678 ProcessRecord proc = mBackupTarget.app;
10679 mBackupTarget = null;
10680 mBackupAppName = null;
10681
10682 // Not backing this app up any more; reset its OOM adjustment
10683 updateOomAdjLocked(proc);
10684
Christopher Tatec7b31e32009-06-10 15:49:30 -070010685 // If the app crashed during backup, 'thread' will be null here
10686 if (proc.thread != null) {
10687 try {
10688 proc.thread.scheduleDestroyBackupAgent(appInfo);
10689 } catch (Exception e) {
10690 Log.e(TAG, "Exception when unbinding backup agent:");
10691 e.printStackTrace();
10692 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010693 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010694 }
10695 }
10696 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010697 // BROADCASTS
10698 // =========================================================
10699
10700 private final List getStickies(String action, IntentFilter filter,
10701 List cur) {
10702 final ContentResolver resolver = mContext.getContentResolver();
10703 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10704 if (list == null) {
10705 return cur;
10706 }
10707 int N = list.size();
10708 for (int i=0; i<N; i++) {
10709 Intent intent = list.get(i);
10710 if (filter.match(resolver, intent, true, TAG) >= 0) {
10711 if (cur == null) {
10712 cur = new ArrayList<Intent>();
10713 }
10714 cur.add(intent);
10715 }
10716 }
10717 return cur;
10718 }
10719
10720 private final void scheduleBroadcastsLocked() {
10721 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10722 + mBroadcastsScheduled);
10723
10724 if (mBroadcastsScheduled) {
10725 return;
10726 }
10727 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10728 mBroadcastsScheduled = true;
10729 }
10730
10731 public Intent registerReceiver(IApplicationThread caller,
10732 IIntentReceiver receiver, IntentFilter filter, String permission) {
10733 synchronized(this) {
10734 ProcessRecord callerApp = null;
10735 if (caller != null) {
10736 callerApp = getRecordForAppLocked(caller);
10737 if (callerApp == null) {
10738 throw new SecurityException(
10739 "Unable to find app for caller " + caller
10740 + " (pid=" + Binder.getCallingPid()
10741 + ") when registering receiver " + receiver);
10742 }
10743 }
10744
10745 List allSticky = null;
10746
10747 // Look for any matching sticky broadcasts...
10748 Iterator actions = filter.actionsIterator();
10749 if (actions != null) {
10750 while (actions.hasNext()) {
10751 String action = (String)actions.next();
10752 allSticky = getStickies(action, filter, allSticky);
10753 }
10754 } else {
10755 allSticky = getStickies(null, filter, allSticky);
10756 }
10757
10758 // The first sticky in the list is returned directly back to
10759 // the client.
10760 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10761
10762 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10763 + ": " + sticky);
10764
10765 if (receiver == null) {
10766 return sticky;
10767 }
10768
10769 ReceiverList rl
10770 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10771 if (rl == null) {
10772 rl = new ReceiverList(this, callerApp,
10773 Binder.getCallingPid(),
10774 Binder.getCallingUid(), receiver);
10775 if (rl.app != null) {
10776 rl.app.receivers.add(rl);
10777 } else {
10778 try {
10779 receiver.asBinder().linkToDeath(rl, 0);
10780 } catch (RemoteException e) {
10781 return sticky;
10782 }
10783 rl.linkedToDeath = true;
10784 }
10785 mRegisteredReceivers.put(receiver.asBinder(), rl);
10786 }
10787 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10788 rl.add(bf);
10789 if (!bf.debugCheck()) {
10790 Log.w(TAG, "==> For Dynamic broadast");
10791 }
10792 mReceiverResolver.addFilter(bf);
10793
10794 // Enqueue broadcasts for all existing stickies that match
10795 // this filter.
10796 if (allSticky != null) {
10797 ArrayList receivers = new ArrayList();
10798 receivers.add(bf);
10799
10800 int N = allSticky.size();
10801 for (int i=0; i<N; i++) {
10802 Intent intent = (Intent)allSticky.get(i);
10803 BroadcastRecord r = new BroadcastRecord(intent, null,
10804 null, -1, -1, null, receivers, null, 0, null, null,
10805 false);
10806 if (mParallelBroadcasts.size() == 0) {
10807 scheduleBroadcastsLocked();
10808 }
10809 mParallelBroadcasts.add(r);
10810 }
10811 }
10812
10813 return sticky;
10814 }
10815 }
10816
10817 public void unregisterReceiver(IIntentReceiver receiver) {
10818 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10819
10820 boolean doNext = false;
10821
10822 synchronized(this) {
10823 ReceiverList rl
10824 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10825 if (rl != null) {
10826 if (rl.curBroadcast != null) {
10827 BroadcastRecord r = rl.curBroadcast;
10828 doNext = finishReceiverLocked(
10829 receiver.asBinder(), r.resultCode, r.resultData,
10830 r.resultExtras, r.resultAbort, true);
10831 }
10832
10833 if (rl.app != null) {
10834 rl.app.receivers.remove(rl);
10835 }
10836 removeReceiverLocked(rl);
10837 if (rl.linkedToDeath) {
10838 rl.linkedToDeath = false;
10839 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10840 }
10841 }
10842 }
10843
10844 if (!doNext) {
10845 return;
10846 }
10847
10848 final long origId = Binder.clearCallingIdentity();
10849 processNextBroadcast(false);
10850 trimApplications();
10851 Binder.restoreCallingIdentity(origId);
10852 }
10853
10854 void removeReceiverLocked(ReceiverList rl) {
10855 mRegisteredReceivers.remove(rl.receiver.asBinder());
10856 int N = rl.size();
10857 for (int i=0; i<N; i++) {
10858 mReceiverResolver.removeFilter(rl.get(i));
10859 }
10860 }
10861
10862 private final int broadcastIntentLocked(ProcessRecord callerApp,
10863 String callerPackage, Intent intent, String resolvedType,
10864 IIntentReceiver resultTo, int resultCode, String resultData,
10865 Bundle map, String requiredPermission,
10866 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10867 intent = new Intent(intent);
10868
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010869 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010870 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10871 + " ordered=" + ordered);
10872 if ((resultTo != null) && !ordered) {
10873 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10874 }
10875
10876 // Handle special intents: if this broadcast is from the package
10877 // manager about a package being removed, we need to remove all of
10878 // its activities from the history stack.
10879 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10880 intent.getAction());
10881 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10882 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10883 || uidRemoved) {
10884 if (checkComponentPermission(
10885 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10886 callingPid, callingUid, -1)
10887 == PackageManager.PERMISSION_GRANTED) {
10888 if (uidRemoved) {
10889 final Bundle intentExtras = intent.getExtras();
10890 final int uid = intentExtras != null
10891 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10892 if (uid >= 0) {
10893 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10894 synchronized (bs) {
10895 bs.removeUidStatsLocked(uid);
10896 }
10897 }
10898 } else {
10899 Uri data = intent.getData();
10900 String ssp;
10901 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10902 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10903 uninstallPackageLocked(ssp,
10904 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010905 AttributeCache ac = AttributeCache.instance();
10906 if (ac != null) {
10907 ac.removePackage(ssp);
10908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010909 }
10910 }
10911 }
10912 } else {
10913 String msg = "Permission Denial: " + intent.getAction()
10914 + " broadcast from " + callerPackage + " (pid=" + callingPid
10915 + ", uid=" + callingUid + ")"
10916 + " requires "
10917 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10918 Log.w(TAG, msg);
10919 throw new SecurityException(msg);
10920 }
10921 }
10922
10923 /*
10924 * If this is the time zone changed action, queue up a message that will reset the timezone
10925 * of all currently running processes. This message will get queued up before the broadcast
10926 * happens.
10927 */
10928 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10929 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10930 }
10931
Dianne Hackborn854060af2009-07-09 18:14:31 -070010932 /*
10933 * Prevent non-system code (defined here to be non-persistent
10934 * processes) from sending protected broadcasts.
10935 */
10936 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
10937 || callingUid == Process.SHELL_UID || callingUid == 0) {
10938 // Always okay.
10939 } else if (callerApp == null || !callerApp.persistent) {
10940 try {
10941 if (ActivityThread.getPackageManager().isProtectedBroadcast(
10942 intent.getAction())) {
10943 String msg = "Permission Denial: not allowed to send broadcast "
10944 + intent.getAction() + " from pid="
10945 + callingPid + ", uid=" + callingUid;
10946 Log.w(TAG, msg);
10947 throw new SecurityException(msg);
10948 }
10949 } catch (RemoteException e) {
10950 Log.w(TAG, "Remote exception", e);
10951 return BROADCAST_SUCCESS;
10952 }
10953 }
10954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010955 // Add to the sticky list if requested.
10956 if (sticky) {
10957 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10958 callingPid, callingUid)
10959 != PackageManager.PERMISSION_GRANTED) {
10960 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10961 + callingPid + ", uid=" + callingUid
10962 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10963 Log.w(TAG, msg);
10964 throw new SecurityException(msg);
10965 }
10966 if (requiredPermission != null) {
10967 Log.w(TAG, "Can't broadcast sticky intent " + intent
10968 + " and enforce permission " + requiredPermission);
10969 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10970 }
10971 if (intent.getComponent() != null) {
10972 throw new SecurityException(
10973 "Sticky broadcasts can't target a specific component");
10974 }
10975 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10976 if (list == null) {
10977 list = new ArrayList<Intent>();
10978 mStickyBroadcasts.put(intent.getAction(), list);
10979 }
10980 int N = list.size();
10981 int i;
10982 for (i=0; i<N; i++) {
10983 if (intent.filterEquals(list.get(i))) {
10984 // This sticky already exists, replace it.
10985 list.set(i, new Intent(intent));
10986 break;
10987 }
10988 }
10989 if (i >= N) {
10990 list.add(new Intent(intent));
10991 }
10992 }
10993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010994 // Figure out who all will receive this broadcast.
10995 List receivers = null;
10996 List<BroadcastFilter> registeredReceivers = null;
10997 try {
10998 if (intent.getComponent() != null) {
10999 // Broadcast is going to one specific receiver class...
11000 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011001 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011002 if (ai != null) {
11003 receivers = new ArrayList();
11004 ResolveInfo ri = new ResolveInfo();
11005 ri.activityInfo = ai;
11006 receivers.add(ri);
11007 }
11008 } else {
11009 // Need to resolve the intent to interested receivers...
11010 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11011 == 0) {
11012 receivers =
11013 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011014 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011015 }
Mihai Preda074edef2009-05-18 17:13:31 +020011016 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011017 }
11018 } catch (RemoteException ex) {
11019 // pm is in same process, this will never happen.
11020 }
11021
11022 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11023 if (!ordered && NR > 0) {
11024 // If we are not serializing this broadcast, then send the
11025 // registered receivers separately so they don't wait for the
11026 // components to be launched.
11027 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11028 callerPackage, callingPid, callingUid, requiredPermission,
11029 registeredReceivers, resultTo, resultCode, resultData, map,
11030 ordered);
11031 if (DEBUG_BROADCAST) Log.v(
11032 TAG, "Enqueueing parallel broadcast " + r
11033 + ": prev had " + mParallelBroadcasts.size());
11034 mParallelBroadcasts.add(r);
11035 scheduleBroadcastsLocked();
11036 registeredReceivers = null;
11037 NR = 0;
11038 }
11039
11040 // Merge into one list.
11041 int ir = 0;
11042 if (receivers != null) {
11043 // A special case for PACKAGE_ADDED: do not allow the package
11044 // being added to see this broadcast. This prevents them from
11045 // using this as a back door to get run as soon as they are
11046 // installed. Maybe in the future we want to have a special install
11047 // broadcast or such for apps, but we'd like to deliberately make
11048 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011049 boolean skip = false;
11050 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011051 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011052 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11053 skip = true;
11054 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11055 skip = true;
11056 }
11057 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011058 ? intent.getData().getSchemeSpecificPart()
11059 : null;
11060 if (skipPackage != null && receivers != null) {
11061 int NT = receivers.size();
11062 for (int it=0; it<NT; it++) {
11063 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11064 if (curt.activityInfo.packageName.equals(skipPackage)) {
11065 receivers.remove(it);
11066 it--;
11067 NT--;
11068 }
11069 }
11070 }
11071
11072 int NT = receivers != null ? receivers.size() : 0;
11073 int it = 0;
11074 ResolveInfo curt = null;
11075 BroadcastFilter curr = null;
11076 while (it < NT && ir < NR) {
11077 if (curt == null) {
11078 curt = (ResolveInfo)receivers.get(it);
11079 }
11080 if (curr == null) {
11081 curr = registeredReceivers.get(ir);
11082 }
11083 if (curr.getPriority() >= curt.priority) {
11084 // Insert this broadcast record into the final list.
11085 receivers.add(it, curr);
11086 ir++;
11087 curr = null;
11088 it++;
11089 NT++;
11090 } else {
11091 // Skip to the next ResolveInfo in the final list.
11092 it++;
11093 curt = null;
11094 }
11095 }
11096 }
11097 while (ir < NR) {
11098 if (receivers == null) {
11099 receivers = new ArrayList();
11100 }
11101 receivers.add(registeredReceivers.get(ir));
11102 ir++;
11103 }
11104
11105 if ((receivers != null && receivers.size() > 0)
11106 || resultTo != null) {
11107 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11108 callerPackage, callingPid, callingUid, requiredPermission,
11109 receivers, resultTo, resultCode, resultData, map, ordered);
11110 if (DEBUG_BROADCAST) Log.v(
11111 TAG, "Enqueueing ordered broadcast " + r
11112 + ": prev had " + mOrderedBroadcasts.size());
11113 if (DEBUG_BROADCAST) {
11114 int seq = r.intent.getIntExtra("seq", -1);
11115 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11116 }
11117 mOrderedBroadcasts.add(r);
11118 scheduleBroadcastsLocked();
11119 }
11120
11121 return BROADCAST_SUCCESS;
11122 }
11123
11124 public final int broadcastIntent(IApplicationThread caller,
11125 Intent intent, String resolvedType, IIntentReceiver resultTo,
11126 int resultCode, String resultData, Bundle map,
11127 String requiredPermission, boolean serialized, boolean sticky) {
11128 // Refuse possible leaked file descriptors
11129 if (intent != null && intent.hasFileDescriptors() == true) {
11130 throw new IllegalArgumentException("File descriptors passed in Intent");
11131 }
11132
11133 synchronized(this) {
11134 if (!mSystemReady) {
11135 // if the caller really truly claims to know what they're doing, go
11136 // ahead and allow the broadcast without launching any receivers
11137 int flags = intent.getFlags();
11138 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11139 intent = new Intent(intent);
11140 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11141 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11142 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11143 + " before boot completion");
11144 throw new IllegalStateException("Cannot broadcast before boot completed");
11145 }
11146 }
11147
11148 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11149 final int callingPid = Binder.getCallingPid();
11150 final int callingUid = Binder.getCallingUid();
11151 final long origId = Binder.clearCallingIdentity();
11152 int res = broadcastIntentLocked(callerApp,
11153 callerApp != null ? callerApp.info.packageName : null,
11154 intent, resolvedType, resultTo,
11155 resultCode, resultData, map, requiredPermission, serialized,
11156 sticky, callingPid, callingUid);
11157 Binder.restoreCallingIdentity(origId);
11158 return res;
11159 }
11160 }
11161
11162 int broadcastIntentInPackage(String packageName, int uid,
11163 Intent intent, String resolvedType, IIntentReceiver resultTo,
11164 int resultCode, String resultData, Bundle map,
11165 String requiredPermission, boolean serialized, boolean sticky) {
11166 synchronized(this) {
11167 final long origId = Binder.clearCallingIdentity();
11168 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11169 resultTo, resultCode, resultData, map, requiredPermission,
11170 serialized, sticky, -1, uid);
11171 Binder.restoreCallingIdentity(origId);
11172 return res;
11173 }
11174 }
11175
11176 public final void unbroadcastIntent(IApplicationThread caller,
11177 Intent intent) {
11178 // Refuse possible leaked file descriptors
11179 if (intent != null && intent.hasFileDescriptors() == true) {
11180 throw new IllegalArgumentException("File descriptors passed in Intent");
11181 }
11182
11183 synchronized(this) {
11184 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11185 != PackageManager.PERMISSION_GRANTED) {
11186 String msg = "Permission Denial: unbroadcastIntent() from pid="
11187 + Binder.getCallingPid()
11188 + ", uid=" + Binder.getCallingUid()
11189 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11190 Log.w(TAG, msg);
11191 throw new SecurityException(msg);
11192 }
11193 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11194 if (list != null) {
11195 int N = list.size();
11196 int i;
11197 for (i=0; i<N; i++) {
11198 if (intent.filterEquals(list.get(i))) {
11199 list.remove(i);
11200 break;
11201 }
11202 }
11203 }
11204 }
11205 }
11206
11207 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11208 String resultData, Bundle resultExtras, boolean resultAbort,
11209 boolean explicit) {
11210 if (mOrderedBroadcasts.size() == 0) {
11211 if (explicit) {
11212 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11213 }
11214 return false;
11215 }
11216 BroadcastRecord r = mOrderedBroadcasts.get(0);
11217 if (r.receiver == null) {
11218 if (explicit) {
11219 Log.w(TAG, "finishReceiver called but none active");
11220 }
11221 return false;
11222 }
11223 if (r.receiver != receiver) {
11224 Log.w(TAG, "finishReceiver called but active receiver is different");
11225 return false;
11226 }
11227 int state = r.state;
11228 r.state = r.IDLE;
11229 if (state == r.IDLE) {
11230 if (explicit) {
11231 Log.w(TAG, "finishReceiver called but state is IDLE");
11232 }
11233 }
11234 r.receiver = null;
11235 r.intent.setComponent(null);
11236 if (r.curApp != null) {
11237 r.curApp.curReceiver = null;
11238 }
11239 if (r.curFilter != null) {
11240 r.curFilter.receiverList.curBroadcast = null;
11241 }
11242 r.curFilter = null;
11243 r.curApp = null;
11244 r.curComponent = null;
11245 r.curReceiver = null;
11246 mPendingBroadcast = null;
11247
11248 r.resultCode = resultCode;
11249 r.resultData = resultData;
11250 r.resultExtras = resultExtras;
11251 r.resultAbort = resultAbort;
11252
11253 // We will process the next receiver right now if this is finishing
11254 // an app receiver (which is always asynchronous) or after we have
11255 // come back from calling a receiver.
11256 return state == BroadcastRecord.APP_RECEIVE
11257 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11258 }
11259
11260 public void finishReceiver(IBinder who, int resultCode, String resultData,
11261 Bundle resultExtras, boolean resultAbort) {
11262 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11263
11264 // Refuse possible leaked file descriptors
11265 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11266 throw new IllegalArgumentException("File descriptors passed in Bundle");
11267 }
11268
11269 boolean doNext;
11270
11271 final long origId = Binder.clearCallingIdentity();
11272
11273 synchronized(this) {
11274 doNext = finishReceiverLocked(
11275 who, resultCode, resultData, resultExtras, resultAbort, true);
11276 }
11277
11278 if (doNext) {
11279 processNextBroadcast(false);
11280 }
11281 trimApplications();
11282
11283 Binder.restoreCallingIdentity(origId);
11284 }
11285
11286 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11287 if (r.nextReceiver > 0) {
11288 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11289 if (curReceiver instanceof BroadcastFilter) {
11290 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11291 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11292 System.identityHashCode(r),
11293 r.intent.getAction(),
11294 r.nextReceiver - 1,
11295 System.identityHashCode(bf));
11296 } else {
11297 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11298 System.identityHashCode(r),
11299 r.intent.getAction(),
11300 r.nextReceiver - 1,
11301 ((ResolveInfo)curReceiver).toString());
11302 }
11303 } else {
11304 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11305 + r);
11306 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11307 System.identityHashCode(r),
11308 r.intent.getAction(),
11309 r.nextReceiver,
11310 "NONE");
11311 }
11312 }
11313
11314 private final void broadcastTimeout() {
11315 synchronized (this) {
11316 if (mOrderedBroadcasts.size() == 0) {
11317 return;
11318 }
11319 long now = SystemClock.uptimeMillis();
11320 BroadcastRecord r = mOrderedBroadcasts.get(0);
11321 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11322 if (DEBUG_BROADCAST) Log.v(TAG,
11323 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11324 + (r.startTime + BROADCAST_TIMEOUT));
11325 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11326 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11327 return;
11328 }
11329
11330 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11331 r.startTime = now;
11332 r.anrCount++;
11333
11334 // Current receiver has passed its expiration date.
11335 if (r.nextReceiver <= 0) {
11336 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11337 return;
11338 }
11339
11340 ProcessRecord app = null;
11341
11342 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11343 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11344 logBroadcastReceiverDiscard(r);
11345 if (curReceiver instanceof BroadcastFilter) {
11346 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11347 if (bf.receiverList.pid != 0
11348 && bf.receiverList.pid != MY_PID) {
11349 synchronized (this.mPidsSelfLocked) {
11350 app = this.mPidsSelfLocked.get(
11351 bf.receiverList.pid);
11352 }
11353 }
11354 } else {
11355 app = r.curApp;
11356 }
11357
11358 if (app != null) {
11359 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11360 }
11361
11362 if (mPendingBroadcast == r) {
11363 mPendingBroadcast = null;
11364 }
11365
11366 // Move on to the next receiver.
11367 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11368 r.resultExtras, r.resultAbort, true);
11369 scheduleBroadcastsLocked();
11370 }
11371 }
11372
11373 private final void processCurBroadcastLocked(BroadcastRecord r,
11374 ProcessRecord app) throws RemoteException {
11375 if (app.thread == null) {
11376 throw new RemoteException();
11377 }
11378 r.receiver = app.thread.asBinder();
11379 r.curApp = app;
11380 app.curReceiver = r;
11381 updateLRUListLocked(app, true);
11382
11383 // Tell the application to launch this receiver.
11384 r.intent.setComponent(r.curComponent);
11385
11386 boolean started = false;
11387 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011388 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011389 "Delivering to component " + r.curComponent
11390 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011391 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011392 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11393 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11394 started = true;
11395 } finally {
11396 if (!started) {
11397 r.receiver = null;
11398 r.curApp = null;
11399 app.curReceiver = null;
11400 }
11401 }
11402
11403 }
11404
11405 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11406 Intent intent, int resultCode, String data,
11407 Bundle extras, boolean ordered) throws RemoteException {
11408 if (app != null && app.thread != null) {
11409 // If we have an app thread, do the call through that so it is
11410 // correctly ordered with other one-way calls.
11411 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11412 data, extras, ordered);
11413 } else {
11414 receiver.performReceive(intent, resultCode, data, extras, ordered);
11415 }
11416 }
11417
11418 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11419 BroadcastFilter filter, boolean ordered) {
11420 boolean skip = false;
11421 if (filter.requiredPermission != null) {
11422 int perm = checkComponentPermission(filter.requiredPermission,
11423 r.callingPid, r.callingUid, -1);
11424 if (perm != PackageManager.PERMISSION_GRANTED) {
11425 Log.w(TAG, "Permission Denial: broadcasting "
11426 + r.intent.toString()
11427 + " from " + r.callerPackage + " (pid="
11428 + r.callingPid + ", uid=" + r.callingUid + ")"
11429 + " requires " + filter.requiredPermission
11430 + " due to registered receiver " + filter);
11431 skip = true;
11432 }
11433 }
11434 if (r.requiredPermission != null) {
11435 int perm = checkComponentPermission(r.requiredPermission,
11436 filter.receiverList.pid, filter.receiverList.uid, -1);
11437 if (perm != PackageManager.PERMISSION_GRANTED) {
11438 Log.w(TAG, "Permission Denial: receiving "
11439 + r.intent.toString()
11440 + " to " + filter.receiverList.app
11441 + " (pid=" + filter.receiverList.pid
11442 + ", uid=" + filter.receiverList.uid + ")"
11443 + " requires " + r.requiredPermission
11444 + " due to sender " + r.callerPackage
11445 + " (uid " + r.callingUid + ")");
11446 skip = true;
11447 }
11448 }
11449
11450 if (!skip) {
11451 // If this is not being sent as an ordered broadcast, then we
11452 // don't want to touch the fields that keep track of the current
11453 // state of ordered broadcasts.
11454 if (ordered) {
11455 r.receiver = filter.receiverList.receiver.asBinder();
11456 r.curFilter = filter;
11457 filter.receiverList.curBroadcast = r;
11458 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011459 if (filter.receiverList.app != null) {
11460 // Bump hosting application to no longer be in background
11461 // scheduling class. Note that we can't do that if there
11462 // isn't an app... but we can only be in that case for
11463 // things that directly call the IActivityManager API, which
11464 // are already core system stuff so don't matter for this.
11465 r.curApp = filter.receiverList.app;
11466 filter.receiverList.app.curReceiver = r;
11467 updateOomAdjLocked();
11468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011469 }
11470 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011471 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011472 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011473 Log.i(TAG, "Delivering to " + filter.receiverList.app
11474 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011475 }
11476 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11477 new Intent(r.intent), r.resultCode,
11478 r.resultData, r.resultExtras, r.ordered);
11479 if (ordered) {
11480 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11481 }
11482 } catch (RemoteException e) {
11483 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11484 if (ordered) {
11485 r.receiver = null;
11486 r.curFilter = null;
11487 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011488 if (filter.receiverList.app != null) {
11489 filter.receiverList.app.curReceiver = null;
11490 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011491 }
11492 }
11493 }
11494 }
11495
11496 private final void processNextBroadcast(boolean fromMsg) {
11497 synchronized(this) {
11498 BroadcastRecord r;
11499
11500 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11501 + mParallelBroadcasts.size() + " broadcasts, "
11502 + mOrderedBroadcasts.size() + " serialized broadcasts");
11503
11504 updateCpuStats();
11505
11506 if (fromMsg) {
11507 mBroadcastsScheduled = false;
11508 }
11509
11510 // First, deliver any non-serialized broadcasts right away.
11511 while (mParallelBroadcasts.size() > 0) {
11512 r = mParallelBroadcasts.remove(0);
11513 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011514 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11515 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011516 for (int i=0; i<N; i++) {
11517 Object target = r.receivers.get(i);
11518 if (DEBUG_BROADCAST) Log.v(TAG,
11519 "Delivering non-serialized to registered "
11520 + target + ": " + r);
11521 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11522 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011523 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11524 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011525 }
11526
11527 // Now take care of the next serialized one...
11528
11529 // If we are waiting for a process to come up to handle the next
11530 // broadcast, then do nothing at this point. Just in case, we
11531 // check that the process we're waiting for still exists.
11532 if (mPendingBroadcast != null) {
11533 Log.i(TAG, "processNextBroadcast: waiting for "
11534 + mPendingBroadcast.curApp);
11535
11536 boolean isDead;
11537 synchronized (mPidsSelfLocked) {
11538 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11539 }
11540 if (!isDead) {
11541 // It's still alive, so keep waiting
11542 return;
11543 } else {
11544 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11545 + " died before responding to broadcast");
11546 mPendingBroadcast = null;
11547 }
11548 }
11549
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011550 boolean looped = false;
11551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011552 do {
11553 if (mOrderedBroadcasts.size() == 0) {
11554 // No more broadcasts pending, so all done!
11555 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011556 if (looped) {
11557 // If we had finished the last ordered broadcast, then
11558 // make sure all processes have correct oom and sched
11559 // adjustments.
11560 updateOomAdjLocked();
11561 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011562 return;
11563 }
11564 r = mOrderedBroadcasts.get(0);
11565 boolean forceReceive = false;
11566
11567 // Ensure that even if something goes awry with the timeout
11568 // detection, we catch "hung" broadcasts here, discard them,
11569 // and continue to make progress.
11570 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11571 long now = SystemClock.uptimeMillis();
11572 if (r.dispatchTime > 0) {
11573 if ((numReceivers > 0) &&
11574 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11575 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11576 + " now=" + now
11577 + " dispatchTime=" + r.dispatchTime
11578 + " startTime=" + r.startTime
11579 + " intent=" + r.intent
11580 + " numReceivers=" + numReceivers
11581 + " nextReceiver=" + r.nextReceiver
11582 + " state=" + r.state);
11583 broadcastTimeout(); // forcibly finish this broadcast
11584 forceReceive = true;
11585 r.state = BroadcastRecord.IDLE;
11586 }
11587 }
11588
11589 if (r.state != BroadcastRecord.IDLE) {
11590 if (DEBUG_BROADCAST) Log.d(TAG,
11591 "processNextBroadcast() called when not idle (state="
11592 + r.state + ")");
11593 return;
11594 }
11595
11596 if (r.receivers == null || r.nextReceiver >= numReceivers
11597 || r.resultAbort || forceReceive) {
11598 // No more receivers for this broadcast! Send the final
11599 // result if requested...
11600 if (r.resultTo != null) {
11601 try {
11602 if (DEBUG_BROADCAST) {
11603 int seq = r.intent.getIntExtra("seq", -1);
11604 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11605 + " seq=" + seq + " app=" + r.callerApp);
11606 }
11607 performReceive(r.callerApp, r.resultTo,
11608 new Intent(r.intent), r.resultCode,
11609 r.resultData, r.resultExtras, false);
11610 } catch (RemoteException e) {
11611 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11612 }
11613 }
11614
11615 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11616 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11617
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011618 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11619 + r);
11620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011621 // ... and on to the next...
11622 mOrderedBroadcasts.remove(0);
11623 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011624 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011625 continue;
11626 }
11627 } while (r == null);
11628
11629 // Get the next receiver...
11630 int recIdx = r.nextReceiver++;
11631
11632 // Keep track of when this receiver started, and make sure there
11633 // is a timeout message pending to kill it if need be.
11634 r.startTime = SystemClock.uptimeMillis();
11635 if (recIdx == 0) {
11636 r.dispatchTime = r.startTime;
11637
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011638 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11639 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011640 if (DEBUG_BROADCAST) Log.v(TAG,
11641 "Submitting BROADCAST_TIMEOUT_MSG for "
11642 + (r.startTime + BROADCAST_TIMEOUT));
11643 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11644 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11645 }
11646
11647 Object nextReceiver = r.receivers.get(recIdx);
11648 if (nextReceiver instanceof BroadcastFilter) {
11649 // Simple case: this is a registered receiver who gets
11650 // a direct call.
11651 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11652 if (DEBUG_BROADCAST) Log.v(TAG,
11653 "Delivering serialized to registered "
11654 + filter + ": " + r);
11655 deliverToRegisteredReceiver(r, filter, r.ordered);
11656 if (r.receiver == null || !r.ordered) {
11657 // The receiver has already finished, so schedule to
11658 // process the next one.
11659 r.state = BroadcastRecord.IDLE;
11660 scheduleBroadcastsLocked();
11661 }
11662 return;
11663 }
11664
11665 // Hard case: need to instantiate the receiver, possibly
11666 // starting its application process to host it.
11667
11668 ResolveInfo info =
11669 (ResolveInfo)nextReceiver;
11670
11671 boolean skip = false;
11672 int perm = checkComponentPermission(info.activityInfo.permission,
11673 r.callingPid, r.callingUid,
11674 info.activityInfo.exported
11675 ? -1 : info.activityInfo.applicationInfo.uid);
11676 if (perm != PackageManager.PERMISSION_GRANTED) {
11677 Log.w(TAG, "Permission Denial: broadcasting "
11678 + r.intent.toString()
11679 + " from " + r.callerPackage + " (pid=" + r.callingPid
11680 + ", uid=" + r.callingUid + ")"
11681 + " requires " + info.activityInfo.permission
11682 + " due to receiver " + info.activityInfo.packageName
11683 + "/" + info.activityInfo.name);
11684 skip = true;
11685 }
11686 if (r.callingUid != Process.SYSTEM_UID &&
11687 r.requiredPermission != null) {
11688 try {
11689 perm = ActivityThread.getPackageManager().
11690 checkPermission(r.requiredPermission,
11691 info.activityInfo.applicationInfo.packageName);
11692 } catch (RemoteException e) {
11693 perm = PackageManager.PERMISSION_DENIED;
11694 }
11695 if (perm != PackageManager.PERMISSION_GRANTED) {
11696 Log.w(TAG, "Permission Denial: receiving "
11697 + r.intent + " to "
11698 + info.activityInfo.applicationInfo.packageName
11699 + " requires " + r.requiredPermission
11700 + " due to sender " + r.callerPackage
11701 + " (uid " + r.callingUid + ")");
11702 skip = true;
11703 }
11704 }
11705 if (r.curApp != null && r.curApp.crashing) {
11706 // If the target process is crashing, just skip it.
11707 skip = true;
11708 }
11709
11710 if (skip) {
11711 r.receiver = null;
11712 r.curFilter = null;
11713 r.state = BroadcastRecord.IDLE;
11714 scheduleBroadcastsLocked();
11715 return;
11716 }
11717
11718 r.state = BroadcastRecord.APP_RECEIVE;
11719 String targetProcess = info.activityInfo.processName;
11720 r.curComponent = new ComponentName(
11721 info.activityInfo.applicationInfo.packageName,
11722 info.activityInfo.name);
11723 r.curReceiver = info.activityInfo;
11724
11725 // Is this receiver's application already running?
11726 ProcessRecord app = getProcessRecordLocked(targetProcess,
11727 info.activityInfo.applicationInfo.uid);
11728 if (app != null && app.thread != null) {
11729 try {
11730 processCurBroadcastLocked(r, app);
11731 return;
11732 } catch (RemoteException e) {
11733 Log.w(TAG, "Exception when sending broadcast to "
11734 + r.curComponent, e);
11735 }
11736
11737 // If a dead object exception was thrown -- fall through to
11738 // restart the application.
11739 }
11740
11741 // Not running -- get it started, and enqueue this history record
11742 // to be executed when the app comes up.
11743 if ((r.curApp=startProcessLocked(targetProcess,
11744 info.activityInfo.applicationInfo, true,
11745 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11746 "broadcast", r.curComponent)) == null) {
11747 // Ah, this recipient is unavailable. Finish it if necessary,
11748 // and mark the broadcast record as ready for the next.
11749 Log.w(TAG, "Unable to launch app "
11750 + info.activityInfo.applicationInfo.packageName + "/"
11751 + info.activityInfo.applicationInfo.uid + " for broadcast "
11752 + r.intent + ": process is bad");
11753 logBroadcastReceiverDiscard(r);
11754 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11755 r.resultExtras, r.resultAbort, true);
11756 scheduleBroadcastsLocked();
11757 r.state = BroadcastRecord.IDLE;
11758 return;
11759 }
11760
11761 mPendingBroadcast = r;
11762 }
11763 }
11764
11765 // =========================================================
11766 // INSTRUMENTATION
11767 // =========================================================
11768
11769 public boolean startInstrumentation(ComponentName className,
11770 String profileFile, int flags, Bundle arguments,
11771 IInstrumentationWatcher watcher) {
11772 // Refuse possible leaked file descriptors
11773 if (arguments != null && arguments.hasFileDescriptors()) {
11774 throw new IllegalArgumentException("File descriptors passed in Bundle");
11775 }
11776
11777 synchronized(this) {
11778 InstrumentationInfo ii = null;
11779 ApplicationInfo ai = null;
11780 try {
11781 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011782 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011783 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011784 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011785 } catch (PackageManager.NameNotFoundException e) {
11786 }
11787 if (ii == null) {
11788 reportStartInstrumentationFailure(watcher, className,
11789 "Unable to find instrumentation info for: " + className);
11790 return false;
11791 }
11792 if (ai == null) {
11793 reportStartInstrumentationFailure(watcher, className,
11794 "Unable to find instrumentation target package: " + ii.targetPackage);
11795 return false;
11796 }
11797
11798 int match = mContext.getPackageManager().checkSignatures(
11799 ii.targetPackage, ii.packageName);
11800 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11801 String msg = "Permission Denial: starting instrumentation "
11802 + className + " from pid="
11803 + Binder.getCallingPid()
11804 + ", uid=" + Binder.getCallingPid()
11805 + " not allowed because package " + ii.packageName
11806 + " does not have a signature matching the target "
11807 + ii.targetPackage;
11808 reportStartInstrumentationFailure(watcher, className, msg);
11809 throw new SecurityException(msg);
11810 }
11811
11812 final long origId = Binder.clearCallingIdentity();
11813 uninstallPackageLocked(ii.targetPackage, -1, true);
11814 ProcessRecord app = addAppLocked(ai);
11815 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011816 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011817 app.instrumentationProfileFile = profileFile;
11818 app.instrumentationArguments = arguments;
11819 app.instrumentationWatcher = watcher;
11820 app.instrumentationResultClass = className;
11821 Binder.restoreCallingIdentity(origId);
11822 }
11823
11824 return true;
11825 }
11826
11827 /**
11828 * Report errors that occur while attempting to start Instrumentation. Always writes the
11829 * error to the logs, but if somebody is watching, send the report there too. This enables
11830 * the "am" command to report errors with more information.
11831 *
11832 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11833 * @param cn The component name of the instrumentation.
11834 * @param report The error report.
11835 */
11836 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11837 ComponentName cn, String report) {
11838 Log.w(TAG, report);
11839 try {
11840 if (watcher != null) {
11841 Bundle results = new Bundle();
11842 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11843 results.putString("Error", report);
11844 watcher.instrumentationStatus(cn, -1, results);
11845 }
11846 } catch (RemoteException e) {
11847 Log.w(TAG, e);
11848 }
11849 }
11850
11851 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11852 if (app.instrumentationWatcher != null) {
11853 try {
11854 // NOTE: IInstrumentationWatcher *must* be oneway here
11855 app.instrumentationWatcher.instrumentationFinished(
11856 app.instrumentationClass,
11857 resultCode,
11858 results);
11859 } catch (RemoteException e) {
11860 }
11861 }
11862 app.instrumentationWatcher = null;
11863 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011864 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011865 app.instrumentationProfileFile = null;
11866 app.instrumentationArguments = null;
11867
11868 uninstallPackageLocked(app.processName, -1, false);
11869 }
11870
11871 public void finishInstrumentation(IApplicationThread target,
11872 int resultCode, Bundle results) {
11873 // Refuse possible leaked file descriptors
11874 if (results != null && results.hasFileDescriptors()) {
11875 throw new IllegalArgumentException("File descriptors passed in Intent");
11876 }
11877
11878 synchronized(this) {
11879 ProcessRecord app = getRecordForAppLocked(target);
11880 if (app == null) {
11881 Log.w(TAG, "finishInstrumentation: no app for " + target);
11882 return;
11883 }
11884 final long origId = Binder.clearCallingIdentity();
11885 finishInstrumentationLocked(app, resultCode, results);
11886 Binder.restoreCallingIdentity(origId);
11887 }
11888 }
11889
11890 // =========================================================
11891 // CONFIGURATION
11892 // =========================================================
11893
11894 public ConfigurationInfo getDeviceConfigurationInfo() {
11895 ConfigurationInfo config = new ConfigurationInfo();
11896 synchronized (this) {
11897 config.reqTouchScreen = mConfiguration.touchscreen;
11898 config.reqKeyboardType = mConfiguration.keyboard;
11899 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011900 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
11901 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011902 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11903 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011904 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
11905 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011906 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11907 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070011908 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011909 }
11910 return config;
11911 }
11912
11913 public Configuration getConfiguration() {
11914 Configuration ci;
11915 synchronized(this) {
11916 ci = new Configuration(mConfiguration);
11917 }
11918 return ci;
11919 }
11920
11921 public void updateConfiguration(Configuration values) {
11922 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11923 "updateConfiguration()");
11924
11925 synchronized(this) {
11926 if (values == null && mWindowManager != null) {
11927 // sentinel: fetch the current configuration from the window manager
11928 values = mWindowManager.computeNewConfiguration();
11929 }
11930
11931 final long origId = Binder.clearCallingIdentity();
11932 updateConfigurationLocked(values, null);
11933 Binder.restoreCallingIdentity(origId);
11934 }
11935 }
11936
11937 /**
11938 * Do either or both things: (1) change the current configuration, and (2)
11939 * make sure the given activity is running with the (now) current
11940 * configuration. Returns true if the activity has been left running, or
11941 * false if <var>starting</var> is being destroyed to match the new
11942 * configuration.
11943 */
11944 public boolean updateConfigurationLocked(Configuration values,
11945 HistoryRecord starting) {
11946 int changes = 0;
11947
11948 boolean kept = true;
11949
11950 if (values != null) {
11951 Configuration newConfig = new Configuration(mConfiguration);
11952 changes = newConfig.updateFrom(values);
11953 if (changes != 0) {
11954 if (DEBUG_SWITCH) {
11955 Log.i(TAG, "Updating configuration to: " + values);
11956 }
11957
11958 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11959
11960 if (values.locale != null) {
11961 saveLocaleLocked(values.locale,
11962 !values.locale.equals(mConfiguration.locale),
11963 values.userSetLocale);
11964 }
11965
11966 mConfiguration = newConfig;
11967
11968 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11969 msg.obj = new Configuration(mConfiguration);
11970 mHandler.sendMessage(msg);
11971
11972 final int N = mLRUProcesses.size();
11973 for (int i=0; i<N; i++) {
11974 ProcessRecord app = mLRUProcesses.get(i);
11975 try {
11976 if (app.thread != null) {
11977 app.thread.scheduleConfigurationChanged(mConfiguration);
11978 }
11979 } catch (Exception e) {
11980 }
11981 }
11982 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11983 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11984 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011985
11986 AttributeCache ac = AttributeCache.instance();
11987 if (ac != null) {
11988 ac.updateConfiguration(mConfiguration);
11989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011990 }
11991 }
11992
11993 if (changes != 0 && starting == null) {
11994 // If the configuration changed, and the caller is not already
11995 // in the process of starting an activity, then find the top
11996 // activity to check if its configuration needs to change.
11997 starting = topRunningActivityLocked(null);
11998 }
11999
12000 if (starting != null) {
12001 kept = ensureActivityConfigurationLocked(starting, changes);
12002 if (kept) {
12003 // If this didn't result in the starting activity being
12004 // destroyed, then we need to make sure at this point that all
12005 // other activities are made visible.
12006 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12007 + ", ensuring others are correct.");
12008 ensureActivitiesVisibleLocked(starting, changes);
12009 }
12010 }
12011
12012 return kept;
12013 }
12014
12015 private final boolean relaunchActivityLocked(HistoryRecord r,
12016 int changes, boolean andResume) {
12017 List<ResultInfo> results = null;
12018 List<Intent> newIntents = null;
12019 if (andResume) {
12020 results = r.results;
12021 newIntents = r.newIntents;
12022 }
12023 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12024 + " with results=" + results + " newIntents=" + newIntents
12025 + " andResume=" + andResume);
12026 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12027 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12028 r.task.taskId, r.shortComponentName);
12029
12030 r.startFreezingScreenLocked(r.app, 0);
12031
12032 try {
12033 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12034 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12035 changes, !andResume);
12036 // Note: don't need to call pauseIfSleepingLocked() here, because
12037 // the caller will only pass in 'andResume' if this activity is
12038 // currently resumed, which implies we aren't sleeping.
12039 } catch (RemoteException e) {
12040 return false;
12041 }
12042
12043 if (andResume) {
12044 r.results = null;
12045 r.newIntents = null;
12046 }
12047
12048 return true;
12049 }
12050
12051 /**
12052 * Make sure the given activity matches the current configuration. Returns
12053 * false if the activity had to be destroyed. Returns true if the
12054 * configuration is the same, or the activity will remain running as-is
12055 * for whatever reason. Ensures the HistoryRecord is updated with the
12056 * correct configuration and all other bookkeeping is handled.
12057 */
12058 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12059 int globalChanges) {
12060 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12061
12062 // Short circuit: if the two configurations are the exact same
12063 // object (the common case), then there is nothing to do.
12064 Configuration newConfig = mConfiguration;
12065 if (r.configuration == newConfig) {
12066 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12067 return true;
12068 }
12069
12070 // We don't worry about activities that are finishing.
12071 if (r.finishing) {
12072 if (DEBUG_SWITCH) Log.i(TAG,
12073 "Configuration doesn't matter in finishing " + r);
12074 r.stopFreezingScreenLocked(false);
12075 return true;
12076 }
12077
12078 // Okay we now are going to make this activity have the new config.
12079 // But then we need to figure out how it needs to deal with that.
12080 Configuration oldConfig = r.configuration;
12081 r.configuration = newConfig;
12082
12083 // If the activity isn't currently running, just leave the new
12084 // configuration and it will pick that up next time it starts.
12085 if (r.app == null || r.app.thread == null) {
12086 if (DEBUG_SWITCH) Log.i(TAG,
12087 "Configuration doesn't matter not running " + r);
12088 r.stopFreezingScreenLocked(false);
12089 return true;
12090 }
12091
12092 // If the activity isn't persistent, there is a chance we will
12093 // need to restart it.
12094 if (!r.persistent) {
12095
12096 // Figure out what has changed between the two configurations.
12097 int changes = oldConfig.diff(newConfig);
12098 if (DEBUG_SWITCH) {
12099 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12100 + Integer.toHexString(changes) + ", handles=0x"
12101 + Integer.toHexString(r.info.configChanges));
12102 }
12103 if ((changes&(~r.info.configChanges)) != 0) {
12104 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12105 r.configChangeFlags |= changes;
12106 r.startFreezingScreenLocked(r.app, globalChanges);
12107 if (r.app == null || r.app.thread == null) {
12108 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12109 destroyActivityLocked(r, true);
12110 } else if (r.state == ActivityState.PAUSING) {
12111 // A little annoying: we are waiting for this activity to
12112 // finish pausing. Let's not do anything now, but just
12113 // flag that it needs to be restarted when done pausing.
12114 r.configDestroy = true;
12115 return true;
12116 } else if (r.state == ActivityState.RESUMED) {
12117 // Try to optimize this case: the configuration is changing
12118 // and we need to restart the top, resumed activity.
12119 // Instead of doing the normal handshaking, just say
12120 // "restart!".
12121 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12122 relaunchActivityLocked(r, r.configChangeFlags, true);
12123 r.configChangeFlags = 0;
12124 } else {
12125 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12126 relaunchActivityLocked(r, r.configChangeFlags, false);
12127 r.configChangeFlags = 0;
12128 }
12129
12130 // All done... tell the caller we weren't able to keep this
12131 // activity around.
12132 return false;
12133 }
12134 }
12135
12136 // Default case: the activity can handle this new configuration, so
12137 // hand it over. Note that we don't need to give it the new
12138 // configuration, since we always send configuration changes to all
12139 // process when they happen so it can just use whatever configuration
12140 // it last got.
12141 if (r.app != null && r.app.thread != null) {
12142 try {
12143 r.app.thread.scheduleActivityConfigurationChanged(r);
12144 } catch (RemoteException e) {
12145 // If process died, whatever.
12146 }
12147 }
12148 r.stopFreezingScreenLocked(false);
12149
12150 return true;
12151 }
12152
12153 /**
12154 * Save the locale. You must be inside a synchronized (this) block.
12155 */
12156 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12157 if(isDiff) {
12158 SystemProperties.set("user.language", l.getLanguage());
12159 SystemProperties.set("user.region", l.getCountry());
12160 }
12161
12162 if(isPersist) {
12163 SystemProperties.set("persist.sys.language", l.getLanguage());
12164 SystemProperties.set("persist.sys.country", l.getCountry());
12165 SystemProperties.set("persist.sys.localevar", l.getVariant());
12166 }
12167 }
12168
12169 // =========================================================
12170 // LIFETIME MANAGEMENT
12171 // =========================================================
12172
12173 private final int computeOomAdjLocked(
12174 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12175 if (mAdjSeq == app.adjSeq) {
12176 // This adjustment has already been computed.
12177 return app.curAdj;
12178 }
12179
12180 if (app.thread == null) {
12181 app.adjSeq = mAdjSeq;
12182 return (app.curAdj=EMPTY_APP_ADJ);
12183 }
12184
12185 app.isForeground = false;
12186
The Android Open Source Project4df24232009-03-05 14:34:35 -080012187 // Determine the importance of the process, starting with most
12188 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012189 int adj;
12190 int N;
12191 if (app == TOP_APP || app.instrumentationClass != null
12192 || app.persistentActivities > 0) {
12193 // The last app on the list is the foreground app.
12194 adj = FOREGROUND_APP_ADJ;
12195 app.isForeground = true;
12196 } else if (app.curReceiver != null ||
12197 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12198 // An app that is currently receiving a broadcast also
12199 // counts as being in the foreground.
12200 adj = FOREGROUND_APP_ADJ;
12201 } else if (app.executingServices.size() > 0) {
12202 // An app that is currently executing a service callback also
12203 // counts as being in the foreground.
12204 adj = FOREGROUND_APP_ADJ;
12205 } else if (app.foregroundServices || app.forcingToForeground != null) {
12206 // The user is aware of this app, so make it visible.
12207 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012208 } else if (app == mHomeProcess) {
12209 // This process is hosting what we currently consider to be the
12210 // home app, so we don't want to let it go into the background.
12211 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012212 } else if ((N=app.activities.size()) != 0) {
12213 // This app is in the background with paused activities.
12214 adj = hiddenAdj;
12215 for (int j=0; j<N; j++) {
12216 if (((HistoryRecord)app.activities.get(j)).visible) {
12217 // This app has a visible activity!
12218 adj = VISIBLE_APP_ADJ;
12219 break;
12220 }
12221 }
12222 } else {
12223 // A very not-needed process.
12224 adj = EMPTY_APP_ADJ;
12225 }
12226
The Android Open Source Project4df24232009-03-05 14:34:35 -080012227 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012228 // there are applications dependent on our services or providers, but
12229 // this gives us a baseline and makes sure we don't get into an
12230 // infinite recursion.
12231 app.adjSeq = mAdjSeq;
12232 app.curRawAdj = adj;
12233 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12234
Christopher Tate6fa95972009-06-05 18:43:55 -070012235 if (mBackupTarget != null && app == mBackupTarget.app) {
12236 // If possible we want to avoid killing apps while they're being backed up
12237 if (adj > BACKUP_APP_ADJ) {
12238 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12239 adj = BACKUP_APP_ADJ;
12240 }
12241 }
12242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012243 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12244 // If this process has active services running in it, we would
12245 // like to avoid killing it unless it would prevent the current
12246 // application from running.
12247 if (adj > hiddenAdj) {
12248 adj = hiddenAdj;
12249 }
12250 final long now = SystemClock.uptimeMillis();
12251 // This process is more important if the top activity is
12252 // bound to the service.
12253 Iterator jt = app.services.iterator();
12254 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12255 ServiceRecord s = (ServiceRecord)jt.next();
12256 if (s.startRequested) {
12257 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12258 // This service has seen some activity within
12259 // recent memory, so we will keep its process ahead
12260 // of the background processes.
12261 if (adj > SECONDARY_SERVER_ADJ) {
12262 adj = SECONDARY_SERVER_ADJ;
12263 }
12264 } else {
12265 // This service has been inactive for too long, just
12266 // put it with the rest of the background processes.
12267 if (adj > hiddenAdj) {
12268 adj = hiddenAdj;
12269 }
12270 }
12271 }
12272 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12273 Iterator<ConnectionRecord> kt
12274 = s.connections.values().iterator();
12275 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12276 // XXX should compute this based on the max of
12277 // all connected clients.
12278 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012279 if (cr.binding.client == app) {
12280 // Binding to ourself is not interesting.
12281 continue;
12282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012283 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12284 ProcessRecord client = cr.binding.client;
12285 int myHiddenAdj = hiddenAdj;
12286 if (myHiddenAdj > client.hiddenAdj) {
12287 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12288 myHiddenAdj = client.hiddenAdj;
12289 } else {
12290 myHiddenAdj = VISIBLE_APP_ADJ;
12291 }
12292 }
12293 int clientAdj = computeOomAdjLocked(
12294 client, myHiddenAdj, TOP_APP);
12295 if (adj > clientAdj) {
12296 adj = clientAdj > VISIBLE_APP_ADJ
12297 ? clientAdj : VISIBLE_APP_ADJ;
12298 }
12299 }
12300 HistoryRecord a = cr.activity;
12301 //if (a != null) {
12302 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12303 //}
12304 if (a != null && adj > FOREGROUND_APP_ADJ &&
12305 (a.state == ActivityState.RESUMED
12306 || a.state == ActivityState.PAUSING)) {
12307 adj = FOREGROUND_APP_ADJ;
12308 }
12309 }
12310 }
12311 }
12312 }
12313
12314 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12315 // If this process has published any content providers, then
12316 // its adjustment makes it at least as important as any of the
12317 // processes using those providers, and no less important than
12318 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12319 if (adj > CONTENT_PROVIDER_ADJ) {
12320 adj = CONTENT_PROVIDER_ADJ;
12321 }
12322 Iterator jt = app.pubProviders.values().iterator();
12323 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12324 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12325 if (cpr.clients.size() != 0) {
12326 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12327 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12328 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012329 if (client == app) {
12330 // Being our own client is not interesting.
12331 continue;
12332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012333 int myHiddenAdj = hiddenAdj;
12334 if (myHiddenAdj > client.hiddenAdj) {
12335 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12336 myHiddenAdj = client.hiddenAdj;
12337 } else {
12338 myHiddenAdj = FOREGROUND_APP_ADJ;
12339 }
12340 }
12341 int clientAdj = computeOomAdjLocked(
12342 client, myHiddenAdj, TOP_APP);
12343 if (adj > clientAdj) {
12344 adj = clientAdj > FOREGROUND_APP_ADJ
12345 ? clientAdj : FOREGROUND_APP_ADJ;
12346 }
12347 }
12348 }
12349 // If the provider has external (non-framework) process
12350 // dependencies, ensure that its adjustment is at least
12351 // FOREGROUND_APP_ADJ.
12352 if (cpr.externals != 0) {
12353 if (adj > FOREGROUND_APP_ADJ) {
12354 adj = FOREGROUND_APP_ADJ;
12355 }
12356 }
12357 }
12358 }
12359
12360 app.curRawAdj = adj;
12361
12362 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12363 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12364 if (adj > app.maxAdj) {
12365 adj = app.maxAdj;
12366 }
12367
12368 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012369 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12370 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12371 : Process.THREAD_GROUP_DEFAULT;
12372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012373 return adj;
12374 }
12375
12376 /**
12377 * Ask a given process to GC right now.
12378 */
12379 final void performAppGcLocked(ProcessRecord app) {
12380 try {
12381 app.lastRequestedGc = SystemClock.uptimeMillis();
12382 if (app.thread != null) {
12383 app.thread.processInBackground();
12384 }
12385 } catch (Exception e) {
12386 // whatever.
12387 }
12388 }
12389
12390 /**
12391 * Returns true if things are idle enough to perform GCs.
12392 */
12393 private final boolean canGcNow() {
12394 return mParallelBroadcasts.size() == 0
12395 && mOrderedBroadcasts.size() == 0
12396 && (mSleeping || (mResumedActivity != null &&
12397 mResumedActivity.idle));
12398 }
12399
12400 /**
12401 * Perform GCs on all processes that are waiting for it, but only
12402 * if things are idle.
12403 */
12404 final void performAppGcsLocked() {
12405 final int N = mProcessesToGc.size();
12406 if (N <= 0) {
12407 return;
12408 }
12409 if (canGcNow()) {
12410 while (mProcessesToGc.size() > 0) {
12411 ProcessRecord proc = mProcessesToGc.remove(0);
12412 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12413 // To avoid spamming the system, we will GC processes one
12414 // at a time, waiting a few seconds between each.
12415 performAppGcLocked(proc);
12416 scheduleAppGcsLocked();
12417 return;
12418 }
12419 }
12420 }
12421 }
12422
12423 /**
12424 * If all looks good, perform GCs on all processes waiting for them.
12425 */
12426 final void performAppGcsIfAppropriateLocked() {
12427 if (canGcNow()) {
12428 performAppGcsLocked();
12429 return;
12430 }
12431 // Still not idle, wait some more.
12432 scheduleAppGcsLocked();
12433 }
12434
12435 /**
12436 * Schedule the execution of all pending app GCs.
12437 */
12438 final void scheduleAppGcsLocked() {
12439 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12440 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12441 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12442 }
12443
12444 /**
12445 * Set up to ask a process to GC itself. This will either do it
12446 * immediately, or put it on the list of processes to gc the next
12447 * time things are idle.
12448 */
12449 final void scheduleAppGcLocked(ProcessRecord app) {
12450 long now = SystemClock.uptimeMillis();
12451 if ((app.lastRequestedGc+5000) > now) {
12452 return;
12453 }
12454 if (!mProcessesToGc.contains(app)) {
12455 mProcessesToGc.add(app);
12456 scheduleAppGcsLocked();
12457 }
12458 }
12459
12460 private final boolean updateOomAdjLocked(
12461 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12462 app.hiddenAdj = hiddenAdj;
12463
12464 if (app.thread == null) {
12465 return true;
12466 }
12467
12468 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12469
12470 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12471 //Thread priority adjustment is disabled out to see
12472 //how the kernel scheduler performs.
12473 if (false) {
12474 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12475 app.setIsForeground = app.isForeground;
12476 if (app.pid != MY_PID) {
12477 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12478 + " to " + (app.isForeground
12479 ? Process.THREAD_PRIORITY_FOREGROUND
12480 : Process.THREAD_PRIORITY_DEFAULT));
12481 try {
12482 Process.setThreadPriority(app.pid, app.isForeground
12483 ? Process.THREAD_PRIORITY_FOREGROUND
12484 : Process.THREAD_PRIORITY_DEFAULT);
12485 } catch (RuntimeException e) {
12486 Log.w(TAG, "Exception trying to set priority of application thread "
12487 + app.pid, e);
12488 }
12489 }
12490 }
12491 }
12492 if (app.pid != 0 && app.pid != MY_PID) {
12493 if (app.curRawAdj != app.setRawAdj) {
12494 if (app.curRawAdj > FOREGROUND_APP_ADJ
12495 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12496 // If this app is transitioning from foreground to
12497 // non-foreground, have it do a gc.
12498 scheduleAppGcLocked(app);
12499 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12500 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12501 // Likewise do a gc when an app is moving in to the
12502 // background (such as a service stopping).
12503 scheduleAppGcLocked(app);
12504 }
12505 app.setRawAdj = app.curRawAdj;
12506 }
12507 if (adj != app.setAdj) {
12508 if (Process.setOomAdj(app.pid, adj)) {
12509 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12510 TAG, "Set app " + app.processName +
12511 " oom adj to " + adj);
12512 app.setAdj = adj;
12513 } else {
12514 return false;
12515 }
12516 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012517 if (app.setSchedGroup != app.curSchedGroup) {
12518 app.setSchedGroup = app.curSchedGroup;
12519 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12520 "Setting process group of " + app.processName
12521 + " to " + app.curSchedGroup);
12522 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012523 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012524 try {
12525 Process.setProcessGroup(app.pid, app.curSchedGroup);
12526 } catch (Exception e) {
12527 Log.w(TAG, "Failed setting process group of " + app.pid
12528 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012529 e.printStackTrace();
12530 } finally {
12531 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012532 }
12533 }
12534 if (false) {
12535 if (app.thread != null) {
12536 try {
12537 app.thread.setSchedulingGroup(app.curSchedGroup);
12538 } catch (RemoteException e) {
12539 }
12540 }
12541 }
12542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012543 }
12544
12545 return true;
12546 }
12547
12548 private final HistoryRecord resumedAppLocked() {
12549 HistoryRecord resumedActivity = mResumedActivity;
12550 if (resumedActivity == null || resumedActivity.app == null) {
12551 resumedActivity = mPausingActivity;
12552 if (resumedActivity == null || resumedActivity.app == null) {
12553 resumedActivity = topRunningActivityLocked(null);
12554 }
12555 }
12556 return resumedActivity;
12557 }
12558
12559 private final boolean updateOomAdjLocked(ProcessRecord app) {
12560 final HistoryRecord TOP_ACT = resumedAppLocked();
12561 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12562 int curAdj = app.curAdj;
12563 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12564 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12565
12566 mAdjSeq++;
12567
12568 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12569 if (res) {
12570 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12571 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12572 if (nowHidden != wasHidden) {
12573 // Changed to/from hidden state, so apps after it in the LRU
12574 // list may also be changed.
12575 updateOomAdjLocked();
12576 }
12577 }
12578 return res;
12579 }
12580
12581 private final boolean updateOomAdjLocked() {
12582 boolean didOomAdj = true;
12583 final HistoryRecord TOP_ACT = resumedAppLocked();
12584 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12585
12586 if (false) {
12587 RuntimeException e = new RuntimeException();
12588 e.fillInStackTrace();
12589 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12590 }
12591
12592 mAdjSeq++;
12593
12594 // First try updating the OOM adjustment for each of the
12595 // application processes based on their current state.
12596 int i = mLRUProcesses.size();
12597 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12598 while (i > 0) {
12599 i--;
12600 ProcessRecord app = mLRUProcesses.get(i);
12601 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12602 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12603 && app.curAdj == curHiddenAdj) {
12604 curHiddenAdj++;
12605 }
12606 } else {
12607 didOomAdj = false;
12608 }
12609 }
12610
12611 // todo: for now pretend like OOM ADJ didn't work, because things
12612 // aren't behaving as expected on Linux -- it's not killing processes.
12613 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12614 }
12615
12616 private final void trimApplications() {
12617 synchronized (this) {
12618 int i;
12619
12620 // First remove any unused application processes whose package
12621 // has been removed.
12622 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12623 final ProcessRecord app = mRemovedProcesses.get(i);
12624 if (app.activities.size() == 0
12625 && app.curReceiver == null && app.services.size() == 0) {
12626 Log.i(
12627 TAG, "Exiting empty application process "
12628 + app.processName + " ("
12629 + (app.thread != null ? app.thread.asBinder() : null)
12630 + ")\n");
12631 if (app.pid > 0 && app.pid != MY_PID) {
12632 Process.killProcess(app.pid);
12633 } else {
12634 try {
12635 app.thread.scheduleExit();
12636 } catch (Exception e) {
12637 // Ignore exceptions.
12638 }
12639 }
12640 cleanUpApplicationRecordLocked(app, false, -1);
12641 mRemovedProcesses.remove(i);
12642
12643 if (app.persistent) {
12644 if (app.persistent) {
12645 addAppLocked(app.info);
12646 }
12647 }
12648 }
12649 }
12650
12651 // Now try updating the OOM adjustment for each of the
12652 // application processes based on their current state.
12653 // If the setOomAdj() API is not supported, then go with our
12654 // back-up plan...
12655 if (!updateOomAdjLocked()) {
12656
12657 // Count how many processes are running services.
12658 int numServiceProcs = 0;
12659 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12660 final ProcessRecord app = mLRUProcesses.get(i);
12661
12662 if (app.persistent || app.services.size() != 0
12663 || app.curReceiver != null
12664 || app.persistentActivities > 0) {
12665 // Don't count processes holding services against our
12666 // maximum process count.
12667 if (localLOGV) Log.v(
12668 TAG, "Not trimming app " + app + " with services: "
12669 + app.services);
12670 numServiceProcs++;
12671 }
12672 }
12673
12674 int curMaxProcs = mProcessLimit;
12675 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12676 if (mAlwaysFinishActivities) {
12677 curMaxProcs = 1;
12678 }
12679 curMaxProcs += numServiceProcs;
12680
12681 // Quit as many processes as we can to get down to the desired
12682 // process count. First remove any processes that no longer
12683 // have activites running in them.
12684 for ( i=0;
12685 i<mLRUProcesses.size()
12686 && mLRUProcesses.size() > curMaxProcs;
12687 i++) {
12688 final ProcessRecord app = mLRUProcesses.get(i);
12689 // Quit an application only if it is not currently
12690 // running any activities.
12691 if (!app.persistent && app.activities.size() == 0
12692 && app.curReceiver == null && app.services.size() == 0) {
12693 Log.i(
12694 TAG, "Exiting empty application process "
12695 + app.processName + " ("
12696 + (app.thread != null ? app.thread.asBinder() : null)
12697 + ")\n");
12698 if (app.pid > 0 && app.pid != MY_PID) {
12699 Process.killProcess(app.pid);
12700 } else {
12701 try {
12702 app.thread.scheduleExit();
12703 } catch (Exception e) {
12704 // Ignore exceptions.
12705 }
12706 }
12707 // todo: For now we assume the application is not buggy
12708 // or evil, and will quit as a result of our request.
12709 // Eventually we need to drive this off of the death
12710 // notification, and kill the process if it takes too long.
12711 cleanUpApplicationRecordLocked(app, false, i);
12712 i--;
12713 }
12714 }
12715
12716 // If we still have too many processes, now from the least
12717 // recently used process we start finishing activities.
12718 if (Config.LOGV) Log.v(
12719 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12720 " of " + curMaxProcs + " processes");
12721 for ( i=0;
12722 i<mLRUProcesses.size()
12723 && mLRUProcesses.size() > curMaxProcs;
12724 i++) {
12725 final ProcessRecord app = mLRUProcesses.get(i);
12726 // Quit the application only if we have a state saved for
12727 // all of its activities.
12728 boolean canQuit = !app.persistent && app.curReceiver == null
12729 && app.services.size() == 0
12730 && app.persistentActivities == 0;
12731 int NUMA = app.activities.size();
12732 int j;
12733 if (Config.LOGV) Log.v(
12734 TAG, "Looking to quit " + app.processName);
12735 for (j=0; j<NUMA && canQuit; j++) {
12736 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12737 if (Config.LOGV) Log.v(
12738 TAG, " " + r.intent.getComponent().flattenToShortString()
12739 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12740 canQuit = (r.haveState || !r.stateNotNeeded)
12741 && !r.visible && r.stopped;
12742 }
12743 if (canQuit) {
12744 // Finish all of the activities, and then the app itself.
12745 for (j=0; j<NUMA; j++) {
12746 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12747 if (!r.finishing) {
12748 destroyActivityLocked(r, false);
12749 }
12750 r.resultTo = null;
12751 }
12752 Log.i(TAG, "Exiting application process "
12753 + app.processName + " ("
12754 + (app.thread != null ? app.thread.asBinder() : null)
12755 + ")\n");
12756 if (app.pid > 0 && app.pid != MY_PID) {
12757 Process.killProcess(app.pid);
12758 } else {
12759 try {
12760 app.thread.scheduleExit();
12761 } catch (Exception e) {
12762 // Ignore exceptions.
12763 }
12764 }
12765 // todo: For now we assume the application is not buggy
12766 // or evil, and will quit as a result of our request.
12767 // Eventually we need to drive this off of the death
12768 // notification, and kill the process if it takes too long.
12769 cleanUpApplicationRecordLocked(app, false, i);
12770 i--;
12771 //dump();
12772 }
12773 }
12774
12775 }
12776
12777 int curMaxActivities = MAX_ACTIVITIES;
12778 if (mAlwaysFinishActivities) {
12779 curMaxActivities = 1;
12780 }
12781
12782 // Finally, if there are too many activities now running, try to
12783 // finish as many as we can to get back down to the limit.
12784 for ( i=0;
12785 i<mLRUActivities.size()
12786 && mLRUActivities.size() > curMaxActivities;
12787 i++) {
12788 final HistoryRecord r
12789 = (HistoryRecord)mLRUActivities.get(i);
12790
12791 // We can finish this one if we have its icicle saved and
12792 // it is not persistent.
12793 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12794 && r.stopped && !r.persistent && !r.finishing) {
12795 final int origSize = mLRUActivities.size();
12796 destroyActivityLocked(r, true);
12797
12798 // This will remove it from the LRU list, so keep
12799 // our index at the same value. Note that this check to
12800 // see if the size changes is just paranoia -- if
12801 // something unexpected happens, we don't want to end up
12802 // in an infinite loop.
12803 if (origSize > mLRUActivities.size()) {
12804 i--;
12805 }
12806 }
12807 }
12808 }
12809 }
12810
12811 /** This method sends the specified signal to each of the persistent apps */
12812 public void signalPersistentProcesses(int sig) throws RemoteException {
12813 if (sig != Process.SIGNAL_USR1) {
12814 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12815 }
12816
12817 synchronized (this) {
12818 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12819 != PackageManager.PERMISSION_GRANTED) {
12820 throw new SecurityException("Requires permission "
12821 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12822 }
12823
12824 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12825 ProcessRecord r = mLRUProcesses.get(i);
12826 if (r.thread != null && r.persistent) {
12827 Process.sendSignal(r.pid, sig);
12828 }
12829 }
12830 }
12831 }
12832
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012833 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012834 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012835
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012836 try {
12837 synchronized (this) {
12838 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12839 // its own permission.
12840 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12841 != PackageManager.PERMISSION_GRANTED) {
12842 throw new SecurityException("Requires permission "
12843 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012844 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012845
12846 if (start && fd == null) {
12847 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012848 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012849
12850 ProcessRecord proc = null;
12851 try {
12852 int pid = Integer.parseInt(process);
12853 synchronized (mPidsSelfLocked) {
12854 proc = mPidsSelfLocked.get(pid);
12855 }
12856 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012857 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012858
12859 if (proc == null) {
12860 HashMap<String, SparseArray<ProcessRecord>> all
12861 = mProcessNames.getMap();
12862 SparseArray<ProcessRecord> procs = all.get(process);
12863 if (procs != null && procs.size() > 0) {
12864 proc = procs.valueAt(0);
12865 }
12866 }
12867
12868 if (proc == null || proc.thread == null) {
12869 throw new IllegalArgumentException("Unknown process: " + process);
12870 }
12871
12872 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12873 if (isSecure) {
12874 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12875 throw new SecurityException("Process not debuggable: " + proc);
12876 }
12877 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012878
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012879 proc.thread.profilerControl(start, path, fd);
12880 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012881 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012882 }
12883 } catch (RemoteException e) {
12884 throw new IllegalStateException("Process disappeared");
12885 } finally {
12886 if (fd != null) {
12887 try {
12888 fd.close();
12889 } catch (IOException e) {
12890 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012891 }
12892 }
12893 }
12894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012895 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12896 public void monitor() {
12897 synchronized (this) { }
12898 }
12899}