blob: ae790c9a8057f4874efc9349a1c5a99ebf294c48 [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 Hackbornde42bb62009-08-05 12:26:15 -07009140 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009141 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009142 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9143 if (r.adjSource != null || r.adjTarget != null) {
9144 pw.println(prefix + " " + r.adjTarget
9145 + " used by " + r.adjSource);
9146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 } else {
9148 pw.println(String.format("%s%s #%2d: %s",
9149 prefix, (r.persistent ? persistentLabel : normalLabel),
9150 i, r.toString()));
9151 }
9152 if (r.persistent) {
9153 numPers++;
9154 }
9155 }
9156 return numPers;
9157 }
9158
9159 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9160 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009161 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009162 long uptime = SystemClock.uptimeMillis();
9163 long realtime = SystemClock.elapsedRealtime();
9164
9165 if (isCheckinRequest) {
9166 // short checkin version
9167 pw.println(uptime + "," + realtime);
9168 pw.flush();
9169 } else {
9170 pw.println("Applications Memory Usage (kB):");
9171 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9172 }
9173 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9174 ProcessRecord r = (ProcessRecord)list.get(i);
9175 if (r.thread != null) {
9176 if (!isCheckinRequest) {
9177 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9178 pw.flush();
9179 }
9180 try {
9181 r.thread.asBinder().dump(fd, args);
9182 } catch (RemoteException e) {
9183 if (!isCheckinRequest) {
9184 pw.println("Got RemoteException!");
9185 pw.flush();
9186 }
9187 }
9188 }
9189 }
9190 }
9191
9192 /**
9193 * Searches array of arguments for the specified string
9194 * @param args array of argument strings
9195 * @param value value to search for
9196 * @return true if the value is contained in the array
9197 */
9198 private static boolean scanArgs(String[] args, String value) {
9199 if (args != null) {
9200 for (String arg : args) {
9201 if (value.equals(arg)) {
9202 return true;
9203 }
9204 }
9205 }
9206 return false;
9207 }
9208
Dianne Hackborn75b03852009-06-12 15:43:26 -07009209 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009210 int count = mHistory.size();
9211
9212 // convert the token to an entry in the history.
9213 HistoryRecord r = null;
9214 int index = -1;
9215 for (int i=count-1; i>=0; i--) {
9216 Object o = mHistory.get(i);
9217 if (o == token) {
9218 r = (HistoryRecord)o;
9219 index = i;
9220 break;
9221 }
9222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009223
9224 return index;
9225 }
9226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009227 private final void killServicesLocked(ProcessRecord app,
9228 boolean allowRestart) {
9229 // Report disconnected services.
9230 if (false) {
9231 // XXX we are letting the client link to the service for
9232 // death notifications.
9233 if (app.services.size() > 0) {
9234 Iterator it = app.services.iterator();
9235 while (it.hasNext()) {
9236 ServiceRecord r = (ServiceRecord)it.next();
9237 if (r.connections.size() > 0) {
9238 Iterator<ConnectionRecord> jt
9239 = r.connections.values().iterator();
9240 while (jt.hasNext()) {
9241 ConnectionRecord c = jt.next();
9242 if (c.binding.client != app) {
9243 try {
9244 //c.conn.connected(r.className, null);
9245 } catch (Exception e) {
9246 // todo: this should be asynchronous!
9247 Log.w(TAG, "Exception thrown disconnected servce "
9248 + r.shortName
9249 + " from app " + app.processName, e);
9250 }
9251 }
9252 }
9253 }
9254 }
9255 }
9256 }
9257
9258 // Clean up any connections this application has to other services.
9259 if (app.connections.size() > 0) {
9260 Iterator<ConnectionRecord> it = app.connections.iterator();
9261 while (it.hasNext()) {
9262 ConnectionRecord r = it.next();
9263 removeConnectionLocked(r, app, null);
9264 }
9265 }
9266 app.connections.clear();
9267
9268 if (app.services.size() != 0) {
9269 // Any services running in the application need to be placed
9270 // back in the pending list.
9271 Iterator it = app.services.iterator();
9272 while (it.hasNext()) {
9273 ServiceRecord sr = (ServiceRecord)it.next();
9274 synchronized (sr.stats.getBatteryStats()) {
9275 sr.stats.stopLaunchedLocked();
9276 }
9277 sr.app = null;
9278 sr.executeNesting = 0;
9279 mStoppingServices.remove(sr);
9280 if (sr.bindings.size() > 0) {
9281 Iterator<IntentBindRecord> bindings
9282 = sr.bindings.values().iterator();
9283 while (bindings.hasNext()) {
9284 IntentBindRecord b = bindings.next();
9285 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9286 + ": shouldUnbind=" + b.hasBound);
9287 b.binder = null;
9288 b.requested = b.received = b.hasBound = false;
9289 }
9290 }
9291
9292 if (sr.crashCount >= 2) {
9293 Log.w(TAG, "Service crashed " + sr.crashCount
9294 + " times, stopping: " + sr);
9295 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9296 sr.crashCount, sr.shortName, app.pid);
9297 bringDownServiceLocked(sr, true);
9298 } else if (!allowRestart) {
9299 bringDownServiceLocked(sr, true);
9300 } else {
9301 scheduleServiceRestartLocked(sr);
9302 }
9303 }
9304
9305 if (!allowRestart) {
9306 app.services.clear();
9307 }
9308 }
9309
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009310 // Make sure we have no more records on the stopping list.
9311 int i = mStoppingServices.size();
9312 while (i > 0) {
9313 i--;
9314 ServiceRecord sr = mStoppingServices.get(i);
9315 if (sr.app == app) {
9316 mStoppingServices.remove(i);
9317 }
9318 }
9319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009320 app.executingServices.clear();
9321 }
9322
9323 private final void removeDyingProviderLocked(ProcessRecord proc,
9324 ContentProviderRecord cpr) {
9325 synchronized (cpr) {
9326 cpr.launchingApp = null;
9327 cpr.notifyAll();
9328 }
9329
9330 mProvidersByClass.remove(cpr.info.name);
9331 String names[] = cpr.info.authority.split(";");
9332 for (int j = 0; j < names.length; j++) {
9333 mProvidersByName.remove(names[j]);
9334 }
9335
9336 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9337 while (cit.hasNext()) {
9338 ProcessRecord capp = cit.next();
9339 if (!capp.persistent && capp.thread != null
9340 && capp.pid != 0
9341 && capp.pid != MY_PID) {
9342 Log.i(TAG, "Killing app " + capp.processName
9343 + " (pid " + capp.pid
9344 + ") because provider " + cpr.info.name
9345 + " is in dying process " + proc.processName);
9346 Process.killProcess(capp.pid);
9347 }
9348 }
9349
9350 mLaunchingProviders.remove(cpr);
9351 }
9352
9353 /**
9354 * Main code for cleaning up a process when it has gone away. This is
9355 * called both as a result of the process dying, or directly when stopping
9356 * a process when running in single process mode.
9357 */
9358 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9359 boolean restarting, int index) {
9360 if (index >= 0) {
9361 mLRUProcesses.remove(index);
9362 }
9363
9364 // Dismiss any open dialogs.
9365 if (app.crashDialog != null) {
9366 app.crashDialog.dismiss();
9367 app.crashDialog = null;
9368 }
9369 if (app.anrDialog != null) {
9370 app.anrDialog.dismiss();
9371 app.anrDialog = null;
9372 }
9373 if (app.waitDialog != null) {
9374 app.waitDialog.dismiss();
9375 app.waitDialog = null;
9376 }
9377
9378 app.crashing = false;
9379 app.notResponding = false;
9380
9381 app.resetPackageList();
9382 app.thread = null;
9383 app.forcingToForeground = null;
9384 app.foregroundServices = false;
9385
9386 killServicesLocked(app, true);
9387
9388 boolean restart = false;
9389
9390 int NL = mLaunchingProviders.size();
9391
9392 // Remove published content providers.
9393 if (!app.pubProviders.isEmpty()) {
9394 Iterator it = app.pubProviders.values().iterator();
9395 while (it.hasNext()) {
9396 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9397 cpr.provider = null;
9398 cpr.app = null;
9399
9400 // See if someone is waiting for this provider... in which
9401 // case we don't remove it, but just let it restart.
9402 int i = 0;
9403 if (!app.bad) {
9404 for (; i<NL; i++) {
9405 if (mLaunchingProviders.get(i) == cpr) {
9406 restart = true;
9407 break;
9408 }
9409 }
9410 } else {
9411 i = NL;
9412 }
9413
9414 if (i >= NL) {
9415 removeDyingProviderLocked(app, cpr);
9416 NL = mLaunchingProviders.size();
9417 }
9418 }
9419 app.pubProviders.clear();
9420 }
9421
9422 // Look through the content providers we are waiting to have launched,
9423 // and if any run in this process then either schedule a restart of
9424 // the process or kill the client waiting for it if this process has
9425 // gone bad.
9426 for (int i=0; i<NL; i++) {
9427 ContentProviderRecord cpr = (ContentProviderRecord)
9428 mLaunchingProviders.get(i);
9429 if (cpr.launchingApp == app) {
9430 if (!app.bad) {
9431 restart = true;
9432 } else {
9433 removeDyingProviderLocked(app, cpr);
9434 NL = mLaunchingProviders.size();
9435 }
9436 }
9437 }
9438
9439 // Unregister from connected content providers.
9440 if (!app.conProviders.isEmpty()) {
9441 Iterator it = app.conProviders.iterator();
9442 while (it.hasNext()) {
9443 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9444 cpr.clients.remove(app);
9445 }
9446 app.conProviders.clear();
9447 }
9448
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009449 // At this point there may be remaining entries in mLaunchingProviders
9450 // where we were the only one waiting, so they are no longer of use.
9451 // Look for these and clean up if found.
9452 // XXX Commented out for now. Trying to figure out a way to reproduce
9453 // the actual situation to identify what is actually going on.
9454 if (false) {
9455 for (int i=0; i<NL; i++) {
9456 ContentProviderRecord cpr = (ContentProviderRecord)
9457 mLaunchingProviders.get(i);
9458 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9459 synchronized (cpr) {
9460 cpr.launchingApp = null;
9461 cpr.notifyAll();
9462 }
9463 }
9464 }
9465 }
9466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009467 skipCurrentReceiverLocked(app);
9468
9469 // Unregister any receivers.
9470 if (app.receivers.size() > 0) {
9471 Iterator<ReceiverList> it = app.receivers.iterator();
9472 while (it.hasNext()) {
9473 removeReceiverLocked(it.next());
9474 }
9475 app.receivers.clear();
9476 }
9477
Christopher Tate181fafa2009-05-14 11:12:14 -07009478 // If the app is undergoing backup, tell the backup manager about it
9479 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9480 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9481 try {
9482 IBackupManager bm = IBackupManager.Stub.asInterface(
9483 ServiceManager.getService(Context.BACKUP_SERVICE));
9484 bm.agentDisconnected(app.info.packageName);
9485 } catch (RemoteException e) {
9486 // can't happen; backup manager is local
9487 }
9488 }
9489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009490 // If the caller is restarting this app, then leave it in its
9491 // current lists and let the caller take care of it.
9492 if (restarting) {
9493 return;
9494 }
9495
9496 if (!app.persistent) {
9497 if (DEBUG_PROCESSES) Log.v(TAG,
9498 "Removing non-persistent process during cleanup: " + app);
9499 mProcessNames.remove(app.processName, app.info.uid);
9500 } else if (!app.removed) {
9501 // This app is persistent, so we need to keep its record around.
9502 // If it is not already on the pending app list, add it there
9503 // and start a new process for it.
9504 app.thread = null;
9505 app.forcingToForeground = null;
9506 app.foregroundServices = false;
9507 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9508 mPersistentStartingProcesses.add(app);
9509 restart = true;
9510 }
9511 }
9512 mProcessesOnHold.remove(app);
9513
The Android Open Source Project4df24232009-03-05 14:34:35 -08009514 if (app == mHomeProcess) {
9515 mHomeProcess = null;
9516 }
9517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009518 if (restart) {
9519 // We have components that still need to be running in the
9520 // process, so re-launch it.
9521 mProcessNames.put(app.processName, app.info.uid, app);
9522 startProcessLocked(app, "restart", app.processName);
9523 } else if (app.pid > 0 && app.pid != MY_PID) {
9524 // Goodbye!
9525 synchronized (mPidsSelfLocked) {
9526 mPidsSelfLocked.remove(app.pid);
9527 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9528 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009529 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009530 }
9531 }
9532
9533 // =========================================================
9534 // SERVICES
9535 // =========================================================
9536
9537 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9538 ActivityManager.RunningServiceInfo info =
9539 new ActivityManager.RunningServiceInfo();
9540 info.service = r.name;
9541 if (r.app != null) {
9542 info.pid = r.app.pid;
9543 }
9544 info.process = r.processName;
9545 info.foreground = r.isForeground;
9546 info.activeSince = r.createTime;
9547 info.started = r.startRequested;
9548 info.clientCount = r.connections.size();
9549 info.crashCount = r.crashCount;
9550 info.lastActivityTime = r.lastActivity;
9551 return info;
9552 }
9553
9554 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9555 int flags) {
9556 synchronized (this) {
9557 ArrayList<ActivityManager.RunningServiceInfo> res
9558 = new ArrayList<ActivityManager.RunningServiceInfo>();
9559
9560 if (mServices.size() > 0) {
9561 Iterator<ServiceRecord> it = mServices.values().iterator();
9562 while (it.hasNext() && res.size() < maxNum) {
9563 res.add(makeRunningServiceInfoLocked(it.next()));
9564 }
9565 }
9566
9567 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9568 ServiceRecord r = mRestartingServices.get(i);
9569 ActivityManager.RunningServiceInfo info =
9570 makeRunningServiceInfoLocked(r);
9571 info.restarting = r.nextRestartTime;
9572 res.add(info);
9573 }
9574
9575 return res;
9576 }
9577 }
9578
9579 private final ServiceRecord findServiceLocked(ComponentName name,
9580 IBinder token) {
9581 ServiceRecord r = mServices.get(name);
9582 return r == token ? r : null;
9583 }
9584
9585 private final class ServiceLookupResult {
9586 final ServiceRecord record;
9587 final String permission;
9588
9589 ServiceLookupResult(ServiceRecord _record, String _permission) {
9590 record = _record;
9591 permission = _permission;
9592 }
9593 };
9594
9595 private ServiceLookupResult findServiceLocked(Intent service,
9596 String resolvedType) {
9597 ServiceRecord r = null;
9598 if (service.getComponent() != null) {
9599 r = mServices.get(service.getComponent());
9600 }
9601 if (r == null) {
9602 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9603 r = mServicesByIntent.get(filter);
9604 }
9605
9606 if (r == null) {
9607 try {
9608 ResolveInfo rInfo =
9609 ActivityThread.getPackageManager().resolveService(
9610 service, resolvedType, 0);
9611 ServiceInfo sInfo =
9612 rInfo != null ? rInfo.serviceInfo : null;
9613 if (sInfo == null) {
9614 return null;
9615 }
9616
9617 ComponentName name = new ComponentName(
9618 sInfo.applicationInfo.packageName, sInfo.name);
9619 r = mServices.get(name);
9620 } catch (RemoteException ex) {
9621 // pm is in same process, this will never happen.
9622 }
9623 }
9624 if (r != null) {
9625 int callingPid = Binder.getCallingPid();
9626 int callingUid = Binder.getCallingUid();
9627 if (checkComponentPermission(r.permission,
9628 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9629 != PackageManager.PERMISSION_GRANTED) {
9630 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9631 + " from pid=" + callingPid
9632 + ", uid=" + callingUid
9633 + " requires " + r.permission);
9634 return new ServiceLookupResult(null, r.permission);
9635 }
9636 return new ServiceLookupResult(r, null);
9637 }
9638 return null;
9639 }
9640
9641 private class ServiceRestarter implements Runnable {
9642 private ServiceRecord mService;
9643
9644 void setService(ServiceRecord service) {
9645 mService = service;
9646 }
9647
9648 public void run() {
9649 synchronized(ActivityManagerService.this) {
9650 performServiceRestartLocked(mService);
9651 }
9652 }
9653 }
9654
9655 private ServiceLookupResult retrieveServiceLocked(Intent service,
9656 String resolvedType, int callingPid, int callingUid) {
9657 ServiceRecord r = null;
9658 if (service.getComponent() != null) {
9659 r = mServices.get(service.getComponent());
9660 }
9661 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9662 r = mServicesByIntent.get(filter);
9663 if (r == null) {
9664 try {
9665 ResolveInfo rInfo =
9666 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009667 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009668 ServiceInfo sInfo =
9669 rInfo != null ? rInfo.serviceInfo : null;
9670 if (sInfo == null) {
9671 Log.w(TAG, "Unable to start service " + service +
9672 ": not found");
9673 return null;
9674 }
9675
9676 ComponentName name = new ComponentName(
9677 sInfo.applicationInfo.packageName, sInfo.name);
9678 r = mServices.get(name);
9679 if (r == null) {
9680 filter = new Intent.FilterComparison(service.cloneFilter());
9681 ServiceRestarter res = new ServiceRestarter();
9682 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9683 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9684 synchronized (stats) {
9685 ss = stats.getServiceStatsLocked(
9686 sInfo.applicationInfo.uid, sInfo.packageName,
9687 sInfo.name);
9688 }
9689 r = new ServiceRecord(ss, name, filter, sInfo, res);
9690 res.setService(r);
9691 mServices.put(name, r);
9692 mServicesByIntent.put(filter, r);
9693
9694 // Make sure this component isn't in the pending list.
9695 int N = mPendingServices.size();
9696 for (int i=0; i<N; i++) {
9697 ServiceRecord pr = mPendingServices.get(i);
9698 if (pr.name.equals(name)) {
9699 mPendingServices.remove(i);
9700 i--;
9701 N--;
9702 }
9703 }
9704 }
9705 } catch (RemoteException ex) {
9706 // pm is in same process, this will never happen.
9707 }
9708 }
9709 if (r != null) {
9710 if (checkComponentPermission(r.permission,
9711 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9712 != PackageManager.PERMISSION_GRANTED) {
9713 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9714 + " from pid=" + Binder.getCallingPid()
9715 + ", uid=" + Binder.getCallingUid()
9716 + " requires " + r.permission);
9717 return new ServiceLookupResult(null, r.permission);
9718 }
9719 return new ServiceLookupResult(r, null);
9720 }
9721 return null;
9722 }
9723
9724 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9725 long now = SystemClock.uptimeMillis();
9726 if (r.executeNesting == 0 && r.app != null) {
9727 if (r.app.executingServices.size() == 0) {
9728 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9729 msg.obj = r.app;
9730 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9731 }
9732 r.app.executingServices.add(r);
9733 }
9734 r.executeNesting++;
9735 r.executingStart = now;
9736 }
9737
9738 private final void sendServiceArgsLocked(ServiceRecord r,
9739 boolean oomAdjusted) {
9740 final int N = r.startArgs.size();
9741 if (N == 0) {
9742 return;
9743 }
9744
9745 final int BASEID = r.lastStartId - N + 1;
9746 int i = 0;
9747 while (i < N) {
9748 try {
9749 Intent args = r.startArgs.get(i);
9750 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9751 + r.name + " " + r.intent + " args=" + args);
9752 bumpServiceExecutingLocked(r);
9753 if (!oomAdjusted) {
9754 oomAdjusted = true;
9755 updateOomAdjLocked(r.app);
9756 }
9757 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9758 i++;
9759 } catch (Exception e) {
9760 break;
9761 }
9762 }
9763 if (i == N) {
9764 r.startArgs.clear();
9765 } else {
9766 while (i > 0) {
9767 r.startArgs.remove(0);
9768 i--;
9769 }
9770 }
9771 }
9772
9773 private final boolean requestServiceBindingLocked(ServiceRecord r,
9774 IntentBindRecord i, boolean rebind) {
9775 if (r.app == null || r.app.thread == null) {
9776 // If service is not currently running, can't yet bind.
9777 return false;
9778 }
9779 if ((!i.requested || rebind) && i.apps.size() > 0) {
9780 try {
9781 bumpServiceExecutingLocked(r);
9782 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9783 + ": shouldUnbind=" + i.hasBound);
9784 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9785 if (!rebind) {
9786 i.requested = true;
9787 }
9788 i.hasBound = true;
9789 i.doRebind = false;
9790 } catch (RemoteException e) {
9791 return false;
9792 }
9793 }
9794 return true;
9795 }
9796
9797 private final void requestServiceBindingsLocked(ServiceRecord r) {
9798 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9799 while (bindings.hasNext()) {
9800 IntentBindRecord i = bindings.next();
9801 if (!requestServiceBindingLocked(r, i, false)) {
9802 break;
9803 }
9804 }
9805 }
9806
9807 private final void realStartServiceLocked(ServiceRecord r,
9808 ProcessRecord app) throws RemoteException {
9809 if (app.thread == null) {
9810 throw new RemoteException();
9811 }
9812
9813 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009814 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009815
9816 app.services.add(r);
9817 bumpServiceExecutingLocked(r);
9818 updateLRUListLocked(app, true);
9819
9820 boolean created = false;
9821 try {
9822 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9823 + r.name + " " + r.intent);
9824 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9825 System.identityHashCode(r), r.shortName,
9826 r.intent.getIntent().toString(), r.app.pid);
9827 synchronized (r.stats.getBatteryStats()) {
9828 r.stats.startLaunchedLocked();
9829 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009830 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009831 app.thread.scheduleCreateService(r, r.serviceInfo);
9832 created = true;
9833 } finally {
9834 if (!created) {
9835 app.services.remove(r);
9836 scheduleServiceRestartLocked(r);
9837 }
9838 }
9839
9840 requestServiceBindingsLocked(r);
9841 sendServiceArgsLocked(r, true);
9842 }
9843
9844 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9845 r.totalRestartCount++;
9846 if (r.restartDelay == 0) {
9847 r.restartCount++;
9848 r.restartDelay = SERVICE_RESTART_DURATION;
9849 } else {
9850 // If it has been a "reasonably long time" since the service
9851 // was started, then reset our restart duration back to
9852 // the beginning, so we don't infinitely increase the duration
9853 // on a service that just occasionally gets killed (which is
9854 // a normal case, due to process being killed to reclaim memory).
9855 long now = SystemClock.uptimeMillis();
9856 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9857 r.restartCount = 1;
9858 r.restartDelay = SERVICE_RESTART_DURATION;
9859 } else {
9860 r.restartDelay *= 2;
9861 }
9862 }
9863 if (!mRestartingServices.contains(r)) {
9864 mRestartingServices.add(r);
9865 }
9866 mHandler.removeCallbacks(r.restarter);
9867 mHandler.postDelayed(r.restarter, r.restartDelay);
9868 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9869 Log.w(TAG, "Scheduling restart of crashed service "
9870 + r.shortName + " in " + r.restartDelay + "ms");
9871 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9872 r.shortName, r.restartDelay);
9873
9874 Message msg = Message.obtain();
9875 msg.what = SERVICE_ERROR_MSG;
9876 msg.obj = r;
9877 mHandler.sendMessage(msg);
9878 }
9879
9880 final void performServiceRestartLocked(ServiceRecord r) {
9881 if (!mRestartingServices.contains(r)) {
9882 return;
9883 }
9884 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9885 }
9886
9887 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9888 if (r.restartDelay == 0) {
9889 return false;
9890 }
9891 r.resetRestartCounter();
9892 mRestartingServices.remove(r);
9893 mHandler.removeCallbacks(r.restarter);
9894 return true;
9895 }
9896
9897 private final boolean bringUpServiceLocked(ServiceRecord r,
9898 int intentFlags, boolean whileRestarting) {
9899 //Log.i(TAG, "Bring up service:");
9900 //r.dump(" ");
9901
9902 if (r.app != null) {
9903 sendServiceArgsLocked(r, false);
9904 return true;
9905 }
9906
9907 if (!whileRestarting && r.restartDelay > 0) {
9908 // If waiting for a restart, then do nothing.
9909 return true;
9910 }
9911
9912 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9913 + " " + r.intent);
9914
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009915 // We are now bringing the service up, so no longer in the
9916 // restarting state.
9917 mRestartingServices.remove(r);
9918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009919 final String appName = r.processName;
9920 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9921 if (app != null && app.thread != null) {
9922 try {
9923 realStartServiceLocked(r, app);
9924 return true;
9925 } catch (RemoteException e) {
9926 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9927 }
9928
9929 // If a dead object exception was thrown -- fall through to
9930 // restart the application.
9931 }
9932
9933 if (!mPendingServices.contains(r)) {
9934 // Not running -- get it started, and enqueue this service record
9935 // to be executed when the app comes up.
9936 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9937 "service", r.name) == null) {
9938 Log.w(TAG, "Unable to launch app "
9939 + r.appInfo.packageName + "/"
9940 + r.appInfo.uid + " for service "
9941 + r.intent.getIntent() + ": process is bad");
9942 bringDownServiceLocked(r, true);
9943 return false;
9944 }
9945 mPendingServices.add(r);
9946 }
9947 return true;
9948 }
9949
9950 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9951 //Log.i(TAG, "Bring down service:");
9952 //r.dump(" ");
9953
9954 // Does it still need to run?
9955 if (!force && r.startRequested) {
9956 return;
9957 }
9958 if (r.connections.size() > 0) {
9959 if (!force) {
9960 // XXX should probably keep a count of the number of auto-create
9961 // connections directly in the service.
9962 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9963 while (it.hasNext()) {
9964 ConnectionRecord cr = it.next();
9965 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9966 return;
9967 }
9968 }
9969 }
9970
9971 // Report to all of the connections that the service is no longer
9972 // available.
9973 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9974 while (it.hasNext()) {
9975 ConnectionRecord c = it.next();
9976 try {
9977 // todo: shouldn't be a synchronous call!
9978 c.conn.connected(r.name, null);
9979 } catch (Exception e) {
9980 Log.w(TAG, "Failure disconnecting service " + r.name +
9981 " to connection " + c.conn.asBinder() +
9982 " (in " + c.binding.client.processName + ")", e);
9983 }
9984 }
9985 }
9986
9987 // Tell the service that it has been unbound.
9988 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9989 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9990 while (it.hasNext()) {
9991 IntentBindRecord ibr = it.next();
9992 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9993 + ": hasBound=" + ibr.hasBound);
9994 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9995 try {
9996 bumpServiceExecutingLocked(r);
9997 updateOomAdjLocked(r.app);
9998 ibr.hasBound = false;
9999 r.app.thread.scheduleUnbindService(r,
10000 ibr.intent.getIntent());
10001 } catch (Exception e) {
10002 Log.w(TAG, "Exception when unbinding service "
10003 + r.shortName, e);
10004 serviceDoneExecutingLocked(r, true);
10005 }
10006 }
10007 }
10008 }
10009
10010 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10011 + " " + r.intent);
10012 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10013 System.identityHashCode(r), r.shortName,
10014 (r.app != null) ? r.app.pid : -1);
10015
10016 mServices.remove(r.name);
10017 mServicesByIntent.remove(r.intent);
10018 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10019 r.totalRestartCount = 0;
10020 unscheduleServiceRestartLocked(r);
10021
10022 // Also make sure it is not on the pending list.
10023 int N = mPendingServices.size();
10024 for (int i=0; i<N; i++) {
10025 if (mPendingServices.get(i) == r) {
10026 mPendingServices.remove(i);
10027 if (DEBUG_SERVICE) Log.v(
10028 TAG, "Removed pending service: " + r.shortName);
10029 i--;
10030 N--;
10031 }
10032 }
10033
10034 if (r.app != null) {
10035 synchronized (r.stats.getBatteryStats()) {
10036 r.stats.stopLaunchedLocked();
10037 }
10038 r.app.services.remove(r);
10039 if (r.app.thread != null) {
10040 updateServiceForegroundLocked(r.app, false);
10041 try {
10042 Log.i(TAG, "Stopping service: " + r.shortName);
10043 bumpServiceExecutingLocked(r);
10044 mStoppingServices.add(r);
10045 updateOomAdjLocked(r.app);
10046 r.app.thread.scheduleStopService(r);
10047 } catch (Exception e) {
10048 Log.w(TAG, "Exception when stopping service "
10049 + r.shortName, e);
10050 serviceDoneExecutingLocked(r, true);
10051 }
10052 } else {
10053 if (DEBUG_SERVICE) Log.v(
10054 TAG, "Removed service that has no process: " + r.shortName);
10055 }
10056 } else {
10057 if (DEBUG_SERVICE) Log.v(
10058 TAG, "Removed service that is not running: " + r.shortName);
10059 }
10060 }
10061
10062 ComponentName startServiceLocked(IApplicationThread caller,
10063 Intent service, String resolvedType,
10064 int callingPid, int callingUid) {
10065 synchronized(this) {
10066 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10067 + " type=" + resolvedType + " args=" + service.getExtras());
10068
10069 if (caller != null) {
10070 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10071 if (callerApp == null) {
10072 throw new SecurityException(
10073 "Unable to find app for caller " + caller
10074 + " (pid=" + Binder.getCallingPid()
10075 + ") when starting service " + service);
10076 }
10077 }
10078
10079 ServiceLookupResult res =
10080 retrieveServiceLocked(service, resolvedType,
10081 callingPid, callingUid);
10082 if (res == null) {
10083 return null;
10084 }
10085 if (res.record == null) {
10086 return new ComponentName("!", res.permission != null
10087 ? res.permission : "private to package");
10088 }
10089 ServiceRecord r = res.record;
10090 if (unscheduleServiceRestartLocked(r)) {
10091 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10092 + r.shortName);
10093 }
10094 r.startRequested = true;
10095 r.startArgs.add(service);
10096 r.lastStartId++;
10097 if (r.lastStartId < 1) {
10098 r.lastStartId = 1;
10099 }
10100 r.lastActivity = SystemClock.uptimeMillis();
10101 synchronized (r.stats.getBatteryStats()) {
10102 r.stats.startRunningLocked();
10103 }
10104 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10105 return new ComponentName("!", "Service process is bad");
10106 }
10107 return r.name;
10108 }
10109 }
10110
10111 public ComponentName startService(IApplicationThread caller, Intent service,
10112 String resolvedType) {
10113 // Refuse possible leaked file descriptors
10114 if (service != null && service.hasFileDescriptors() == true) {
10115 throw new IllegalArgumentException("File descriptors passed in Intent");
10116 }
10117
10118 synchronized(this) {
10119 final int callingPid = Binder.getCallingPid();
10120 final int callingUid = Binder.getCallingUid();
10121 final long origId = Binder.clearCallingIdentity();
10122 ComponentName res = startServiceLocked(caller, service,
10123 resolvedType, callingPid, callingUid);
10124 Binder.restoreCallingIdentity(origId);
10125 return res;
10126 }
10127 }
10128
10129 ComponentName startServiceInPackage(int uid,
10130 Intent service, String resolvedType) {
10131 synchronized(this) {
10132 final long origId = Binder.clearCallingIdentity();
10133 ComponentName res = startServiceLocked(null, service,
10134 resolvedType, -1, uid);
10135 Binder.restoreCallingIdentity(origId);
10136 return res;
10137 }
10138 }
10139
10140 public int stopService(IApplicationThread caller, Intent service,
10141 String resolvedType) {
10142 // Refuse possible leaked file descriptors
10143 if (service != null && service.hasFileDescriptors() == true) {
10144 throw new IllegalArgumentException("File descriptors passed in Intent");
10145 }
10146
10147 synchronized(this) {
10148 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10149 + " type=" + resolvedType);
10150
10151 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10152 if (caller != null && callerApp == null) {
10153 throw new SecurityException(
10154 "Unable to find app for caller " + caller
10155 + " (pid=" + Binder.getCallingPid()
10156 + ") when stopping service " + service);
10157 }
10158
10159 // If this service is active, make sure it is stopped.
10160 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10161 if (r != null) {
10162 if (r.record != null) {
10163 synchronized (r.record.stats.getBatteryStats()) {
10164 r.record.stats.stopRunningLocked();
10165 }
10166 r.record.startRequested = false;
10167 final long origId = Binder.clearCallingIdentity();
10168 bringDownServiceLocked(r.record, false);
10169 Binder.restoreCallingIdentity(origId);
10170 return 1;
10171 }
10172 return -1;
10173 }
10174 }
10175
10176 return 0;
10177 }
10178
10179 public IBinder peekService(Intent service, String resolvedType) {
10180 // Refuse possible leaked file descriptors
10181 if (service != null && service.hasFileDescriptors() == true) {
10182 throw new IllegalArgumentException("File descriptors passed in Intent");
10183 }
10184
10185 IBinder ret = null;
10186
10187 synchronized(this) {
10188 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10189
10190 if (r != null) {
10191 // r.record is null if findServiceLocked() failed the caller permission check
10192 if (r.record == null) {
10193 throw new SecurityException(
10194 "Permission Denial: Accessing service " + r.record.name
10195 + " from pid=" + Binder.getCallingPid()
10196 + ", uid=" + Binder.getCallingUid()
10197 + " requires " + r.permission);
10198 }
10199 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10200 if (ib != null) {
10201 ret = ib.binder;
10202 }
10203 }
10204 }
10205
10206 return ret;
10207 }
10208
10209 public boolean stopServiceToken(ComponentName className, IBinder token,
10210 int startId) {
10211 synchronized(this) {
10212 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10213 + " " + token + " startId=" + startId);
10214 ServiceRecord r = findServiceLocked(className, token);
10215 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10216 synchronized (r.stats.getBatteryStats()) {
10217 r.stats.stopRunningLocked();
10218 r.startRequested = false;
10219 }
10220 final long origId = Binder.clearCallingIdentity();
10221 bringDownServiceLocked(r, false);
10222 Binder.restoreCallingIdentity(origId);
10223 return true;
10224 }
10225 }
10226 return false;
10227 }
10228
10229 public void setServiceForeground(ComponentName className, IBinder token,
10230 boolean isForeground) {
10231 synchronized(this) {
10232 ServiceRecord r = findServiceLocked(className, token);
10233 if (r != null) {
10234 if (r.isForeground != isForeground) {
10235 final long origId = Binder.clearCallingIdentity();
10236 r.isForeground = isForeground;
10237 if (r.app != null) {
10238 updateServiceForegroundLocked(r.app, true);
10239 }
10240 Binder.restoreCallingIdentity(origId);
10241 }
10242 }
10243 }
10244 }
10245
10246 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10247 boolean anyForeground = false;
10248 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10249 if (sr.isForeground) {
10250 anyForeground = true;
10251 break;
10252 }
10253 }
10254 if (anyForeground != proc.foregroundServices) {
10255 proc.foregroundServices = anyForeground;
10256 if (oomAdj) {
10257 updateOomAdjLocked();
10258 }
10259 }
10260 }
10261
10262 public int bindService(IApplicationThread caller, IBinder token,
10263 Intent service, String resolvedType,
10264 IServiceConnection connection, int flags) {
10265 // Refuse possible leaked file descriptors
10266 if (service != null && service.hasFileDescriptors() == true) {
10267 throw new IllegalArgumentException("File descriptors passed in Intent");
10268 }
10269
10270 synchronized(this) {
10271 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10272 + " type=" + resolvedType + " conn=" + connection.asBinder()
10273 + " flags=0x" + Integer.toHexString(flags));
10274 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10275 if (callerApp == null) {
10276 throw new SecurityException(
10277 "Unable to find app for caller " + caller
10278 + " (pid=" + Binder.getCallingPid()
10279 + ") when binding service " + service);
10280 }
10281
10282 HistoryRecord activity = null;
10283 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010284 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010285 if (aindex < 0) {
10286 Log.w(TAG, "Binding with unknown activity: " + token);
10287 return 0;
10288 }
10289 activity = (HistoryRecord)mHistory.get(aindex);
10290 }
10291
10292 ServiceLookupResult res =
10293 retrieveServiceLocked(service, resolvedType,
10294 Binder.getCallingPid(), Binder.getCallingUid());
10295 if (res == null) {
10296 return 0;
10297 }
10298 if (res.record == null) {
10299 return -1;
10300 }
10301 ServiceRecord s = res.record;
10302
10303 final long origId = Binder.clearCallingIdentity();
10304
10305 if (unscheduleServiceRestartLocked(s)) {
10306 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10307 + s.shortName);
10308 }
10309
10310 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10311 ConnectionRecord c = new ConnectionRecord(b, activity,
10312 connection, flags);
10313
10314 IBinder binder = connection.asBinder();
10315 s.connections.put(binder, c);
10316 b.connections.add(c);
10317 if (activity != null) {
10318 if (activity.connections == null) {
10319 activity.connections = new HashSet<ConnectionRecord>();
10320 }
10321 activity.connections.add(c);
10322 }
10323 b.client.connections.add(c);
10324 mServiceConnections.put(binder, c);
10325
10326 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10327 s.lastActivity = SystemClock.uptimeMillis();
10328 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10329 return 0;
10330 }
10331 }
10332
10333 if (s.app != null) {
10334 // This could have made the service more important.
10335 updateOomAdjLocked(s.app);
10336 }
10337
10338 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10339 + ": received=" + b.intent.received
10340 + " apps=" + b.intent.apps.size()
10341 + " doRebind=" + b.intent.doRebind);
10342
10343 if (s.app != null && b.intent.received) {
10344 // Service is already running, so we can immediately
10345 // publish the connection.
10346 try {
10347 c.conn.connected(s.name, b.intent.binder);
10348 } catch (Exception e) {
10349 Log.w(TAG, "Failure sending service " + s.shortName
10350 + " to connection " + c.conn.asBinder()
10351 + " (in " + c.binding.client.processName + ")", e);
10352 }
10353
10354 // If this is the first app connected back to this binding,
10355 // and the service had previously asked to be told when
10356 // rebound, then do so.
10357 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10358 requestServiceBindingLocked(s, b.intent, true);
10359 }
10360 } else if (!b.intent.requested) {
10361 requestServiceBindingLocked(s, b.intent, false);
10362 }
10363
10364 Binder.restoreCallingIdentity(origId);
10365 }
10366
10367 return 1;
10368 }
10369
10370 private void removeConnectionLocked(
10371 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10372 IBinder binder = c.conn.asBinder();
10373 AppBindRecord b = c.binding;
10374 ServiceRecord s = b.service;
10375 s.connections.remove(binder);
10376 b.connections.remove(c);
10377 if (c.activity != null && c.activity != skipAct) {
10378 if (c.activity.connections != null) {
10379 c.activity.connections.remove(c);
10380 }
10381 }
10382 if (b.client != skipApp) {
10383 b.client.connections.remove(c);
10384 }
10385 mServiceConnections.remove(binder);
10386
10387 if (b.connections.size() == 0) {
10388 b.intent.apps.remove(b.client);
10389 }
10390
10391 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10392 + ": shouldUnbind=" + b.intent.hasBound);
10393 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10394 && b.intent.hasBound) {
10395 try {
10396 bumpServiceExecutingLocked(s);
10397 updateOomAdjLocked(s.app);
10398 b.intent.hasBound = false;
10399 // Assume the client doesn't want to know about a rebind;
10400 // we will deal with that later if it asks for one.
10401 b.intent.doRebind = false;
10402 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10403 } catch (Exception e) {
10404 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10405 serviceDoneExecutingLocked(s, true);
10406 }
10407 }
10408
10409 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10410 bringDownServiceLocked(s, false);
10411 }
10412 }
10413
10414 public boolean unbindService(IServiceConnection connection) {
10415 synchronized (this) {
10416 IBinder binder = connection.asBinder();
10417 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10418 ConnectionRecord r = mServiceConnections.get(binder);
10419 if (r == null) {
10420 Log.w(TAG, "Unbind failed: could not find connection for "
10421 + connection.asBinder());
10422 return false;
10423 }
10424
10425 final long origId = Binder.clearCallingIdentity();
10426
10427 removeConnectionLocked(r, null, null);
10428
10429 if (r.binding.service.app != null) {
10430 // This could have made the service less important.
10431 updateOomAdjLocked(r.binding.service.app);
10432 }
10433
10434 Binder.restoreCallingIdentity(origId);
10435 }
10436
10437 return true;
10438 }
10439
10440 public void publishService(IBinder token, Intent intent, IBinder service) {
10441 // Refuse possible leaked file descriptors
10442 if (intent != null && intent.hasFileDescriptors() == true) {
10443 throw new IllegalArgumentException("File descriptors passed in Intent");
10444 }
10445
10446 synchronized(this) {
10447 if (!(token instanceof ServiceRecord)) {
10448 throw new IllegalArgumentException("Invalid service token");
10449 }
10450 ServiceRecord r = (ServiceRecord)token;
10451
10452 final long origId = Binder.clearCallingIdentity();
10453
10454 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10455 + " " + intent + ": " + service);
10456 if (r != null) {
10457 Intent.FilterComparison filter
10458 = new Intent.FilterComparison(intent);
10459 IntentBindRecord b = r.bindings.get(filter);
10460 if (b != null && !b.received) {
10461 b.binder = service;
10462 b.requested = true;
10463 b.received = true;
10464 if (r.connections.size() > 0) {
10465 Iterator<ConnectionRecord> it
10466 = r.connections.values().iterator();
10467 while (it.hasNext()) {
10468 ConnectionRecord c = it.next();
10469 if (!filter.equals(c.binding.intent.intent)) {
10470 if (DEBUG_SERVICE) Log.v(
10471 TAG, "Not publishing to: " + c);
10472 if (DEBUG_SERVICE) Log.v(
10473 TAG, "Bound intent: " + c.binding.intent.intent);
10474 if (DEBUG_SERVICE) Log.v(
10475 TAG, "Published intent: " + intent);
10476 continue;
10477 }
10478 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10479 try {
10480 c.conn.connected(r.name, service);
10481 } catch (Exception e) {
10482 Log.w(TAG, "Failure sending service " + r.name +
10483 " to connection " + c.conn.asBinder() +
10484 " (in " + c.binding.client.processName + ")", e);
10485 }
10486 }
10487 }
10488 }
10489
10490 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10491
10492 Binder.restoreCallingIdentity(origId);
10493 }
10494 }
10495 }
10496
10497 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10498 // Refuse possible leaked file descriptors
10499 if (intent != null && intent.hasFileDescriptors() == true) {
10500 throw new IllegalArgumentException("File descriptors passed in Intent");
10501 }
10502
10503 synchronized(this) {
10504 if (!(token instanceof ServiceRecord)) {
10505 throw new IllegalArgumentException("Invalid service token");
10506 }
10507 ServiceRecord r = (ServiceRecord)token;
10508
10509 final long origId = Binder.clearCallingIdentity();
10510
10511 if (r != null) {
10512 Intent.FilterComparison filter
10513 = new Intent.FilterComparison(intent);
10514 IntentBindRecord b = r.bindings.get(filter);
10515 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10516 + " at " + b + ": apps="
10517 + (b != null ? b.apps.size() : 0));
10518 if (b != null) {
10519 if (b.apps.size() > 0) {
10520 // Applications have already bound since the last
10521 // unbind, so just rebind right here.
10522 requestServiceBindingLocked(r, b, true);
10523 } else {
10524 // Note to tell the service the next time there is
10525 // a new client.
10526 b.doRebind = true;
10527 }
10528 }
10529
10530 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10531
10532 Binder.restoreCallingIdentity(origId);
10533 }
10534 }
10535 }
10536
10537 public void serviceDoneExecuting(IBinder token) {
10538 synchronized(this) {
10539 if (!(token instanceof ServiceRecord)) {
10540 throw new IllegalArgumentException("Invalid service token");
10541 }
10542 ServiceRecord r = (ServiceRecord)token;
10543 boolean inStopping = mStoppingServices.contains(token);
10544 if (r != null) {
10545 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10546 + ": nesting=" + r.executeNesting
10547 + ", inStopping=" + inStopping);
10548 if (r != token) {
10549 Log.w(TAG, "Done executing service " + r.name
10550 + " with incorrect token: given " + token
10551 + ", expected " + r);
10552 return;
10553 }
10554
10555 final long origId = Binder.clearCallingIdentity();
10556 serviceDoneExecutingLocked(r, inStopping);
10557 Binder.restoreCallingIdentity(origId);
10558 } else {
10559 Log.w(TAG, "Done executing unknown service " + r.name
10560 + " with token " + token);
10561 }
10562 }
10563 }
10564
10565 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10566 r.executeNesting--;
10567 if (r.executeNesting <= 0 && r.app != null) {
10568 r.app.executingServices.remove(r);
10569 if (r.app.executingServices.size() == 0) {
10570 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10571 }
10572 if (inStopping) {
10573 mStoppingServices.remove(r);
10574 }
10575 updateOomAdjLocked(r.app);
10576 }
10577 }
10578
10579 void serviceTimeout(ProcessRecord proc) {
10580 synchronized(this) {
10581 if (proc.executingServices.size() == 0 || proc.thread == null) {
10582 return;
10583 }
10584 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10585 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10586 ServiceRecord timeout = null;
10587 long nextTime = 0;
10588 while (it.hasNext()) {
10589 ServiceRecord sr = it.next();
10590 if (sr.executingStart < maxTime) {
10591 timeout = sr;
10592 break;
10593 }
10594 if (sr.executingStart > nextTime) {
10595 nextTime = sr.executingStart;
10596 }
10597 }
10598 if (timeout != null && mLRUProcesses.contains(proc)) {
10599 Log.w(TAG, "Timeout executing service: " + timeout);
10600 appNotRespondingLocked(proc, null, "Executing service "
10601 + timeout.name);
10602 } else {
10603 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10604 msg.obj = proc;
10605 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10606 }
10607 }
10608 }
10609
10610 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010611 // BACKUP AND RESTORE
10612 // =========================================================
10613
10614 // Cause the target app to be launched if necessary and its backup agent
10615 // instantiated. The backup agent will invoke backupAgentCreated() on the
10616 // activity manager to announce its creation.
10617 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10618 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10619 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10620
10621 synchronized(this) {
10622 // !!! TODO: currently no check here that we're already bound
10623 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10624 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10625 synchronized (stats) {
10626 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10627 }
10628
10629 BackupRecord r = new BackupRecord(ss, app, backupMode);
10630 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10631 // startProcessLocked() returns existing proc's record if it's already running
10632 ProcessRecord proc = startProcessLocked(app.processName, app,
10633 false, 0, "backup", hostingName);
10634 if (proc == null) {
10635 Log.e(TAG, "Unable to start backup agent process " + r);
10636 return false;
10637 }
10638
10639 r.app = proc;
10640 mBackupTarget = r;
10641 mBackupAppName = app.packageName;
10642
Christopher Tate6fa95972009-06-05 18:43:55 -070010643 // Try not to kill the process during backup
10644 updateOomAdjLocked(proc);
10645
Christopher Tate181fafa2009-05-14 11:12:14 -070010646 // If the process is already attached, schedule the creation of the backup agent now.
10647 // If it is not yet live, this will be done when it attaches to the framework.
10648 if (proc.thread != null) {
10649 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10650 try {
10651 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10652 } catch (RemoteException e) {
10653 // !!! TODO: notify the backup manager that we crashed, or rely on
10654 // death notices, or...?
10655 }
10656 } else {
10657 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10658 }
10659 // Invariants: at this point, the target app process exists and the application
10660 // is either already running or in the process of coming up. mBackupTarget and
10661 // mBackupAppName describe the app, so that when it binds back to the AM we
10662 // know that it's scheduled for a backup-agent operation.
10663 }
10664
10665 return true;
10666 }
10667
10668 // A backup agent has just come up
10669 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10670 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10671 + " = " + agent);
10672
10673 synchronized(this) {
10674 if (!agentPackageName.equals(mBackupAppName)) {
10675 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10676 return;
10677 }
10678
Christopher Tate043dadc2009-06-02 16:11:00 -070010679 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010680 try {
10681 IBackupManager bm = IBackupManager.Stub.asInterface(
10682 ServiceManager.getService(Context.BACKUP_SERVICE));
10683 bm.agentConnected(agentPackageName, agent);
10684 } catch (RemoteException e) {
10685 // can't happen; the backup manager service is local
10686 } catch (Exception e) {
10687 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10688 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010689 } finally {
10690 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010691 }
10692 }
10693 }
10694
10695 // done with this agent
10696 public void unbindBackupAgent(ApplicationInfo appInfo) {
10697 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010698 if (appInfo == null) {
10699 Log.w(TAG, "unbind backup agent for null app");
10700 return;
10701 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010702
10703 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010704 if (mBackupAppName == null) {
10705 Log.w(TAG, "Unbinding backup agent with no active backup");
10706 return;
10707 }
10708
Christopher Tate181fafa2009-05-14 11:12:14 -070010709 if (!mBackupAppName.equals(appInfo.packageName)) {
10710 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10711 return;
10712 }
10713
Christopher Tate6fa95972009-06-05 18:43:55 -070010714 ProcessRecord proc = mBackupTarget.app;
10715 mBackupTarget = null;
10716 mBackupAppName = null;
10717
10718 // Not backing this app up any more; reset its OOM adjustment
10719 updateOomAdjLocked(proc);
10720
Christopher Tatec7b31e32009-06-10 15:49:30 -070010721 // If the app crashed during backup, 'thread' will be null here
10722 if (proc.thread != null) {
10723 try {
10724 proc.thread.scheduleDestroyBackupAgent(appInfo);
10725 } catch (Exception e) {
10726 Log.e(TAG, "Exception when unbinding backup agent:");
10727 e.printStackTrace();
10728 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010729 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010730 }
10731 }
10732 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010733 // BROADCASTS
10734 // =========================================================
10735
10736 private final List getStickies(String action, IntentFilter filter,
10737 List cur) {
10738 final ContentResolver resolver = mContext.getContentResolver();
10739 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10740 if (list == null) {
10741 return cur;
10742 }
10743 int N = list.size();
10744 for (int i=0; i<N; i++) {
10745 Intent intent = list.get(i);
10746 if (filter.match(resolver, intent, true, TAG) >= 0) {
10747 if (cur == null) {
10748 cur = new ArrayList<Intent>();
10749 }
10750 cur.add(intent);
10751 }
10752 }
10753 return cur;
10754 }
10755
10756 private final void scheduleBroadcastsLocked() {
10757 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10758 + mBroadcastsScheduled);
10759
10760 if (mBroadcastsScheduled) {
10761 return;
10762 }
10763 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10764 mBroadcastsScheduled = true;
10765 }
10766
10767 public Intent registerReceiver(IApplicationThread caller,
10768 IIntentReceiver receiver, IntentFilter filter, String permission) {
10769 synchronized(this) {
10770 ProcessRecord callerApp = null;
10771 if (caller != null) {
10772 callerApp = getRecordForAppLocked(caller);
10773 if (callerApp == null) {
10774 throw new SecurityException(
10775 "Unable to find app for caller " + caller
10776 + " (pid=" + Binder.getCallingPid()
10777 + ") when registering receiver " + receiver);
10778 }
10779 }
10780
10781 List allSticky = null;
10782
10783 // Look for any matching sticky broadcasts...
10784 Iterator actions = filter.actionsIterator();
10785 if (actions != null) {
10786 while (actions.hasNext()) {
10787 String action = (String)actions.next();
10788 allSticky = getStickies(action, filter, allSticky);
10789 }
10790 } else {
10791 allSticky = getStickies(null, filter, allSticky);
10792 }
10793
10794 // The first sticky in the list is returned directly back to
10795 // the client.
10796 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10797
10798 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10799 + ": " + sticky);
10800
10801 if (receiver == null) {
10802 return sticky;
10803 }
10804
10805 ReceiverList rl
10806 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10807 if (rl == null) {
10808 rl = new ReceiverList(this, callerApp,
10809 Binder.getCallingPid(),
10810 Binder.getCallingUid(), receiver);
10811 if (rl.app != null) {
10812 rl.app.receivers.add(rl);
10813 } else {
10814 try {
10815 receiver.asBinder().linkToDeath(rl, 0);
10816 } catch (RemoteException e) {
10817 return sticky;
10818 }
10819 rl.linkedToDeath = true;
10820 }
10821 mRegisteredReceivers.put(receiver.asBinder(), rl);
10822 }
10823 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10824 rl.add(bf);
10825 if (!bf.debugCheck()) {
10826 Log.w(TAG, "==> For Dynamic broadast");
10827 }
10828 mReceiverResolver.addFilter(bf);
10829
10830 // Enqueue broadcasts for all existing stickies that match
10831 // this filter.
10832 if (allSticky != null) {
10833 ArrayList receivers = new ArrayList();
10834 receivers.add(bf);
10835
10836 int N = allSticky.size();
10837 for (int i=0; i<N; i++) {
10838 Intent intent = (Intent)allSticky.get(i);
10839 BroadcastRecord r = new BroadcastRecord(intent, null,
10840 null, -1, -1, null, receivers, null, 0, null, null,
10841 false);
10842 if (mParallelBroadcasts.size() == 0) {
10843 scheduleBroadcastsLocked();
10844 }
10845 mParallelBroadcasts.add(r);
10846 }
10847 }
10848
10849 return sticky;
10850 }
10851 }
10852
10853 public void unregisterReceiver(IIntentReceiver receiver) {
10854 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10855
10856 boolean doNext = false;
10857
10858 synchronized(this) {
10859 ReceiverList rl
10860 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10861 if (rl != null) {
10862 if (rl.curBroadcast != null) {
10863 BroadcastRecord r = rl.curBroadcast;
10864 doNext = finishReceiverLocked(
10865 receiver.asBinder(), r.resultCode, r.resultData,
10866 r.resultExtras, r.resultAbort, true);
10867 }
10868
10869 if (rl.app != null) {
10870 rl.app.receivers.remove(rl);
10871 }
10872 removeReceiverLocked(rl);
10873 if (rl.linkedToDeath) {
10874 rl.linkedToDeath = false;
10875 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10876 }
10877 }
10878 }
10879
10880 if (!doNext) {
10881 return;
10882 }
10883
10884 final long origId = Binder.clearCallingIdentity();
10885 processNextBroadcast(false);
10886 trimApplications();
10887 Binder.restoreCallingIdentity(origId);
10888 }
10889
10890 void removeReceiverLocked(ReceiverList rl) {
10891 mRegisteredReceivers.remove(rl.receiver.asBinder());
10892 int N = rl.size();
10893 for (int i=0; i<N; i++) {
10894 mReceiverResolver.removeFilter(rl.get(i));
10895 }
10896 }
10897
10898 private final int broadcastIntentLocked(ProcessRecord callerApp,
10899 String callerPackage, Intent intent, String resolvedType,
10900 IIntentReceiver resultTo, int resultCode, String resultData,
10901 Bundle map, String requiredPermission,
10902 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10903 intent = new Intent(intent);
10904
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010905 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010906 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10907 + " ordered=" + ordered);
10908 if ((resultTo != null) && !ordered) {
10909 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10910 }
10911
10912 // Handle special intents: if this broadcast is from the package
10913 // manager about a package being removed, we need to remove all of
10914 // its activities from the history stack.
10915 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10916 intent.getAction());
10917 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10918 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10919 || uidRemoved) {
10920 if (checkComponentPermission(
10921 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10922 callingPid, callingUid, -1)
10923 == PackageManager.PERMISSION_GRANTED) {
10924 if (uidRemoved) {
10925 final Bundle intentExtras = intent.getExtras();
10926 final int uid = intentExtras != null
10927 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10928 if (uid >= 0) {
10929 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10930 synchronized (bs) {
10931 bs.removeUidStatsLocked(uid);
10932 }
10933 }
10934 } else {
10935 Uri data = intent.getData();
10936 String ssp;
10937 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10938 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10939 uninstallPackageLocked(ssp,
10940 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010941 AttributeCache ac = AttributeCache.instance();
10942 if (ac != null) {
10943 ac.removePackage(ssp);
10944 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010945 }
10946 }
10947 }
10948 } else {
10949 String msg = "Permission Denial: " + intent.getAction()
10950 + " broadcast from " + callerPackage + " (pid=" + callingPid
10951 + ", uid=" + callingUid + ")"
10952 + " requires "
10953 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10954 Log.w(TAG, msg);
10955 throw new SecurityException(msg);
10956 }
10957 }
10958
10959 /*
10960 * If this is the time zone changed action, queue up a message that will reset the timezone
10961 * of all currently running processes. This message will get queued up before the broadcast
10962 * happens.
10963 */
10964 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10965 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10966 }
10967
Dianne Hackborn854060af2009-07-09 18:14:31 -070010968 /*
10969 * Prevent non-system code (defined here to be non-persistent
10970 * processes) from sending protected broadcasts.
10971 */
10972 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
10973 || callingUid == Process.SHELL_UID || callingUid == 0) {
10974 // Always okay.
10975 } else if (callerApp == null || !callerApp.persistent) {
10976 try {
10977 if (ActivityThread.getPackageManager().isProtectedBroadcast(
10978 intent.getAction())) {
10979 String msg = "Permission Denial: not allowed to send broadcast "
10980 + intent.getAction() + " from pid="
10981 + callingPid + ", uid=" + callingUid;
10982 Log.w(TAG, msg);
10983 throw new SecurityException(msg);
10984 }
10985 } catch (RemoteException e) {
10986 Log.w(TAG, "Remote exception", e);
10987 return BROADCAST_SUCCESS;
10988 }
10989 }
10990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010991 // Add to the sticky list if requested.
10992 if (sticky) {
10993 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10994 callingPid, callingUid)
10995 != PackageManager.PERMISSION_GRANTED) {
10996 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10997 + callingPid + ", uid=" + callingUid
10998 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10999 Log.w(TAG, msg);
11000 throw new SecurityException(msg);
11001 }
11002 if (requiredPermission != null) {
11003 Log.w(TAG, "Can't broadcast sticky intent " + intent
11004 + " and enforce permission " + requiredPermission);
11005 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11006 }
11007 if (intent.getComponent() != null) {
11008 throw new SecurityException(
11009 "Sticky broadcasts can't target a specific component");
11010 }
11011 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11012 if (list == null) {
11013 list = new ArrayList<Intent>();
11014 mStickyBroadcasts.put(intent.getAction(), list);
11015 }
11016 int N = list.size();
11017 int i;
11018 for (i=0; i<N; i++) {
11019 if (intent.filterEquals(list.get(i))) {
11020 // This sticky already exists, replace it.
11021 list.set(i, new Intent(intent));
11022 break;
11023 }
11024 }
11025 if (i >= N) {
11026 list.add(new Intent(intent));
11027 }
11028 }
11029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011030 // Figure out who all will receive this broadcast.
11031 List receivers = null;
11032 List<BroadcastFilter> registeredReceivers = null;
11033 try {
11034 if (intent.getComponent() != null) {
11035 // Broadcast is going to one specific receiver class...
11036 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011037 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011038 if (ai != null) {
11039 receivers = new ArrayList();
11040 ResolveInfo ri = new ResolveInfo();
11041 ri.activityInfo = ai;
11042 receivers.add(ri);
11043 }
11044 } else {
11045 // Need to resolve the intent to interested receivers...
11046 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11047 == 0) {
11048 receivers =
11049 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011050 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011051 }
Mihai Preda074edef2009-05-18 17:13:31 +020011052 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011053 }
11054 } catch (RemoteException ex) {
11055 // pm is in same process, this will never happen.
11056 }
11057
11058 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11059 if (!ordered && NR > 0) {
11060 // If we are not serializing this broadcast, then send the
11061 // registered receivers separately so they don't wait for the
11062 // components to be launched.
11063 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11064 callerPackage, callingPid, callingUid, requiredPermission,
11065 registeredReceivers, resultTo, resultCode, resultData, map,
11066 ordered);
11067 if (DEBUG_BROADCAST) Log.v(
11068 TAG, "Enqueueing parallel broadcast " + r
11069 + ": prev had " + mParallelBroadcasts.size());
11070 mParallelBroadcasts.add(r);
11071 scheduleBroadcastsLocked();
11072 registeredReceivers = null;
11073 NR = 0;
11074 }
11075
11076 // Merge into one list.
11077 int ir = 0;
11078 if (receivers != null) {
11079 // A special case for PACKAGE_ADDED: do not allow the package
11080 // being added to see this broadcast. This prevents them from
11081 // using this as a back door to get run as soon as they are
11082 // installed. Maybe in the future we want to have a special install
11083 // broadcast or such for apps, but we'd like to deliberately make
11084 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011085 boolean skip = false;
11086 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011087 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011088 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11089 skip = true;
11090 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11091 skip = true;
11092 }
11093 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011094 ? intent.getData().getSchemeSpecificPart()
11095 : null;
11096 if (skipPackage != null && receivers != null) {
11097 int NT = receivers.size();
11098 for (int it=0; it<NT; it++) {
11099 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11100 if (curt.activityInfo.packageName.equals(skipPackage)) {
11101 receivers.remove(it);
11102 it--;
11103 NT--;
11104 }
11105 }
11106 }
11107
11108 int NT = receivers != null ? receivers.size() : 0;
11109 int it = 0;
11110 ResolveInfo curt = null;
11111 BroadcastFilter curr = null;
11112 while (it < NT && ir < NR) {
11113 if (curt == null) {
11114 curt = (ResolveInfo)receivers.get(it);
11115 }
11116 if (curr == null) {
11117 curr = registeredReceivers.get(ir);
11118 }
11119 if (curr.getPriority() >= curt.priority) {
11120 // Insert this broadcast record into the final list.
11121 receivers.add(it, curr);
11122 ir++;
11123 curr = null;
11124 it++;
11125 NT++;
11126 } else {
11127 // Skip to the next ResolveInfo in the final list.
11128 it++;
11129 curt = null;
11130 }
11131 }
11132 }
11133 while (ir < NR) {
11134 if (receivers == null) {
11135 receivers = new ArrayList();
11136 }
11137 receivers.add(registeredReceivers.get(ir));
11138 ir++;
11139 }
11140
11141 if ((receivers != null && receivers.size() > 0)
11142 || resultTo != null) {
11143 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11144 callerPackage, callingPid, callingUid, requiredPermission,
11145 receivers, resultTo, resultCode, resultData, map, ordered);
11146 if (DEBUG_BROADCAST) Log.v(
11147 TAG, "Enqueueing ordered broadcast " + r
11148 + ": prev had " + mOrderedBroadcasts.size());
11149 if (DEBUG_BROADCAST) {
11150 int seq = r.intent.getIntExtra("seq", -1);
11151 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11152 }
11153 mOrderedBroadcasts.add(r);
11154 scheduleBroadcastsLocked();
11155 }
11156
11157 return BROADCAST_SUCCESS;
11158 }
11159
11160 public final int broadcastIntent(IApplicationThread caller,
11161 Intent intent, String resolvedType, IIntentReceiver resultTo,
11162 int resultCode, String resultData, Bundle map,
11163 String requiredPermission, boolean serialized, boolean sticky) {
11164 // Refuse possible leaked file descriptors
11165 if (intent != null && intent.hasFileDescriptors() == true) {
11166 throw new IllegalArgumentException("File descriptors passed in Intent");
11167 }
11168
11169 synchronized(this) {
11170 if (!mSystemReady) {
11171 // if the caller really truly claims to know what they're doing, go
11172 // ahead and allow the broadcast without launching any receivers
11173 int flags = intent.getFlags();
11174 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11175 intent = new Intent(intent);
11176 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11177 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11178 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11179 + " before boot completion");
11180 throw new IllegalStateException("Cannot broadcast before boot completed");
11181 }
11182 }
11183
11184 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11185 final int callingPid = Binder.getCallingPid();
11186 final int callingUid = Binder.getCallingUid();
11187 final long origId = Binder.clearCallingIdentity();
11188 int res = broadcastIntentLocked(callerApp,
11189 callerApp != null ? callerApp.info.packageName : null,
11190 intent, resolvedType, resultTo,
11191 resultCode, resultData, map, requiredPermission, serialized,
11192 sticky, callingPid, callingUid);
11193 Binder.restoreCallingIdentity(origId);
11194 return res;
11195 }
11196 }
11197
11198 int broadcastIntentInPackage(String packageName, int uid,
11199 Intent intent, String resolvedType, IIntentReceiver resultTo,
11200 int resultCode, String resultData, Bundle map,
11201 String requiredPermission, boolean serialized, boolean sticky) {
11202 synchronized(this) {
11203 final long origId = Binder.clearCallingIdentity();
11204 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11205 resultTo, resultCode, resultData, map, requiredPermission,
11206 serialized, sticky, -1, uid);
11207 Binder.restoreCallingIdentity(origId);
11208 return res;
11209 }
11210 }
11211
11212 public final void unbroadcastIntent(IApplicationThread caller,
11213 Intent intent) {
11214 // Refuse possible leaked file descriptors
11215 if (intent != null && intent.hasFileDescriptors() == true) {
11216 throw new IllegalArgumentException("File descriptors passed in Intent");
11217 }
11218
11219 synchronized(this) {
11220 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11221 != PackageManager.PERMISSION_GRANTED) {
11222 String msg = "Permission Denial: unbroadcastIntent() from pid="
11223 + Binder.getCallingPid()
11224 + ", uid=" + Binder.getCallingUid()
11225 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11226 Log.w(TAG, msg);
11227 throw new SecurityException(msg);
11228 }
11229 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11230 if (list != null) {
11231 int N = list.size();
11232 int i;
11233 for (i=0; i<N; i++) {
11234 if (intent.filterEquals(list.get(i))) {
11235 list.remove(i);
11236 break;
11237 }
11238 }
11239 }
11240 }
11241 }
11242
11243 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11244 String resultData, Bundle resultExtras, boolean resultAbort,
11245 boolean explicit) {
11246 if (mOrderedBroadcasts.size() == 0) {
11247 if (explicit) {
11248 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11249 }
11250 return false;
11251 }
11252 BroadcastRecord r = mOrderedBroadcasts.get(0);
11253 if (r.receiver == null) {
11254 if (explicit) {
11255 Log.w(TAG, "finishReceiver called but none active");
11256 }
11257 return false;
11258 }
11259 if (r.receiver != receiver) {
11260 Log.w(TAG, "finishReceiver called but active receiver is different");
11261 return false;
11262 }
11263 int state = r.state;
11264 r.state = r.IDLE;
11265 if (state == r.IDLE) {
11266 if (explicit) {
11267 Log.w(TAG, "finishReceiver called but state is IDLE");
11268 }
11269 }
11270 r.receiver = null;
11271 r.intent.setComponent(null);
11272 if (r.curApp != null) {
11273 r.curApp.curReceiver = null;
11274 }
11275 if (r.curFilter != null) {
11276 r.curFilter.receiverList.curBroadcast = null;
11277 }
11278 r.curFilter = null;
11279 r.curApp = null;
11280 r.curComponent = null;
11281 r.curReceiver = null;
11282 mPendingBroadcast = null;
11283
11284 r.resultCode = resultCode;
11285 r.resultData = resultData;
11286 r.resultExtras = resultExtras;
11287 r.resultAbort = resultAbort;
11288
11289 // We will process the next receiver right now if this is finishing
11290 // an app receiver (which is always asynchronous) or after we have
11291 // come back from calling a receiver.
11292 return state == BroadcastRecord.APP_RECEIVE
11293 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11294 }
11295
11296 public void finishReceiver(IBinder who, int resultCode, String resultData,
11297 Bundle resultExtras, boolean resultAbort) {
11298 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11299
11300 // Refuse possible leaked file descriptors
11301 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11302 throw new IllegalArgumentException("File descriptors passed in Bundle");
11303 }
11304
11305 boolean doNext;
11306
11307 final long origId = Binder.clearCallingIdentity();
11308
11309 synchronized(this) {
11310 doNext = finishReceiverLocked(
11311 who, resultCode, resultData, resultExtras, resultAbort, true);
11312 }
11313
11314 if (doNext) {
11315 processNextBroadcast(false);
11316 }
11317 trimApplications();
11318
11319 Binder.restoreCallingIdentity(origId);
11320 }
11321
11322 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11323 if (r.nextReceiver > 0) {
11324 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11325 if (curReceiver instanceof BroadcastFilter) {
11326 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11327 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11328 System.identityHashCode(r),
11329 r.intent.getAction(),
11330 r.nextReceiver - 1,
11331 System.identityHashCode(bf));
11332 } else {
11333 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11334 System.identityHashCode(r),
11335 r.intent.getAction(),
11336 r.nextReceiver - 1,
11337 ((ResolveInfo)curReceiver).toString());
11338 }
11339 } else {
11340 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11341 + r);
11342 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11343 System.identityHashCode(r),
11344 r.intent.getAction(),
11345 r.nextReceiver,
11346 "NONE");
11347 }
11348 }
11349
11350 private final void broadcastTimeout() {
11351 synchronized (this) {
11352 if (mOrderedBroadcasts.size() == 0) {
11353 return;
11354 }
11355 long now = SystemClock.uptimeMillis();
11356 BroadcastRecord r = mOrderedBroadcasts.get(0);
11357 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11358 if (DEBUG_BROADCAST) Log.v(TAG,
11359 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11360 + (r.startTime + BROADCAST_TIMEOUT));
11361 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11362 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11363 return;
11364 }
11365
11366 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11367 r.startTime = now;
11368 r.anrCount++;
11369
11370 // Current receiver has passed its expiration date.
11371 if (r.nextReceiver <= 0) {
11372 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11373 return;
11374 }
11375
11376 ProcessRecord app = null;
11377
11378 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11379 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11380 logBroadcastReceiverDiscard(r);
11381 if (curReceiver instanceof BroadcastFilter) {
11382 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11383 if (bf.receiverList.pid != 0
11384 && bf.receiverList.pid != MY_PID) {
11385 synchronized (this.mPidsSelfLocked) {
11386 app = this.mPidsSelfLocked.get(
11387 bf.receiverList.pid);
11388 }
11389 }
11390 } else {
11391 app = r.curApp;
11392 }
11393
11394 if (app != null) {
11395 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11396 }
11397
11398 if (mPendingBroadcast == r) {
11399 mPendingBroadcast = null;
11400 }
11401
11402 // Move on to the next receiver.
11403 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11404 r.resultExtras, r.resultAbort, true);
11405 scheduleBroadcastsLocked();
11406 }
11407 }
11408
11409 private final void processCurBroadcastLocked(BroadcastRecord r,
11410 ProcessRecord app) throws RemoteException {
11411 if (app.thread == null) {
11412 throw new RemoteException();
11413 }
11414 r.receiver = app.thread.asBinder();
11415 r.curApp = app;
11416 app.curReceiver = r;
11417 updateLRUListLocked(app, true);
11418
11419 // Tell the application to launch this receiver.
11420 r.intent.setComponent(r.curComponent);
11421
11422 boolean started = false;
11423 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011424 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011425 "Delivering to component " + r.curComponent
11426 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011427 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011428 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11429 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11430 started = true;
11431 } finally {
11432 if (!started) {
11433 r.receiver = null;
11434 r.curApp = null;
11435 app.curReceiver = null;
11436 }
11437 }
11438
11439 }
11440
11441 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11442 Intent intent, int resultCode, String data,
11443 Bundle extras, boolean ordered) throws RemoteException {
11444 if (app != null && app.thread != null) {
11445 // If we have an app thread, do the call through that so it is
11446 // correctly ordered with other one-way calls.
11447 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11448 data, extras, ordered);
11449 } else {
11450 receiver.performReceive(intent, resultCode, data, extras, ordered);
11451 }
11452 }
11453
11454 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11455 BroadcastFilter filter, boolean ordered) {
11456 boolean skip = false;
11457 if (filter.requiredPermission != null) {
11458 int perm = checkComponentPermission(filter.requiredPermission,
11459 r.callingPid, r.callingUid, -1);
11460 if (perm != PackageManager.PERMISSION_GRANTED) {
11461 Log.w(TAG, "Permission Denial: broadcasting "
11462 + r.intent.toString()
11463 + " from " + r.callerPackage + " (pid="
11464 + r.callingPid + ", uid=" + r.callingUid + ")"
11465 + " requires " + filter.requiredPermission
11466 + " due to registered receiver " + filter);
11467 skip = true;
11468 }
11469 }
11470 if (r.requiredPermission != null) {
11471 int perm = checkComponentPermission(r.requiredPermission,
11472 filter.receiverList.pid, filter.receiverList.uid, -1);
11473 if (perm != PackageManager.PERMISSION_GRANTED) {
11474 Log.w(TAG, "Permission Denial: receiving "
11475 + r.intent.toString()
11476 + " to " + filter.receiverList.app
11477 + " (pid=" + filter.receiverList.pid
11478 + ", uid=" + filter.receiverList.uid + ")"
11479 + " requires " + r.requiredPermission
11480 + " due to sender " + r.callerPackage
11481 + " (uid " + r.callingUid + ")");
11482 skip = true;
11483 }
11484 }
11485
11486 if (!skip) {
11487 // If this is not being sent as an ordered broadcast, then we
11488 // don't want to touch the fields that keep track of the current
11489 // state of ordered broadcasts.
11490 if (ordered) {
11491 r.receiver = filter.receiverList.receiver.asBinder();
11492 r.curFilter = filter;
11493 filter.receiverList.curBroadcast = r;
11494 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011495 if (filter.receiverList.app != null) {
11496 // Bump hosting application to no longer be in background
11497 // scheduling class. Note that we can't do that if there
11498 // isn't an app... but we can only be in that case for
11499 // things that directly call the IActivityManager API, which
11500 // are already core system stuff so don't matter for this.
11501 r.curApp = filter.receiverList.app;
11502 filter.receiverList.app.curReceiver = r;
11503 updateOomAdjLocked();
11504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011505 }
11506 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011507 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011508 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011509 Log.i(TAG, "Delivering to " + filter.receiverList.app
11510 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011511 }
11512 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11513 new Intent(r.intent), r.resultCode,
11514 r.resultData, r.resultExtras, r.ordered);
11515 if (ordered) {
11516 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11517 }
11518 } catch (RemoteException e) {
11519 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11520 if (ordered) {
11521 r.receiver = null;
11522 r.curFilter = null;
11523 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011524 if (filter.receiverList.app != null) {
11525 filter.receiverList.app.curReceiver = null;
11526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011527 }
11528 }
11529 }
11530 }
11531
11532 private final void processNextBroadcast(boolean fromMsg) {
11533 synchronized(this) {
11534 BroadcastRecord r;
11535
11536 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11537 + mParallelBroadcasts.size() + " broadcasts, "
11538 + mOrderedBroadcasts.size() + " serialized broadcasts");
11539
11540 updateCpuStats();
11541
11542 if (fromMsg) {
11543 mBroadcastsScheduled = false;
11544 }
11545
11546 // First, deliver any non-serialized broadcasts right away.
11547 while (mParallelBroadcasts.size() > 0) {
11548 r = mParallelBroadcasts.remove(0);
11549 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011550 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11551 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011552 for (int i=0; i<N; i++) {
11553 Object target = r.receivers.get(i);
11554 if (DEBUG_BROADCAST) Log.v(TAG,
11555 "Delivering non-serialized to registered "
11556 + target + ": " + r);
11557 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11558 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011559 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11560 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011561 }
11562
11563 // Now take care of the next serialized one...
11564
11565 // If we are waiting for a process to come up to handle the next
11566 // broadcast, then do nothing at this point. Just in case, we
11567 // check that the process we're waiting for still exists.
11568 if (mPendingBroadcast != null) {
11569 Log.i(TAG, "processNextBroadcast: waiting for "
11570 + mPendingBroadcast.curApp);
11571
11572 boolean isDead;
11573 synchronized (mPidsSelfLocked) {
11574 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11575 }
11576 if (!isDead) {
11577 // It's still alive, so keep waiting
11578 return;
11579 } else {
11580 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11581 + " died before responding to broadcast");
11582 mPendingBroadcast = null;
11583 }
11584 }
11585
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011586 boolean looped = false;
11587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011588 do {
11589 if (mOrderedBroadcasts.size() == 0) {
11590 // No more broadcasts pending, so all done!
11591 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011592 if (looped) {
11593 // If we had finished the last ordered broadcast, then
11594 // make sure all processes have correct oom and sched
11595 // adjustments.
11596 updateOomAdjLocked();
11597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011598 return;
11599 }
11600 r = mOrderedBroadcasts.get(0);
11601 boolean forceReceive = false;
11602
11603 // Ensure that even if something goes awry with the timeout
11604 // detection, we catch "hung" broadcasts here, discard them,
11605 // and continue to make progress.
11606 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11607 long now = SystemClock.uptimeMillis();
11608 if (r.dispatchTime > 0) {
11609 if ((numReceivers > 0) &&
11610 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11611 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11612 + " now=" + now
11613 + " dispatchTime=" + r.dispatchTime
11614 + " startTime=" + r.startTime
11615 + " intent=" + r.intent
11616 + " numReceivers=" + numReceivers
11617 + " nextReceiver=" + r.nextReceiver
11618 + " state=" + r.state);
11619 broadcastTimeout(); // forcibly finish this broadcast
11620 forceReceive = true;
11621 r.state = BroadcastRecord.IDLE;
11622 }
11623 }
11624
11625 if (r.state != BroadcastRecord.IDLE) {
11626 if (DEBUG_BROADCAST) Log.d(TAG,
11627 "processNextBroadcast() called when not idle (state="
11628 + r.state + ")");
11629 return;
11630 }
11631
11632 if (r.receivers == null || r.nextReceiver >= numReceivers
11633 || r.resultAbort || forceReceive) {
11634 // No more receivers for this broadcast! Send the final
11635 // result if requested...
11636 if (r.resultTo != null) {
11637 try {
11638 if (DEBUG_BROADCAST) {
11639 int seq = r.intent.getIntExtra("seq", -1);
11640 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11641 + " seq=" + seq + " app=" + r.callerApp);
11642 }
11643 performReceive(r.callerApp, r.resultTo,
11644 new Intent(r.intent), r.resultCode,
11645 r.resultData, r.resultExtras, false);
11646 } catch (RemoteException e) {
11647 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11648 }
11649 }
11650
11651 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11652 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11653
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011654 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11655 + r);
11656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011657 // ... and on to the next...
11658 mOrderedBroadcasts.remove(0);
11659 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011660 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011661 continue;
11662 }
11663 } while (r == null);
11664
11665 // Get the next receiver...
11666 int recIdx = r.nextReceiver++;
11667
11668 // Keep track of when this receiver started, and make sure there
11669 // is a timeout message pending to kill it if need be.
11670 r.startTime = SystemClock.uptimeMillis();
11671 if (recIdx == 0) {
11672 r.dispatchTime = r.startTime;
11673
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011674 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11675 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011676 if (DEBUG_BROADCAST) Log.v(TAG,
11677 "Submitting BROADCAST_TIMEOUT_MSG for "
11678 + (r.startTime + BROADCAST_TIMEOUT));
11679 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11680 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11681 }
11682
11683 Object nextReceiver = r.receivers.get(recIdx);
11684 if (nextReceiver instanceof BroadcastFilter) {
11685 // Simple case: this is a registered receiver who gets
11686 // a direct call.
11687 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11688 if (DEBUG_BROADCAST) Log.v(TAG,
11689 "Delivering serialized to registered "
11690 + filter + ": " + r);
11691 deliverToRegisteredReceiver(r, filter, r.ordered);
11692 if (r.receiver == null || !r.ordered) {
11693 // The receiver has already finished, so schedule to
11694 // process the next one.
11695 r.state = BroadcastRecord.IDLE;
11696 scheduleBroadcastsLocked();
11697 }
11698 return;
11699 }
11700
11701 // Hard case: need to instantiate the receiver, possibly
11702 // starting its application process to host it.
11703
11704 ResolveInfo info =
11705 (ResolveInfo)nextReceiver;
11706
11707 boolean skip = false;
11708 int perm = checkComponentPermission(info.activityInfo.permission,
11709 r.callingPid, r.callingUid,
11710 info.activityInfo.exported
11711 ? -1 : info.activityInfo.applicationInfo.uid);
11712 if (perm != PackageManager.PERMISSION_GRANTED) {
11713 Log.w(TAG, "Permission Denial: broadcasting "
11714 + r.intent.toString()
11715 + " from " + r.callerPackage + " (pid=" + r.callingPid
11716 + ", uid=" + r.callingUid + ")"
11717 + " requires " + info.activityInfo.permission
11718 + " due to receiver " + info.activityInfo.packageName
11719 + "/" + info.activityInfo.name);
11720 skip = true;
11721 }
11722 if (r.callingUid != Process.SYSTEM_UID &&
11723 r.requiredPermission != null) {
11724 try {
11725 perm = ActivityThread.getPackageManager().
11726 checkPermission(r.requiredPermission,
11727 info.activityInfo.applicationInfo.packageName);
11728 } catch (RemoteException e) {
11729 perm = PackageManager.PERMISSION_DENIED;
11730 }
11731 if (perm != PackageManager.PERMISSION_GRANTED) {
11732 Log.w(TAG, "Permission Denial: receiving "
11733 + r.intent + " to "
11734 + info.activityInfo.applicationInfo.packageName
11735 + " requires " + r.requiredPermission
11736 + " due to sender " + r.callerPackage
11737 + " (uid " + r.callingUid + ")");
11738 skip = true;
11739 }
11740 }
11741 if (r.curApp != null && r.curApp.crashing) {
11742 // If the target process is crashing, just skip it.
11743 skip = true;
11744 }
11745
11746 if (skip) {
11747 r.receiver = null;
11748 r.curFilter = null;
11749 r.state = BroadcastRecord.IDLE;
11750 scheduleBroadcastsLocked();
11751 return;
11752 }
11753
11754 r.state = BroadcastRecord.APP_RECEIVE;
11755 String targetProcess = info.activityInfo.processName;
11756 r.curComponent = new ComponentName(
11757 info.activityInfo.applicationInfo.packageName,
11758 info.activityInfo.name);
11759 r.curReceiver = info.activityInfo;
11760
11761 // Is this receiver's application already running?
11762 ProcessRecord app = getProcessRecordLocked(targetProcess,
11763 info.activityInfo.applicationInfo.uid);
11764 if (app != null && app.thread != null) {
11765 try {
11766 processCurBroadcastLocked(r, app);
11767 return;
11768 } catch (RemoteException e) {
11769 Log.w(TAG, "Exception when sending broadcast to "
11770 + r.curComponent, e);
11771 }
11772
11773 // If a dead object exception was thrown -- fall through to
11774 // restart the application.
11775 }
11776
11777 // Not running -- get it started, and enqueue this history record
11778 // to be executed when the app comes up.
11779 if ((r.curApp=startProcessLocked(targetProcess,
11780 info.activityInfo.applicationInfo, true,
11781 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11782 "broadcast", r.curComponent)) == null) {
11783 // Ah, this recipient is unavailable. Finish it if necessary,
11784 // and mark the broadcast record as ready for the next.
11785 Log.w(TAG, "Unable to launch app "
11786 + info.activityInfo.applicationInfo.packageName + "/"
11787 + info.activityInfo.applicationInfo.uid + " for broadcast "
11788 + r.intent + ": process is bad");
11789 logBroadcastReceiverDiscard(r);
11790 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11791 r.resultExtras, r.resultAbort, true);
11792 scheduleBroadcastsLocked();
11793 r.state = BroadcastRecord.IDLE;
11794 return;
11795 }
11796
11797 mPendingBroadcast = r;
11798 }
11799 }
11800
11801 // =========================================================
11802 // INSTRUMENTATION
11803 // =========================================================
11804
11805 public boolean startInstrumentation(ComponentName className,
11806 String profileFile, int flags, Bundle arguments,
11807 IInstrumentationWatcher watcher) {
11808 // Refuse possible leaked file descriptors
11809 if (arguments != null && arguments.hasFileDescriptors()) {
11810 throw new IllegalArgumentException("File descriptors passed in Bundle");
11811 }
11812
11813 synchronized(this) {
11814 InstrumentationInfo ii = null;
11815 ApplicationInfo ai = null;
11816 try {
11817 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011818 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011819 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011820 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011821 } catch (PackageManager.NameNotFoundException e) {
11822 }
11823 if (ii == null) {
11824 reportStartInstrumentationFailure(watcher, className,
11825 "Unable to find instrumentation info for: " + className);
11826 return false;
11827 }
11828 if (ai == null) {
11829 reportStartInstrumentationFailure(watcher, className,
11830 "Unable to find instrumentation target package: " + ii.targetPackage);
11831 return false;
11832 }
11833
11834 int match = mContext.getPackageManager().checkSignatures(
11835 ii.targetPackage, ii.packageName);
11836 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11837 String msg = "Permission Denial: starting instrumentation "
11838 + className + " from pid="
11839 + Binder.getCallingPid()
11840 + ", uid=" + Binder.getCallingPid()
11841 + " not allowed because package " + ii.packageName
11842 + " does not have a signature matching the target "
11843 + ii.targetPackage;
11844 reportStartInstrumentationFailure(watcher, className, msg);
11845 throw new SecurityException(msg);
11846 }
11847
11848 final long origId = Binder.clearCallingIdentity();
11849 uninstallPackageLocked(ii.targetPackage, -1, true);
11850 ProcessRecord app = addAppLocked(ai);
11851 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011852 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011853 app.instrumentationProfileFile = profileFile;
11854 app.instrumentationArguments = arguments;
11855 app.instrumentationWatcher = watcher;
11856 app.instrumentationResultClass = className;
11857 Binder.restoreCallingIdentity(origId);
11858 }
11859
11860 return true;
11861 }
11862
11863 /**
11864 * Report errors that occur while attempting to start Instrumentation. Always writes the
11865 * error to the logs, but if somebody is watching, send the report there too. This enables
11866 * the "am" command to report errors with more information.
11867 *
11868 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11869 * @param cn The component name of the instrumentation.
11870 * @param report The error report.
11871 */
11872 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11873 ComponentName cn, String report) {
11874 Log.w(TAG, report);
11875 try {
11876 if (watcher != null) {
11877 Bundle results = new Bundle();
11878 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11879 results.putString("Error", report);
11880 watcher.instrumentationStatus(cn, -1, results);
11881 }
11882 } catch (RemoteException e) {
11883 Log.w(TAG, e);
11884 }
11885 }
11886
11887 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11888 if (app.instrumentationWatcher != null) {
11889 try {
11890 // NOTE: IInstrumentationWatcher *must* be oneway here
11891 app.instrumentationWatcher.instrumentationFinished(
11892 app.instrumentationClass,
11893 resultCode,
11894 results);
11895 } catch (RemoteException e) {
11896 }
11897 }
11898 app.instrumentationWatcher = null;
11899 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011900 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011901 app.instrumentationProfileFile = null;
11902 app.instrumentationArguments = null;
11903
11904 uninstallPackageLocked(app.processName, -1, false);
11905 }
11906
11907 public void finishInstrumentation(IApplicationThread target,
11908 int resultCode, Bundle results) {
11909 // Refuse possible leaked file descriptors
11910 if (results != null && results.hasFileDescriptors()) {
11911 throw new IllegalArgumentException("File descriptors passed in Intent");
11912 }
11913
11914 synchronized(this) {
11915 ProcessRecord app = getRecordForAppLocked(target);
11916 if (app == null) {
11917 Log.w(TAG, "finishInstrumentation: no app for " + target);
11918 return;
11919 }
11920 final long origId = Binder.clearCallingIdentity();
11921 finishInstrumentationLocked(app, resultCode, results);
11922 Binder.restoreCallingIdentity(origId);
11923 }
11924 }
11925
11926 // =========================================================
11927 // CONFIGURATION
11928 // =========================================================
11929
11930 public ConfigurationInfo getDeviceConfigurationInfo() {
11931 ConfigurationInfo config = new ConfigurationInfo();
11932 synchronized (this) {
11933 config.reqTouchScreen = mConfiguration.touchscreen;
11934 config.reqKeyboardType = mConfiguration.keyboard;
11935 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011936 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
11937 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011938 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11939 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011940 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
11941 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011942 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11943 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070011944 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011945 }
11946 return config;
11947 }
11948
11949 public Configuration getConfiguration() {
11950 Configuration ci;
11951 synchronized(this) {
11952 ci = new Configuration(mConfiguration);
11953 }
11954 return ci;
11955 }
11956
11957 public void updateConfiguration(Configuration values) {
11958 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11959 "updateConfiguration()");
11960
11961 synchronized(this) {
11962 if (values == null && mWindowManager != null) {
11963 // sentinel: fetch the current configuration from the window manager
11964 values = mWindowManager.computeNewConfiguration();
11965 }
11966
11967 final long origId = Binder.clearCallingIdentity();
11968 updateConfigurationLocked(values, null);
11969 Binder.restoreCallingIdentity(origId);
11970 }
11971 }
11972
11973 /**
11974 * Do either or both things: (1) change the current configuration, and (2)
11975 * make sure the given activity is running with the (now) current
11976 * configuration. Returns true if the activity has been left running, or
11977 * false if <var>starting</var> is being destroyed to match the new
11978 * configuration.
11979 */
11980 public boolean updateConfigurationLocked(Configuration values,
11981 HistoryRecord starting) {
11982 int changes = 0;
11983
11984 boolean kept = true;
11985
11986 if (values != null) {
11987 Configuration newConfig = new Configuration(mConfiguration);
11988 changes = newConfig.updateFrom(values);
11989 if (changes != 0) {
11990 if (DEBUG_SWITCH) {
11991 Log.i(TAG, "Updating configuration to: " + values);
11992 }
11993
11994 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11995
11996 if (values.locale != null) {
11997 saveLocaleLocked(values.locale,
11998 !values.locale.equals(mConfiguration.locale),
11999 values.userSetLocale);
12000 }
12001
12002 mConfiguration = newConfig;
12003
12004 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12005 msg.obj = new Configuration(mConfiguration);
12006 mHandler.sendMessage(msg);
12007
12008 final int N = mLRUProcesses.size();
12009 for (int i=0; i<N; i++) {
12010 ProcessRecord app = mLRUProcesses.get(i);
12011 try {
12012 if (app.thread != null) {
12013 app.thread.scheduleConfigurationChanged(mConfiguration);
12014 }
12015 } catch (Exception e) {
12016 }
12017 }
12018 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12019 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12020 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012021
12022 AttributeCache ac = AttributeCache.instance();
12023 if (ac != null) {
12024 ac.updateConfiguration(mConfiguration);
12025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012026 }
12027 }
12028
12029 if (changes != 0 && starting == null) {
12030 // If the configuration changed, and the caller is not already
12031 // in the process of starting an activity, then find the top
12032 // activity to check if its configuration needs to change.
12033 starting = topRunningActivityLocked(null);
12034 }
12035
12036 if (starting != null) {
12037 kept = ensureActivityConfigurationLocked(starting, changes);
12038 if (kept) {
12039 // If this didn't result in the starting activity being
12040 // destroyed, then we need to make sure at this point that all
12041 // other activities are made visible.
12042 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12043 + ", ensuring others are correct.");
12044 ensureActivitiesVisibleLocked(starting, changes);
12045 }
12046 }
12047
12048 return kept;
12049 }
12050
12051 private final boolean relaunchActivityLocked(HistoryRecord r,
12052 int changes, boolean andResume) {
12053 List<ResultInfo> results = null;
12054 List<Intent> newIntents = null;
12055 if (andResume) {
12056 results = r.results;
12057 newIntents = r.newIntents;
12058 }
12059 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12060 + " with results=" + results + " newIntents=" + newIntents
12061 + " andResume=" + andResume);
12062 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12063 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12064 r.task.taskId, r.shortComponentName);
12065
12066 r.startFreezingScreenLocked(r.app, 0);
12067
12068 try {
12069 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12070 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12071 changes, !andResume);
12072 // Note: don't need to call pauseIfSleepingLocked() here, because
12073 // the caller will only pass in 'andResume' if this activity is
12074 // currently resumed, which implies we aren't sleeping.
12075 } catch (RemoteException e) {
12076 return false;
12077 }
12078
12079 if (andResume) {
12080 r.results = null;
12081 r.newIntents = null;
12082 }
12083
12084 return true;
12085 }
12086
12087 /**
12088 * Make sure the given activity matches the current configuration. Returns
12089 * false if the activity had to be destroyed. Returns true if the
12090 * configuration is the same, or the activity will remain running as-is
12091 * for whatever reason. Ensures the HistoryRecord is updated with the
12092 * correct configuration and all other bookkeeping is handled.
12093 */
12094 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12095 int globalChanges) {
12096 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12097
12098 // Short circuit: if the two configurations are the exact same
12099 // object (the common case), then there is nothing to do.
12100 Configuration newConfig = mConfiguration;
12101 if (r.configuration == newConfig) {
12102 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12103 return true;
12104 }
12105
12106 // We don't worry about activities that are finishing.
12107 if (r.finishing) {
12108 if (DEBUG_SWITCH) Log.i(TAG,
12109 "Configuration doesn't matter in finishing " + r);
12110 r.stopFreezingScreenLocked(false);
12111 return true;
12112 }
12113
12114 // Okay we now are going to make this activity have the new config.
12115 // But then we need to figure out how it needs to deal with that.
12116 Configuration oldConfig = r.configuration;
12117 r.configuration = newConfig;
12118
12119 // If the activity isn't currently running, just leave the new
12120 // configuration and it will pick that up next time it starts.
12121 if (r.app == null || r.app.thread == null) {
12122 if (DEBUG_SWITCH) Log.i(TAG,
12123 "Configuration doesn't matter not running " + r);
12124 r.stopFreezingScreenLocked(false);
12125 return true;
12126 }
12127
12128 // If the activity isn't persistent, there is a chance we will
12129 // need to restart it.
12130 if (!r.persistent) {
12131
12132 // Figure out what has changed between the two configurations.
12133 int changes = oldConfig.diff(newConfig);
12134 if (DEBUG_SWITCH) {
12135 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12136 + Integer.toHexString(changes) + ", handles=0x"
12137 + Integer.toHexString(r.info.configChanges));
12138 }
12139 if ((changes&(~r.info.configChanges)) != 0) {
12140 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12141 r.configChangeFlags |= changes;
12142 r.startFreezingScreenLocked(r.app, globalChanges);
12143 if (r.app == null || r.app.thread == null) {
12144 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12145 destroyActivityLocked(r, true);
12146 } else if (r.state == ActivityState.PAUSING) {
12147 // A little annoying: we are waiting for this activity to
12148 // finish pausing. Let's not do anything now, but just
12149 // flag that it needs to be restarted when done pausing.
12150 r.configDestroy = true;
12151 return true;
12152 } else if (r.state == ActivityState.RESUMED) {
12153 // Try to optimize this case: the configuration is changing
12154 // and we need to restart the top, resumed activity.
12155 // Instead of doing the normal handshaking, just say
12156 // "restart!".
12157 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12158 relaunchActivityLocked(r, r.configChangeFlags, true);
12159 r.configChangeFlags = 0;
12160 } else {
12161 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12162 relaunchActivityLocked(r, r.configChangeFlags, false);
12163 r.configChangeFlags = 0;
12164 }
12165
12166 // All done... tell the caller we weren't able to keep this
12167 // activity around.
12168 return false;
12169 }
12170 }
12171
12172 // Default case: the activity can handle this new configuration, so
12173 // hand it over. Note that we don't need to give it the new
12174 // configuration, since we always send configuration changes to all
12175 // process when they happen so it can just use whatever configuration
12176 // it last got.
12177 if (r.app != null && r.app.thread != null) {
12178 try {
12179 r.app.thread.scheduleActivityConfigurationChanged(r);
12180 } catch (RemoteException e) {
12181 // If process died, whatever.
12182 }
12183 }
12184 r.stopFreezingScreenLocked(false);
12185
12186 return true;
12187 }
12188
12189 /**
12190 * Save the locale. You must be inside a synchronized (this) block.
12191 */
12192 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12193 if(isDiff) {
12194 SystemProperties.set("user.language", l.getLanguage());
12195 SystemProperties.set("user.region", l.getCountry());
12196 }
12197
12198 if(isPersist) {
12199 SystemProperties.set("persist.sys.language", l.getLanguage());
12200 SystemProperties.set("persist.sys.country", l.getCountry());
12201 SystemProperties.set("persist.sys.localevar", l.getVariant());
12202 }
12203 }
12204
12205 // =========================================================
12206 // LIFETIME MANAGEMENT
12207 // =========================================================
12208
12209 private final int computeOomAdjLocked(
12210 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12211 if (mAdjSeq == app.adjSeq) {
12212 // This adjustment has already been computed.
12213 return app.curAdj;
12214 }
12215
12216 if (app.thread == null) {
12217 app.adjSeq = mAdjSeq;
12218 return (app.curAdj=EMPTY_APP_ADJ);
12219 }
12220
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012221 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12222 // The max adjustment doesn't allow this app to be anything
12223 // below foreground, so it is not worth doing work for it.
12224 app.adjType = "fixed";
12225 app.adjSeq = mAdjSeq;
12226 app.curRawAdj = app.maxAdj;
12227 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12228 return (app.curAdj=app.maxAdj);
12229 }
12230
12231 app.adjSource = null;
12232 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012233
The Android Open Source Project4df24232009-03-05 14:34:35 -080012234 // Determine the importance of the process, starting with most
12235 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012236 int adj;
12237 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012238 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012239 // The last app on the list is the foreground app.
12240 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012241 app.adjType = "top";
12242 } else if (app.instrumentationClass != null) {
12243 // Don't want to kill running instrumentation.
12244 adj = FOREGROUND_APP_ADJ;
12245 app.adjType = "instr";
12246 } else if (app.persistentActivities > 0) {
12247 // Special persistent activities... shouldn't be used these days.
12248 adj = FOREGROUND_APP_ADJ;
12249 app.adjType = "pers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012250 } else if (app.curReceiver != null ||
12251 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12252 // An app that is currently receiving a broadcast also
12253 // counts as being in the foreground.
12254 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012255 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012256 } else if (app.executingServices.size() > 0) {
12257 // An app that is currently executing a service callback also
12258 // counts as being in the foreground.
12259 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012260 app.adjType = "exec-service";
12261 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012262 // The user is aware of this app, so make it visible.
12263 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012264 app.adjType = "foreground-service";
12265 } else if (app.forcingToForeground != null) {
12266 // The user is aware of this app, so make it visible.
12267 adj = VISIBLE_APP_ADJ;
12268 app.adjType = "force-foreground";
12269 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012270 } else if (app == mHomeProcess) {
12271 // This process is hosting what we currently consider to be the
12272 // home app, so we don't want to let it go into the background.
12273 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012274 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012275 } else if ((N=app.activities.size()) != 0) {
12276 // This app is in the background with paused activities.
12277 adj = hiddenAdj;
12278 for (int j=0; j<N; j++) {
12279 if (((HistoryRecord)app.activities.get(j)).visible) {
12280 // This app has a visible activity!
12281 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012282 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012283 break;
12284 }
12285 }
12286 } else {
12287 // A very not-needed process.
12288 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012289 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012290 }
12291
The Android Open Source Project4df24232009-03-05 14:34:35 -080012292 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012293 // there are applications dependent on our services or providers, but
12294 // this gives us a baseline and makes sure we don't get into an
12295 // infinite recursion.
12296 app.adjSeq = mAdjSeq;
12297 app.curRawAdj = adj;
12298 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12299
Christopher Tate6fa95972009-06-05 18:43:55 -070012300 if (mBackupTarget != null && app == mBackupTarget.app) {
12301 // If possible we want to avoid killing apps while they're being backed up
12302 if (adj > BACKUP_APP_ADJ) {
12303 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12304 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012305 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012306 }
12307 }
12308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012309 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12310 // If this process has active services running in it, we would
12311 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012312 // application from running. By default we put the process in
12313 // with the rest of the background processes; as we scan through
12314 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012315 if (adj > hiddenAdj) {
12316 adj = hiddenAdj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012317 app.adjType = "services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012318 }
12319 final long now = SystemClock.uptimeMillis();
12320 // This process is more important if the top activity is
12321 // bound to the service.
12322 Iterator jt = app.services.iterator();
12323 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12324 ServiceRecord s = (ServiceRecord)jt.next();
12325 if (s.startRequested) {
12326 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12327 // This service has seen some activity within
12328 // recent memory, so we will keep its process ahead
12329 // of the background processes.
12330 if (adj > SECONDARY_SERVER_ADJ) {
12331 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012332 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012333 }
12334 }
12335 }
12336 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12337 Iterator<ConnectionRecord> kt
12338 = s.connections.values().iterator();
12339 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12340 // XXX should compute this based on the max of
12341 // all connected clients.
12342 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012343 if (cr.binding.client == app) {
12344 // Binding to ourself is not interesting.
12345 continue;
12346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012347 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12348 ProcessRecord client = cr.binding.client;
12349 int myHiddenAdj = hiddenAdj;
12350 if (myHiddenAdj > client.hiddenAdj) {
12351 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12352 myHiddenAdj = client.hiddenAdj;
12353 } else {
12354 myHiddenAdj = VISIBLE_APP_ADJ;
12355 }
12356 }
12357 int clientAdj = computeOomAdjLocked(
12358 client, myHiddenAdj, TOP_APP);
12359 if (adj > clientAdj) {
12360 adj = clientAdj > VISIBLE_APP_ADJ
12361 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012362 app.adjType = "service";
12363 app.adjSource = cr.binding.client;
12364 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012365 }
12366 }
12367 HistoryRecord a = cr.activity;
12368 //if (a != null) {
12369 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12370 //}
12371 if (a != null && adj > FOREGROUND_APP_ADJ &&
12372 (a.state == ActivityState.RESUMED
12373 || a.state == ActivityState.PAUSING)) {
12374 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012375 app.adjType = "service";
12376 app.adjSource = a;
12377 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012378 }
12379 }
12380 }
12381 }
12382 }
12383
12384 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12385 // If this process has published any content providers, then
12386 // its adjustment makes it at least as important as any of the
12387 // processes using those providers, and no less important than
12388 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12389 if (adj > CONTENT_PROVIDER_ADJ) {
12390 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012391 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012392 }
12393 Iterator jt = app.pubProviders.values().iterator();
12394 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12395 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12396 if (cpr.clients.size() != 0) {
12397 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12398 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12399 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012400 if (client == app) {
12401 // Being our own client is not interesting.
12402 continue;
12403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012404 int myHiddenAdj = hiddenAdj;
12405 if (myHiddenAdj > client.hiddenAdj) {
12406 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12407 myHiddenAdj = client.hiddenAdj;
12408 } else {
12409 myHiddenAdj = FOREGROUND_APP_ADJ;
12410 }
12411 }
12412 int clientAdj = computeOomAdjLocked(
12413 client, myHiddenAdj, TOP_APP);
12414 if (adj > clientAdj) {
12415 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012416 ? clientAdj : FOREGROUND_APP_ADJ;
12417 app.adjType = "provider";
12418 app.adjSource = client;
12419 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012420 }
12421 }
12422 }
12423 // If the provider has external (non-framework) process
12424 // dependencies, ensure that its adjustment is at least
12425 // FOREGROUND_APP_ADJ.
12426 if (cpr.externals != 0) {
12427 if (adj > FOREGROUND_APP_ADJ) {
12428 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012429 app.adjType = "provider";
12430 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012431 }
12432 }
12433 }
12434 }
12435
12436 app.curRawAdj = adj;
12437
12438 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12439 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12440 if (adj > app.maxAdj) {
12441 adj = app.maxAdj;
12442 }
12443
12444 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012445 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012446 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12447 : Process.THREAD_GROUP_DEFAULT;
12448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012449 return adj;
12450 }
12451
12452 /**
12453 * Ask a given process to GC right now.
12454 */
12455 final void performAppGcLocked(ProcessRecord app) {
12456 try {
12457 app.lastRequestedGc = SystemClock.uptimeMillis();
12458 if (app.thread != null) {
12459 app.thread.processInBackground();
12460 }
12461 } catch (Exception e) {
12462 // whatever.
12463 }
12464 }
12465
12466 /**
12467 * Returns true if things are idle enough to perform GCs.
12468 */
12469 private final boolean canGcNow() {
12470 return mParallelBroadcasts.size() == 0
12471 && mOrderedBroadcasts.size() == 0
12472 && (mSleeping || (mResumedActivity != null &&
12473 mResumedActivity.idle));
12474 }
12475
12476 /**
12477 * Perform GCs on all processes that are waiting for it, but only
12478 * if things are idle.
12479 */
12480 final void performAppGcsLocked() {
12481 final int N = mProcessesToGc.size();
12482 if (N <= 0) {
12483 return;
12484 }
12485 if (canGcNow()) {
12486 while (mProcessesToGc.size() > 0) {
12487 ProcessRecord proc = mProcessesToGc.remove(0);
12488 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12489 // To avoid spamming the system, we will GC processes one
12490 // at a time, waiting a few seconds between each.
12491 performAppGcLocked(proc);
12492 scheduleAppGcsLocked();
12493 return;
12494 }
12495 }
12496 }
12497 }
12498
12499 /**
12500 * If all looks good, perform GCs on all processes waiting for them.
12501 */
12502 final void performAppGcsIfAppropriateLocked() {
12503 if (canGcNow()) {
12504 performAppGcsLocked();
12505 return;
12506 }
12507 // Still not idle, wait some more.
12508 scheduleAppGcsLocked();
12509 }
12510
12511 /**
12512 * Schedule the execution of all pending app GCs.
12513 */
12514 final void scheduleAppGcsLocked() {
12515 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12516 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12517 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12518 }
12519
12520 /**
12521 * Set up to ask a process to GC itself. This will either do it
12522 * immediately, or put it on the list of processes to gc the next
12523 * time things are idle.
12524 */
12525 final void scheduleAppGcLocked(ProcessRecord app) {
12526 long now = SystemClock.uptimeMillis();
12527 if ((app.lastRequestedGc+5000) > now) {
12528 return;
12529 }
12530 if (!mProcessesToGc.contains(app)) {
12531 mProcessesToGc.add(app);
12532 scheduleAppGcsLocked();
12533 }
12534 }
12535
12536 private final boolean updateOomAdjLocked(
12537 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12538 app.hiddenAdj = hiddenAdj;
12539
12540 if (app.thread == null) {
12541 return true;
12542 }
12543
12544 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012546 if (app.pid != 0 && app.pid != MY_PID) {
12547 if (app.curRawAdj != app.setRawAdj) {
12548 if (app.curRawAdj > FOREGROUND_APP_ADJ
12549 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12550 // If this app is transitioning from foreground to
12551 // non-foreground, have it do a gc.
12552 scheduleAppGcLocked(app);
12553 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12554 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12555 // Likewise do a gc when an app is moving in to the
12556 // background (such as a service stopping).
12557 scheduleAppGcLocked(app);
12558 }
12559 app.setRawAdj = app.curRawAdj;
12560 }
12561 if (adj != app.setAdj) {
12562 if (Process.setOomAdj(app.pid, adj)) {
12563 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12564 TAG, "Set app " + app.processName +
12565 " oom adj to " + adj);
12566 app.setAdj = adj;
12567 } else {
12568 return false;
12569 }
12570 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012571 if (app.setSchedGroup != app.curSchedGroup) {
12572 app.setSchedGroup = app.curSchedGroup;
12573 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12574 "Setting process group of " + app.processName
12575 + " to " + app.curSchedGroup);
12576 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012577 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012578 try {
12579 Process.setProcessGroup(app.pid, app.curSchedGroup);
12580 } catch (Exception e) {
12581 Log.w(TAG, "Failed setting process group of " + app.pid
12582 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012583 e.printStackTrace();
12584 } finally {
12585 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012586 }
12587 }
12588 if (false) {
12589 if (app.thread != null) {
12590 try {
12591 app.thread.setSchedulingGroup(app.curSchedGroup);
12592 } catch (RemoteException e) {
12593 }
12594 }
12595 }
12596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012597 }
12598
12599 return true;
12600 }
12601
12602 private final HistoryRecord resumedAppLocked() {
12603 HistoryRecord resumedActivity = mResumedActivity;
12604 if (resumedActivity == null || resumedActivity.app == null) {
12605 resumedActivity = mPausingActivity;
12606 if (resumedActivity == null || resumedActivity.app == null) {
12607 resumedActivity = topRunningActivityLocked(null);
12608 }
12609 }
12610 return resumedActivity;
12611 }
12612
12613 private final boolean updateOomAdjLocked(ProcessRecord app) {
12614 final HistoryRecord TOP_ACT = resumedAppLocked();
12615 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12616 int curAdj = app.curAdj;
12617 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12618 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12619
12620 mAdjSeq++;
12621
12622 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12623 if (res) {
12624 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12625 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12626 if (nowHidden != wasHidden) {
12627 // Changed to/from hidden state, so apps after it in the LRU
12628 // list may also be changed.
12629 updateOomAdjLocked();
12630 }
12631 }
12632 return res;
12633 }
12634
12635 private final boolean updateOomAdjLocked() {
12636 boolean didOomAdj = true;
12637 final HistoryRecord TOP_ACT = resumedAppLocked();
12638 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12639
12640 if (false) {
12641 RuntimeException e = new RuntimeException();
12642 e.fillInStackTrace();
12643 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12644 }
12645
12646 mAdjSeq++;
12647
12648 // First try updating the OOM adjustment for each of the
12649 // application processes based on their current state.
12650 int i = mLRUProcesses.size();
12651 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12652 while (i > 0) {
12653 i--;
12654 ProcessRecord app = mLRUProcesses.get(i);
12655 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12656 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12657 && app.curAdj == curHiddenAdj) {
12658 curHiddenAdj++;
12659 }
12660 } else {
12661 didOomAdj = false;
12662 }
12663 }
12664
12665 // todo: for now pretend like OOM ADJ didn't work, because things
12666 // aren't behaving as expected on Linux -- it's not killing processes.
12667 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12668 }
12669
12670 private final void trimApplications() {
12671 synchronized (this) {
12672 int i;
12673
12674 // First remove any unused application processes whose package
12675 // has been removed.
12676 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12677 final ProcessRecord app = mRemovedProcesses.get(i);
12678 if (app.activities.size() == 0
12679 && app.curReceiver == null && app.services.size() == 0) {
12680 Log.i(
12681 TAG, "Exiting empty application process "
12682 + app.processName + " ("
12683 + (app.thread != null ? app.thread.asBinder() : null)
12684 + ")\n");
12685 if (app.pid > 0 && app.pid != MY_PID) {
12686 Process.killProcess(app.pid);
12687 } else {
12688 try {
12689 app.thread.scheduleExit();
12690 } catch (Exception e) {
12691 // Ignore exceptions.
12692 }
12693 }
12694 cleanUpApplicationRecordLocked(app, false, -1);
12695 mRemovedProcesses.remove(i);
12696
12697 if (app.persistent) {
12698 if (app.persistent) {
12699 addAppLocked(app.info);
12700 }
12701 }
12702 }
12703 }
12704
12705 // Now try updating the OOM adjustment for each of the
12706 // application processes based on their current state.
12707 // If the setOomAdj() API is not supported, then go with our
12708 // back-up plan...
12709 if (!updateOomAdjLocked()) {
12710
12711 // Count how many processes are running services.
12712 int numServiceProcs = 0;
12713 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12714 final ProcessRecord app = mLRUProcesses.get(i);
12715
12716 if (app.persistent || app.services.size() != 0
12717 || app.curReceiver != null
12718 || app.persistentActivities > 0) {
12719 // Don't count processes holding services against our
12720 // maximum process count.
12721 if (localLOGV) Log.v(
12722 TAG, "Not trimming app " + app + " with services: "
12723 + app.services);
12724 numServiceProcs++;
12725 }
12726 }
12727
12728 int curMaxProcs = mProcessLimit;
12729 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12730 if (mAlwaysFinishActivities) {
12731 curMaxProcs = 1;
12732 }
12733 curMaxProcs += numServiceProcs;
12734
12735 // Quit as many processes as we can to get down to the desired
12736 // process count. First remove any processes that no longer
12737 // have activites running in them.
12738 for ( i=0;
12739 i<mLRUProcesses.size()
12740 && mLRUProcesses.size() > curMaxProcs;
12741 i++) {
12742 final ProcessRecord app = mLRUProcesses.get(i);
12743 // Quit an application only if it is not currently
12744 // running any activities.
12745 if (!app.persistent && app.activities.size() == 0
12746 && app.curReceiver == null && app.services.size() == 0) {
12747 Log.i(
12748 TAG, "Exiting empty application process "
12749 + app.processName + " ("
12750 + (app.thread != null ? app.thread.asBinder() : null)
12751 + ")\n");
12752 if (app.pid > 0 && app.pid != MY_PID) {
12753 Process.killProcess(app.pid);
12754 } else {
12755 try {
12756 app.thread.scheduleExit();
12757 } catch (Exception e) {
12758 // Ignore exceptions.
12759 }
12760 }
12761 // todo: For now we assume the application is not buggy
12762 // or evil, and will quit as a result of our request.
12763 // Eventually we need to drive this off of the death
12764 // notification, and kill the process if it takes too long.
12765 cleanUpApplicationRecordLocked(app, false, i);
12766 i--;
12767 }
12768 }
12769
12770 // If we still have too many processes, now from the least
12771 // recently used process we start finishing activities.
12772 if (Config.LOGV) Log.v(
12773 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12774 " of " + curMaxProcs + " processes");
12775 for ( i=0;
12776 i<mLRUProcesses.size()
12777 && mLRUProcesses.size() > curMaxProcs;
12778 i++) {
12779 final ProcessRecord app = mLRUProcesses.get(i);
12780 // Quit the application only if we have a state saved for
12781 // all of its activities.
12782 boolean canQuit = !app.persistent && app.curReceiver == null
12783 && app.services.size() == 0
12784 && app.persistentActivities == 0;
12785 int NUMA = app.activities.size();
12786 int j;
12787 if (Config.LOGV) Log.v(
12788 TAG, "Looking to quit " + app.processName);
12789 for (j=0; j<NUMA && canQuit; j++) {
12790 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12791 if (Config.LOGV) Log.v(
12792 TAG, " " + r.intent.getComponent().flattenToShortString()
12793 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12794 canQuit = (r.haveState || !r.stateNotNeeded)
12795 && !r.visible && r.stopped;
12796 }
12797 if (canQuit) {
12798 // Finish all of the activities, and then the app itself.
12799 for (j=0; j<NUMA; j++) {
12800 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12801 if (!r.finishing) {
12802 destroyActivityLocked(r, false);
12803 }
12804 r.resultTo = null;
12805 }
12806 Log.i(TAG, "Exiting application process "
12807 + app.processName + " ("
12808 + (app.thread != null ? app.thread.asBinder() : null)
12809 + ")\n");
12810 if (app.pid > 0 && app.pid != MY_PID) {
12811 Process.killProcess(app.pid);
12812 } else {
12813 try {
12814 app.thread.scheduleExit();
12815 } catch (Exception e) {
12816 // Ignore exceptions.
12817 }
12818 }
12819 // todo: For now we assume the application is not buggy
12820 // or evil, and will quit as a result of our request.
12821 // Eventually we need to drive this off of the death
12822 // notification, and kill the process if it takes too long.
12823 cleanUpApplicationRecordLocked(app, false, i);
12824 i--;
12825 //dump();
12826 }
12827 }
12828
12829 }
12830
12831 int curMaxActivities = MAX_ACTIVITIES;
12832 if (mAlwaysFinishActivities) {
12833 curMaxActivities = 1;
12834 }
12835
12836 // Finally, if there are too many activities now running, try to
12837 // finish as many as we can to get back down to the limit.
12838 for ( i=0;
12839 i<mLRUActivities.size()
12840 && mLRUActivities.size() > curMaxActivities;
12841 i++) {
12842 final HistoryRecord r
12843 = (HistoryRecord)mLRUActivities.get(i);
12844
12845 // We can finish this one if we have its icicle saved and
12846 // it is not persistent.
12847 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12848 && r.stopped && !r.persistent && !r.finishing) {
12849 final int origSize = mLRUActivities.size();
12850 destroyActivityLocked(r, true);
12851
12852 // This will remove it from the LRU list, so keep
12853 // our index at the same value. Note that this check to
12854 // see if the size changes is just paranoia -- if
12855 // something unexpected happens, we don't want to end up
12856 // in an infinite loop.
12857 if (origSize > mLRUActivities.size()) {
12858 i--;
12859 }
12860 }
12861 }
12862 }
12863 }
12864
12865 /** This method sends the specified signal to each of the persistent apps */
12866 public void signalPersistentProcesses(int sig) throws RemoteException {
12867 if (sig != Process.SIGNAL_USR1) {
12868 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12869 }
12870
12871 synchronized (this) {
12872 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12873 != PackageManager.PERMISSION_GRANTED) {
12874 throw new SecurityException("Requires permission "
12875 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12876 }
12877
12878 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12879 ProcessRecord r = mLRUProcesses.get(i);
12880 if (r.thread != null && r.persistent) {
12881 Process.sendSignal(r.pid, sig);
12882 }
12883 }
12884 }
12885 }
12886
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012887 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012888 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012889
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012890 try {
12891 synchronized (this) {
12892 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12893 // its own permission.
12894 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12895 != PackageManager.PERMISSION_GRANTED) {
12896 throw new SecurityException("Requires permission "
12897 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012898 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012899
12900 if (start && fd == null) {
12901 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012902 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012903
12904 ProcessRecord proc = null;
12905 try {
12906 int pid = Integer.parseInt(process);
12907 synchronized (mPidsSelfLocked) {
12908 proc = mPidsSelfLocked.get(pid);
12909 }
12910 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012911 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012912
12913 if (proc == null) {
12914 HashMap<String, SparseArray<ProcessRecord>> all
12915 = mProcessNames.getMap();
12916 SparseArray<ProcessRecord> procs = all.get(process);
12917 if (procs != null && procs.size() > 0) {
12918 proc = procs.valueAt(0);
12919 }
12920 }
12921
12922 if (proc == null || proc.thread == null) {
12923 throw new IllegalArgumentException("Unknown process: " + process);
12924 }
12925
12926 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12927 if (isSecure) {
12928 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12929 throw new SecurityException("Process not debuggable: " + proc);
12930 }
12931 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012932
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012933 proc.thread.profilerControl(start, path, fd);
12934 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012935 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012936 }
12937 } catch (RemoteException e) {
12938 throw new IllegalStateException("Process disappeared");
12939 } finally {
12940 if (fd != null) {
12941 try {
12942 fd.close();
12943 } catch (IOException e) {
12944 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012945 }
12946 }
12947 }
12948
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012949 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12950 public void monitor() {
12951 synchronized (this) { }
12952 }
12953}