blob: 04bfae6152a817b888b1363d1997226e1557577a [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,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004452 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004453 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);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004480 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004481 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004482 if (reportedActivity != null && reportedActivity.app != null) {
4483 info.append(" (last in ");
4484 info.append(reportedActivity.app.processName);
4485 info.append(")");
4486 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004487 if (annotation != null) {
4488 info.append("\nAnnotation: ");
4489 info.append(annotation);
4490 }
4491 if (MONITOR_CPU_USAGE) {
4492 info.append("\nCPU usage:\n");
4493 info.append(processInfo);
4494 }
4495 Log.i(TAG, info.toString());
4496
4497 // The application is not responding. Dump as many thread traces as we can.
4498 boolean fileDump = prepareTraceFile(true);
4499 if (!fileDump) {
4500 // Dumping traces to the log, just dump the process that isn't responding so
4501 // we don't overflow the log
4502 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4503 } else {
4504 // Dumping traces to a file so dump all active processes we know about
4505 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004506 // First, these are the most important processes.
4507 final int[] imppids = new int[3];
4508 int i=0;
4509 imppids[0] = app.pid;
4510 i++;
4511 if (reportedActivity != null && reportedActivity.app != null
4512 && reportedActivity.app.thread != null
4513 && reportedActivity.app.pid != app.pid) {
4514 imppids[i] = reportedActivity.app.pid;
4515 i++;
4516 }
4517 imppids[i] = Process.myPid();
4518 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4519 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4520 synchronized (this) {
4521 try {
4522 wait(200);
4523 } catch (InterruptedException e) {
4524 }
4525 }
4526 }
4527 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004528 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004529 boolean done = false;
4530 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4531 if (imppids[j] == r.pid) {
4532 done = true;
4533 break;
4534 }
4535 }
4536 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004537 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004538 synchronized (this) {
4539 try {
4540 wait(200);
4541 } catch (InterruptedException e) {
4542 }
4543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004544 }
4545 }
4546 }
4547 }
4548
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004549 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004551 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004552 app.pid, info.toString());
4553 if (res != 0) {
4554 if (res < 0) {
4555 // wait until the SIGQUIT has had a chance to process before killing the
4556 // process.
4557 try {
4558 wait(2000);
4559 } catch (InterruptedException e) {
4560 }
4561
4562 Process.killProcess(app.pid);
4563 return;
4564 }
4565 }
4566 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004567 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 }
4569 }
4570
4571 makeAppNotRespondingLocked(app,
4572 activity != null ? activity.shortComponentName : null,
4573 annotation != null ? "ANR " + annotation : "ANR",
4574 info.toString(), null);
4575 Message msg = Message.obtain();
4576 HashMap map = new HashMap();
4577 msg.what = SHOW_NOT_RESPONDING_MSG;
4578 msg.obj = map;
4579 map.put("app", app);
4580 if (activity != null) {
4581 map.put("activity", activity);
4582 }
4583
4584 mHandler.sendMessage(msg);
4585 return;
4586 }
4587
4588 /**
4589 * If a stack trace file has been configured, prepare the filesystem
4590 * by creating the directory if it doesn't exist and optionally
4591 * removing the old trace file.
4592 *
4593 * @param removeExisting If set, the existing trace file will be removed.
4594 * @return Returns true if the trace file preparations succeeded
4595 */
4596 public static boolean prepareTraceFile(boolean removeExisting) {
4597 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4598 boolean fileReady = false;
4599 if (!TextUtils.isEmpty(tracesPath)) {
4600 File f = new File(tracesPath);
4601 if (!f.exists()) {
4602 // Ensure the enclosing directory exists
4603 File dir = f.getParentFile();
4604 if (!dir.exists()) {
4605 fileReady = dir.mkdirs();
4606 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004607 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 } else if (dir.isDirectory()) {
4609 fileReady = true;
4610 }
4611 } else if (removeExisting) {
4612 // Remove the previous traces file, so we don't fill the disk.
4613 // The VM will recreate it
4614 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4615 fileReady = f.delete();
4616 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004617
4618 if (removeExisting) {
4619 try {
4620 f.createNewFile();
4621 FileUtils.setPermissions(f.getAbsolutePath(),
4622 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4623 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4624 fileReady = true;
4625 } catch (IOException e) {
4626 Log.w(TAG, "Unable to make ANR traces file", e);
4627 }
4628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 }
4630
4631 return fileReady;
4632 }
4633
4634
4635 private final void decPersistentCountLocked(ProcessRecord app)
4636 {
4637 app.persistentActivities--;
4638 if (app.persistentActivities > 0) {
4639 // Still more of 'em...
4640 return;
4641 }
4642 if (app.persistent) {
4643 // Ah, but the application itself is persistent. Whatever!
4644 return;
4645 }
4646
4647 // App is no longer persistent... make sure it and the ones
4648 // following it in the LRU list have the correc oom_adj.
4649 updateOomAdjLocked();
4650 }
4651
4652 public void setPersistent(IBinder token, boolean isPersistent) {
4653 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4654 != PackageManager.PERMISSION_GRANTED) {
4655 String msg = "Permission Denial: setPersistent() from pid="
4656 + Binder.getCallingPid()
4657 + ", uid=" + Binder.getCallingUid()
4658 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4659 Log.w(TAG, msg);
4660 throw new SecurityException(msg);
4661 }
4662
4663 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004664 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004665 if (index < 0) {
4666 return;
4667 }
4668 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4669 ProcessRecord app = r.app;
4670
4671 if (localLOGV) Log.v(
4672 TAG, "Setting persistence " + isPersistent + ": " + r);
4673
4674 if (isPersistent) {
4675 if (r.persistent) {
4676 // Okay okay, I heard you already!
4677 if (localLOGV) Log.v(TAG, "Already persistent!");
4678 return;
4679 }
4680 r.persistent = true;
4681 app.persistentActivities++;
4682 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4683 if (app.persistentActivities > 1) {
4684 // We aren't the first...
4685 if (localLOGV) Log.v(TAG, "Not the first!");
4686 return;
4687 }
4688 if (app.persistent) {
4689 // This would be redundant.
4690 if (localLOGV) Log.v(TAG, "App is persistent!");
4691 return;
4692 }
4693
4694 // App is now persistent... make sure it and the ones
4695 // following it now have the correct oom_adj.
4696 final long origId = Binder.clearCallingIdentity();
4697 updateOomAdjLocked();
4698 Binder.restoreCallingIdentity(origId);
4699
4700 } else {
4701 if (!r.persistent) {
4702 // Okay okay, I heard you already!
4703 return;
4704 }
4705 r.persistent = false;
4706 final long origId = Binder.clearCallingIdentity();
4707 decPersistentCountLocked(app);
4708 Binder.restoreCallingIdentity(origId);
4709
4710 }
4711 }
4712 }
4713
4714 public boolean clearApplicationUserData(final String packageName,
4715 final IPackageDataObserver observer) {
4716 int uid = Binder.getCallingUid();
4717 int pid = Binder.getCallingPid();
4718 long callingId = Binder.clearCallingIdentity();
4719 try {
4720 IPackageManager pm = ActivityThread.getPackageManager();
4721 int pkgUid = -1;
4722 synchronized(this) {
4723 try {
4724 pkgUid = pm.getPackageUid(packageName);
4725 } catch (RemoteException e) {
4726 }
4727 if (pkgUid == -1) {
4728 Log.w(TAG, "Invalid packageName:" + packageName);
4729 return false;
4730 }
4731 if (uid == pkgUid || checkComponentPermission(
4732 android.Manifest.permission.CLEAR_APP_USER_DATA,
4733 pid, uid, -1)
4734 == PackageManager.PERMISSION_GRANTED) {
4735 restartPackageLocked(packageName, pkgUid);
4736 } else {
4737 throw new SecurityException(pid+" does not have permission:"+
4738 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4739 "for process:"+packageName);
4740 }
4741 }
4742
4743 try {
4744 //clear application user data
4745 pm.clearApplicationUserData(packageName, observer);
4746 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4747 Uri.fromParts("package", packageName, null));
4748 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4749 broadcastIntentLocked(null, null, intent,
4750 null, null, 0, null, null, null,
4751 false, false, MY_PID, Process.SYSTEM_UID);
4752 } catch (RemoteException e) {
4753 }
4754 } finally {
4755 Binder.restoreCallingIdentity(callingId);
4756 }
4757 return true;
4758 }
4759
4760 public void restartPackage(final String packageName) {
4761 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4762 != PackageManager.PERMISSION_GRANTED) {
4763 String msg = "Permission Denial: restartPackage() from pid="
4764 + Binder.getCallingPid()
4765 + ", uid=" + Binder.getCallingUid()
4766 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4767 Log.w(TAG, msg);
4768 throw new SecurityException(msg);
4769 }
4770
4771 long callingId = Binder.clearCallingIdentity();
4772 try {
4773 IPackageManager pm = ActivityThread.getPackageManager();
4774 int pkgUid = -1;
4775 synchronized(this) {
4776 try {
4777 pkgUid = pm.getPackageUid(packageName);
4778 } catch (RemoteException e) {
4779 }
4780 if (pkgUid == -1) {
4781 Log.w(TAG, "Invalid packageName: " + packageName);
4782 return;
4783 }
4784 restartPackageLocked(packageName, pkgUid);
4785 }
4786 } finally {
4787 Binder.restoreCallingIdentity(callingId);
4788 }
4789 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004790
4791 /*
4792 * The pkg name and uid have to be specified.
4793 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4794 */
4795 public void killApplicationWithUid(String pkg, int uid) {
4796 if (pkg == null) {
4797 return;
4798 }
4799 // Make sure the uid is valid.
4800 if (uid < 0) {
4801 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4802 return;
4803 }
4804 int callerUid = Binder.getCallingUid();
4805 // Only the system server can kill an application
4806 if (callerUid == Process.SYSTEM_UID) {
4807 uninstallPackageLocked(pkg, uid, false);
4808 } else {
4809 throw new SecurityException(callerUid + " cannot kill pkg: " +
4810 pkg);
4811 }
4812 }
4813
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004814 public void closeSystemDialogs(String reason) {
4815 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4816 if (reason != null) {
4817 intent.putExtra("reason", reason);
4818 }
4819
4820 final int uid = Binder.getCallingUid();
4821 final long origId = Binder.clearCallingIdentity();
4822 synchronized (this) {
4823 int i = mWatchers.beginBroadcast();
4824 while (i > 0) {
4825 i--;
4826 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4827 if (w != null) {
4828 try {
4829 w.closingSystemDialogs(reason);
4830 } catch (RemoteException e) {
4831 }
4832 }
4833 }
4834 mWatchers.finishBroadcast();
4835
4836 broadcastIntentLocked(null, null, intent, null,
4837 null, 0, null, null, null, false, false, -1, uid);
4838 }
4839 Binder.restoreCallingIdentity(origId);
4840 }
4841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004842 private void restartPackageLocked(final String packageName, int uid) {
4843 uninstallPackageLocked(packageName, uid, false);
4844 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4845 Uri.fromParts("package", packageName, null));
4846 intent.putExtra(Intent.EXTRA_UID, uid);
4847 broadcastIntentLocked(null, null, intent,
4848 null, null, 0, null, null, null,
4849 false, false, MY_PID, Process.SYSTEM_UID);
4850 }
4851
4852 private final void uninstallPackageLocked(String name, int uid,
4853 boolean callerWillRestart) {
4854 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4855
4856 int i, N;
4857
4858 final String procNamePrefix = name + ":";
4859 if (uid < 0) {
4860 try {
4861 uid = ActivityThread.getPackageManager().getPackageUid(name);
4862 } catch (RemoteException e) {
4863 }
4864 }
4865
4866 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4867 while (badApps.hasNext()) {
4868 SparseArray<Long> ba = badApps.next();
4869 if (ba.get(uid) != null) {
4870 badApps.remove();
4871 }
4872 }
4873
4874 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4875
4876 // Remove all processes this package may have touched: all with the
4877 // same UID (except for the system or root user), and all whose name
4878 // matches the package name.
4879 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4880 final int NA = apps.size();
4881 for (int ia=0; ia<NA; ia++) {
4882 ProcessRecord app = apps.valueAt(ia);
4883 if (app.removed) {
4884 procs.add(app);
4885 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4886 || app.processName.equals(name)
4887 || app.processName.startsWith(procNamePrefix)) {
4888 app.removed = true;
4889 procs.add(app);
4890 }
4891 }
4892 }
4893
4894 N = procs.size();
4895 for (i=0; i<N; i++) {
4896 removeProcessLocked(procs.get(i), callerWillRestart);
4897 }
4898
4899 for (i=mHistory.size()-1; i>=0; i--) {
4900 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4901 if (r.packageName.equals(name)) {
4902 if (Config.LOGD) Log.d(
4903 TAG, " Force finishing activity "
4904 + r.intent.getComponent().flattenToShortString());
4905 if (r.app != null) {
4906 r.app.removed = true;
4907 }
4908 r.app = null;
4909 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4910 }
4911 }
4912
4913 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4914 for (ServiceRecord service : mServices.values()) {
4915 if (service.packageName.equals(name)) {
4916 if (service.app != null) {
4917 service.app.removed = true;
4918 }
4919 service.app = null;
4920 services.add(service);
4921 }
4922 }
4923
4924 N = services.size();
4925 for (i=0; i<N; i++) {
4926 bringDownServiceLocked(services.get(i), true);
4927 }
4928
4929 resumeTopActivityLocked(null);
4930 }
4931
4932 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4933 final String name = app.processName;
4934 final int uid = app.info.uid;
4935 if (Config.LOGD) Log.d(
4936 TAG, "Force removing process " + app + " (" + name
4937 + "/" + uid + ")");
4938
4939 mProcessNames.remove(name, uid);
4940 boolean needRestart = false;
4941 if (app.pid > 0 && app.pid != MY_PID) {
4942 int pid = app.pid;
4943 synchronized (mPidsSelfLocked) {
4944 mPidsSelfLocked.remove(pid);
4945 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4946 }
4947 handleAppDiedLocked(app, true);
4948 mLRUProcesses.remove(app);
4949 Process.killProcess(pid);
4950
4951 if (app.persistent) {
4952 if (!callerWillRestart) {
4953 addAppLocked(app.info);
4954 } else {
4955 needRestart = true;
4956 }
4957 }
4958 } else {
4959 mRemovedProcesses.add(app);
4960 }
4961
4962 return needRestart;
4963 }
4964
4965 private final void processStartTimedOutLocked(ProcessRecord app) {
4966 final int pid = app.pid;
4967 boolean gone = false;
4968 synchronized (mPidsSelfLocked) {
4969 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4970 if (knownApp != null && knownApp.thread == null) {
4971 mPidsSelfLocked.remove(pid);
4972 gone = true;
4973 }
4974 }
4975
4976 if (gone) {
4977 Log.w(TAG, "Process " + app + " failed to attach");
4978 mProcessNames.remove(app.processName, app.info.uid);
4979 Process.killProcess(pid);
4980 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4981 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4982 mPendingBroadcast = null;
4983 scheduleBroadcastsLocked();
4984 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004985 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4986 Log.w(TAG, "Unattached app died before backup, skipping");
4987 try {
4988 IBackupManager bm = IBackupManager.Stub.asInterface(
4989 ServiceManager.getService(Context.BACKUP_SERVICE));
4990 bm.agentDisconnected(app.info.packageName);
4991 } catch (RemoteException e) {
4992 // Can't happen; the backup manager is local
4993 }
4994 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004995 } else {
4996 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4997 }
4998 }
4999
5000 private final boolean attachApplicationLocked(IApplicationThread thread,
5001 int pid) {
5002
5003 // Find the application record that is being attached... either via
5004 // the pid if we are running in multiple processes, or just pull the
5005 // next app record if we are emulating process with anonymous threads.
5006 ProcessRecord app;
5007 if (pid != MY_PID && pid >= 0) {
5008 synchronized (mPidsSelfLocked) {
5009 app = mPidsSelfLocked.get(pid);
5010 }
5011 } else if (mStartingProcesses.size() > 0) {
5012 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005013 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005014 } else {
5015 app = null;
5016 }
5017
5018 if (app == null) {
5019 Log.w(TAG, "No pending application record for pid " + pid
5020 + " (IApplicationThread " + thread + "); dropping process");
5021 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5022 if (pid > 0 && pid != MY_PID) {
5023 Process.killProcess(pid);
5024 } else {
5025 try {
5026 thread.scheduleExit();
5027 } catch (Exception e) {
5028 // Ignore exceptions.
5029 }
5030 }
5031 return false;
5032 }
5033
5034 // If this application record is still attached to a previous
5035 // process, clean it up now.
5036 if (app.thread != null) {
5037 handleAppDiedLocked(app, true);
5038 }
5039
5040 // Tell the process all about itself.
5041
5042 if (localLOGV) Log.v(
5043 TAG, "Binding process pid " + pid + " to record " + app);
5044
5045 String processName = app.processName;
5046 try {
5047 thread.asBinder().linkToDeath(new AppDeathRecipient(
5048 app, pid, thread), 0);
5049 } catch (RemoteException e) {
5050 app.resetPackageList();
5051 startProcessLocked(app, "link fail", processName);
5052 return false;
5053 }
5054
5055 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5056
5057 app.thread = thread;
5058 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005059 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005060 app.forcingToForeground = null;
5061 app.foregroundServices = false;
5062 app.debugging = false;
5063
5064 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5065
5066 List providers = generateApplicationProvidersLocked(app);
5067
5068 if (localLOGV) Log.v(
5069 TAG, "New app record " + app
5070 + " thread=" + thread.asBinder() + " pid=" + pid);
5071 try {
5072 int testMode = IApplicationThread.DEBUG_OFF;
5073 if (mDebugApp != null && mDebugApp.equals(processName)) {
5074 testMode = mWaitForDebugger
5075 ? IApplicationThread.DEBUG_WAIT
5076 : IApplicationThread.DEBUG_ON;
5077 app.debugging = true;
5078 if (mDebugTransient) {
5079 mDebugApp = mOrigDebugApp;
5080 mWaitForDebugger = mOrigWaitForDebugger;
5081 }
5082 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005083 // If the app is being launched for restore or full backup, set it up specially
5084 boolean isRestrictedBackupMode = false;
5085 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5086 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5087 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5088 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005089 ensurePackageDexOpt(app.instrumentationInfo != null
5090 ? app.instrumentationInfo.packageName
5091 : app.info.packageName);
5092 if (app.instrumentationClass != null) {
5093 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005094 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005095 thread.bindApplication(processName, app.instrumentationInfo != null
5096 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005097 app.instrumentationClass, app.instrumentationProfileFile,
5098 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07005099 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005100 updateLRUListLocked(app, false);
5101 app.lastRequestedGc = SystemClock.uptimeMillis();
5102 } catch (Exception e) {
5103 // todo: Yikes! What should we do? For now we will try to
5104 // start another process, but that could easily get us in
5105 // an infinite loop of restarting processes...
5106 Log.w(TAG, "Exception thrown during bind!", e);
5107
5108 app.resetPackageList();
5109 startProcessLocked(app, "bind fail", processName);
5110 return false;
5111 }
5112
5113 // Remove this record from the list of starting applications.
5114 mPersistentStartingProcesses.remove(app);
5115 mProcessesOnHold.remove(app);
5116
5117 boolean badApp = false;
5118 boolean didSomething = false;
5119
5120 // See if the top visible activity is waiting to run in this process...
5121 HistoryRecord hr = topRunningActivityLocked(null);
5122 if (hr != null) {
5123 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5124 && processName.equals(hr.processName)) {
5125 try {
5126 if (realStartActivityLocked(hr, app, true, true)) {
5127 didSomething = true;
5128 }
5129 } catch (Exception e) {
5130 Log.w(TAG, "Exception in new application when starting activity "
5131 + hr.intent.getComponent().flattenToShortString(), e);
5132 badApp = true;
5133 }
5134 } else {
5135 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5136 }
5137 }
5138
5139 // Find any services that should be running in this process...
5140 if (!badApp && mPendingServices.size() > 0) {
5141 ServiceRecord sr = null;
5142 try {
5143 for (int i=0; i<mPendingServices.size(); i++) {
5144 sr = mPendingServices.get(i);
5145 if (app.info.uid != sr.appInfo.uid
5146 || !processName.equals(sr.processName)) {
5147 continue;
5148 }
5149
5150 mPendingServices.remove(i);
5151 i--;
5152 realStartServiceLocked(sr, app);
5153 didSomething = true;
5154 }
5155 } catch (Exception e) {
5156 Log.w(TAG, "Exception in new application when starting service "
5157 + sr.shortName, e);
5158 badApp = true;
5159 }
5160 }
5161
5162 // Check if the next broadcast receiver is in this process...
5163 BroadcastRecord br = mPendingBroadcast;
5164 if (!badApp && br != null && br.curApp == app) {
5165 try {
5166 mPendingBroadcast = null;
5167 processCurBroadcastLocked(br, app);
5168 didSomething = true;
5169 } catch (Exception e) {
5170 Log.w(TAG, "Exception in new application when starting receiver "
5171 + br.curComponent.flattenToShortString(), e);
5172 badApp = true;
5173 logBroadcastReceiverDiscard(br);
5174 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5175 br.resultExtras, br.resultAbort, true);
5176 scheduleBroadcastsLocked();
5177 }
5178 }
5179
Christopher Tate181fafa2009-05-14 11:12:14 -07005180 // Check whether the next backup agent is in this process...
5181 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5182 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005183 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005184 try {
5185 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5186 } catch (Exception e) {
5187 Log.w(TAG, "Exception scheduling backup agent creation: ");
5188 e.printStackTrace();
5189 }
5190 }
5191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 if (badApp) {
5193 // todo: Also need to kill application to deal with all
5194 // kinds of exceptions.
5195 handleAppDiedLocked(app, false);
5196 return false;
5197 }
5198
5199 if (!didSomething) {
5200 updateOomAdjLocked();
5201 }
5202
5203 return true;
5204 }
5205
5206 public final void attachApplication(IApplicationThread thread) {
5207 synchronized (this) {
5208 int callingPid = Binder.getCallingPid();
5209 final long origId = Binder.clearCallingIdentity();
5210 attachApplicationLocked(thread, callingPid);
5211 Binder.restoreCallingIdentity(origId);
5212 }
5213 }
5214
5215 public final void activityIdle(IBinder token) {
5216 final long origId = Binder.clearCallingIdentity();
5217 activityIdleInternal(token, false);
5218 Binder.restoreCallingIdentity(origId);
5219 }
5220
5221 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5222 boolean remove) {
5223 int N = mStoppingActivities.size();
5224 if (N <= 0) return null;
5225
5226 ArrayList<HistoryRecord> stops = null;
5227
5228 final boolean nowVisible = mResumedActivity != null
5229 && mResumedActivity.nowVisible
5230 && !mResumedActivity.waitingVisible;
5231 for (int i=0; i<N; i++) {
5232 HistoryRecord s = mStoppingActivities.get(i);
5233 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5234 + nowVisible + " waitingVisible=" + s.waitingVisible
5235 + " finishing=" + s.finishing);
5236 if (s.waitingVisible && nowVisible) {
5237 mWaitingVisibleActivities.remove(s);
5238 s.waitingVisible = false;
5239 if (s.finishing) {
5240 // If this activity is finishing, it is sitting on top of
5241 // everyone else but we now know it is no longer needed...
5242 // so get rid of it. Otherwise, we need to go through the
5243 // normal flow and hide it once we determine that it is
5244 // hidden by the activities in front of it.
5245 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5246 mWindowManager.setAppVisibility(s, false);
5247 }
5248 }
5249 if (!s.waitingVisible && remove) {
5250 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5251 if (stops == null) {
5252 stops = new ArrayList<HistoryRecord>();
5253 }
5254 stops.add(s);
5255 mStoppingActivities.remove(i);
5256 N--;
5257 i--;
5258 }
5259 }
5260
5261 return stops;
5262 }
5263
5264 void enableScreenAfterBoot() {
5265 mWindowManager.enableScreenAfterBoot();
5266 }
5267
5268 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5269 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5270
5271 ArrayList<HistoryRecord> stops = null;
5272 ArrayList<HistoryRecord> finishes = null;
5273 ArrayList<HistoryRecord> thumbnails = null;
5274 int NS = 0;
5275 int NF = 0;
5276 int NT = 0;
5277 IApplicationThread sendThumbnail = null;
5278 boolean booting = false;
5279 boolean enableScreen = false;
5280
5281 synchronized (this) {
5282 if (token != null) {
5283 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5284 }
5285
5286 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005287 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005288 if (index >= 0) {
5289 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5290
5291 // No longer need to keep the device awake.
5292 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5293 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5294 mLaunchingActivity.release();
5295 }
5296
5297 // We are now idle. If someone is waiting for a thumbnail from
5298 // us, we can now deliver.
5299 r.idle = true;
5300 scheduleAppGcsLocked();
5301 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5302 sendThumbnail = r.app.thread;
5303 r.thumbnailNeeded = false;
5304 }
5305
5306 // If this activity is fullscreen, set up to hide those under it.
5307
5308 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5309 ensureActivitiesVisibleLocked(null, 0);
5310
5311 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5312 if (!mBooted && !fromTimeout) {
5313 mBooted = true;
5314 enableScreen = true;
5315 }
5316 }
5317
5318 // Atomically retrieve all of the other things to do.
5319 stops = processStoppingActivitiesLocked(true);
5320 NS = stops != null ? stops.size() : 0;
5321 if ((NF=mFinishingActivities.size()) > 0) {
5322 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5323 mFinishingActivities.clear();
5324 }
5325 if ((NT=mCancelledThumbnails.size()) > 0) {
5326 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5327 mCancelledThumbnails.clear();
5328 }
5329
5330 booting = mBooting;
5331 mBooting = false;
5332 }
5333
5334 int i;
5335
5336 // Send thumbnail if requested.
5337 if (sendThumbnail != null) {
5338 try {
5339 sendThumbnail.requestThumbnail(token);
5340 } catch (Exception e) {
5341 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5342 sendPendingThumbnail(null, token, null, null, true);
5343 }
5344 }
5345
5346 // Stop any activities that are scheduled to do so but have been
5347 // waiting for the next one to start.
5348 for (i=0; i<NS; i++) {
5349 HistoryRecord r = (HistoryRecord)stops.get(i);
5350 synchronized (this) {
5351 if (r.finishing) {
5352 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5353 } else {
5354 stopActivityLocked(r);
5355 }
5356 }
5357 }
5358
5359 // Finish any activities that are scheduled to do so but have been
5360 // waiting for the next one to start.
5361 for (i=0; i<NF; i++) {
5362 HistoryRecord r = (HistoryRecord)finishes.get(i);
5363 synchronized (this) {
5364 destroyActivityLocked(r, true);
5365 }
5366 }
5367
5368 // Report back to any thumbnail receivers.
5369 for (i=0; i<NT; i++) {
5370 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5371 sendPendingThumbnail(r, null, null, null, true);
5372 }
5373
5374 if (booting) {
5375 // Ensure that any processes we had put on hold are now started
5376 // up.
5377 final int NP = mProcessesOnHold.size();
5378 if (NP > 0) {
5379 ArrayList<ProcessRecord> procs =
5380 new ArrayList<ProcessRecord>(mProcessesOnHold);
5381 for (int ip=0; ip<NP; ip++) {
5382 this.startProcessLocked(procs.get(ip), "on-hold", null);
5383 }
5384 }
5385 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5386 // Tell anyone interested that we are done booting!
5387 synchronized (this) {
5388 broadcastIntentLocked(null, null,
5389 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5390 null, null, 0, null, null,
5391 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5392 false, false, MY_PID, Process.SYSTEM_UID);
5393 }
5394 }
5395 }
5396
5397 trimApplications();
5398 //dump();
5399 //mWindowManager.dump();
5400
5401 if (enableScreen) {
5402 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5403 SystemClock.uptimeMillis());
5404 enableScreenAfterBoot();
5405 }
5406 }
5407
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005408 final void ensureScreenEnabled() {
5409 boolean enableScreen;
5410 synchronized (this) {
5411 enableScreen = !mBooted;
5412 mBooted = true;
5413 }
5414
5415 if (enableScreen) {
5416 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5417 SystemClock.uptimeMillis());
5418 enableScreenAfterBoot();
5419 }
5420 }
5421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005422 public final void activityPaused(IBinder token, Bundle icicle) {
5423 // Refuse possible leaked file descriptors
5424 if (icicle != null && icicle.hasFileDescriptors()) {
5425 throw new IllegalArgumentException("File descriptors passed in Bundle");
5426 }
5427
5428 final long origId = Binder.clearCallingIdentity();
5429 activityPaused(token, icicle, false);
5430 Binder.restoreCallingIdentity(origId);
5431 }
5432
5433 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5434 if (DEBUG_PAUSE) Log.v(
5435 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5436 + ", timeout=" + timeout);
5437
5438 HistoryRecord r = null;
5439
5440 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005441 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005442 if (index >= 0) {
5443 r = (HistoryRecord)mHistory.get(index);
5444 if (!timeout) {
5445 r.icicle = icicle;
5446 r.haveState = true;
5447 }
5448 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5449 if (mPausingActivity == r) {
5450 r.state = ActivityState.PAUSED;
5451 completePauseLocked();
5452 } else {
5453 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5454 System.identityHashCode(r), r.shortComponentName,
5455 mPausingActivity != null
5456 ? mPausingActivity.shortComponentName : "(none)");
5457 }
5458 }
5459 }
5460 }
5461
5462 public final void activityStopped(IBinder token, Bitmap thumbnail,
5463 CharSequence description) {
5464 if (localLOGV) Log.v(
5465 TAG, "Activity stopped: token=" + token);
5466
5467 HistoryRecord r = null;
5468
5469 final long origId = Binder.clearCallingIdentity();
5470
5471 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005472 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005473 if (index >= 0) {
5474 r = (HistoryRecord)mHistory.get(index);
5475 r.thumbnail = thumbnail;
5476 r.description = description;
5477 r.stopped = true;
5478 r.state = ActivityState.STOPPED;
5479 if (!r.finishing) {
5480 if (r.configDestroy) {
5481 destroyActivityLocked(r, true);
5482 resumeTopActivityLocked(null);
5483 }
5484 }
5485 }
5486 }
5487
5488 if (r != null) {
5489 sendPendingThumbnail(r, null, null, null, false);
5490 }
5491
5492 trimApplications();
5493
5494 Binder.restoreCallingIdentity(origId);
5495 }
5496
5497 public final void activityDestroyed(IBinder token) {
5498 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5499 synchronized (this) {
5500 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5501
Dianne Hackborn75b03852009-06-12 15:43:26 -07005502 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005503 if (index >= 0) {
5504 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5505 if (r.state == ActivityState.DESTROYING) {
5506 final long origId = Binder.clearCallingIdentity();
5507 removeActivityFromHistoryLocked(r);
5508 Binder.restoreCallingIdentity(origId);
5509 }
5510 }
5511 }
5512 }
5513
5514 public String getCallingPackage(IBinder token) {
5515 synchronized (this) {
5516 HistoryRecord r = getCallingRecordLocked(token);
5517 return r != null && r.app != null ? r.app.processName : null;
5518 }
5519 }
5520
5521 public ComponentName getCallingActivity(IBinder token) {
5522 synchronized (this) {
5523 HistoryRecord r = getCallingRecordLocked(token);
5524 return r != null ? r.intent.getComponent() : null;
5525 }
5526 }
5527
5528 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005529 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005530 if (index >= 0) {
5531 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5532 if (r != null) {
5533 return r.resultTo;
5534 }
5535 }
5536 return null;
5537 }
5538
5539 public ComponentName getActivityClassForToken(IBinder token) {
5540 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005541 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005542 if (index >= 0) {
5543 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5544 return r.intent.getComponent();
5545 }
5546 return null;
5547 }
5548 }
5549
5550 public String getPackageForToken(IBinder token) {
5551 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005552 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005553 if (index >= 0) {
5554 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5555 return r.packageName;
5556 }
5557 return null;
5558 }
5559 }
5560
5561 public IIntentSender getIntentSender(int type,
5562 String packageName, IBinder token, String resultWho,
5563 int requestCode, Intent intent, String resolvedType, int flags) {
5564 // Refuse possible leaked file descriptors
5565 if (intent != null && intent.hasFileDescriptors() == true) {
5566 throw new IllegalArgumentException("File descriptors passed in Intent");
5567 }
5568
5569 synchronized(this) {
5570 int callingUid = Binder.getCallingUid();
5571 try {
5572 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5573 Process.supportsProcesses()) {
5574 int uid = ActivityThread.getPackageManager()
5575 .getPackageUid(packageName);
5576 if (uid != Binder.getCallingUid()) {
5577 String msg = "Permission Denial: getIntentSender() from pid="
5578 + Binder.getCallingPid()
5579 + ", uid=" + Binder.getCallingUid()
5580 + ", (need uid=" + uid + ")"
5581 + " is not allowed to send as package " + packageName;
5582 Log.w(TAG, msg);
5583 throw new SecurityException(msg);
5584 }
5585 }
5586 } catch (RemoteException e) {
5587 throw new SecurityException(e);
5588 }
5589 HistoryRecord activity = null;
5590 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005591 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005592 if (index < 0) {
5593 return null;
5594 }
5595 activity = (HistoryRecord)mHistory.get(index);
5596 if (activity.finishing) {
5597 return null;
5598 }
5599 }
5600
5601 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5602 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5603 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5604 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5605 |PendingIntent.FLAG_UPDATE_CURRENT);
5606
5607 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5608 type, packageName, activity, resultWho,
5609 requestCode, intent, resolvedType, flags);
5610 WeakReference<PendingIntentRecord> ref;
5611 ref = mIntentSenderRecords.get(key);
5612 PendingIntentRecord rec = ref != null ? ref.get() : null;
5613 if (rec != null) {
5614 if (!cancelCurrent) {
5615 if (updateCurrent) {
5616 rec.key.requestIntent.replaceExtras(intent);
5617 }
5618 return rec;
5619 }
5620 rec.canceled = true;
5621 mIntentSenderRecords.remove(key);
5622 }
5623 if (noCreate) {
5624 return rec;
5625 }
5626 rec = new PendingIntentRecord(this, key, callingUid);
5627 mIntentSenderRecords.put(key, rec.ref);
5628 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5629 if (activity.pendingResults == null) {
5630 activity.pendingResults
5631 = new HashSet<WeakReference<PendingIntentRecord>>();
5632 }
5633 activity.pendingResults.add(rec.ref);
5634 }
5635 return rec;
5636 }
5637 }
5638
5639 public void cancelIntentSender(IIntentSender sender) {
5640 if (!(sender instanceof PendingIntentRecord)) {
5641 return;
5642 }
5643 synchronized(this) {
5644 PendingIntentRecord rec = (PendingIntentRecord)sender;
5645 try {
5646 int uid = ActivityThread.getPackageManager()
5647 .getPackageUid(rec.key.packageName);
5648 if (uid != Binder.getCallingUid()) {
5649 String msg = "Permission Denial: cancelIntentSender() from pid="
5650 + Binder.getCallingPid()
5651 + ", uid=" + Binder.getCallingUid()
5652 + " is not allowed to cancel packges "
5653 + rec.key.packageName;
5654 Log.w(TAG, msg);
5655 throw new SecurityException(msg);
5656 }
5657 } catch (RemoteException e) {
5658 throw new SecurityException(e);
5659 }
5660 cancelIntentSenderLocked(rec, true);
5661 }
5662 }
5663
5664 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5665 rec.canceled = true;
5666 mIntentSenderRecords.remove(rec.key);
5667 if (cleanActivity && rec.key.activity != null) {
5668 rec.key.activity.pendingResults.remove(rec.ref);
5669 }
5670 }
5671
5672 public String getPackageForIntentSender(IIntentSender pendingResult) {
5673 if (!(pendingResult instanceof PendingIntentRecord)) {
5674 return null;
5675 }
5676 synchronized(this) {
5677 try {
5678 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5679 return res.key.packageName;
5680 } catch (ClassCastException e) {
5681 }
5682 }
5683 return null;
5684 }
5685
5686 public void setProcessLimit(int max) {
5687 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5688 "setProcessLimit()");
5689 mProcessLimit = max;
5690 }
5691
5692 public int getProcessLimit() {
5693 return mProcessLimit;
5694 }
5695
5696 void foregroundTokenDied(ForegroundToken token) {
5697 synchronized (ActivityManagerService.this) {
5698 synchronized (mPidsSelfLocked) {
5699 ForegroundToken cur
5700 = mForegroundProcesses.get(token.pid);
5701 if (cur != token) {
5702 return;
5703 }
5704 mForegroundProcesses.remove(token.pid);
5705 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5706 if (pr == null) {
5707 return;
5708 }
5709 pr.forcingToForeground = null;
5710 pr.foregroundServices = false;
5711 }
5712 updateOomAdjLocked();
5713 }
5714 }
5715
5716 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5717 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5718 "setProcessForeground()");
5719 synchronized(this) {
5720 boolean changed = false;
5721
5722 synchronized (mPidsSelfLocked) {
5723 ProcessRecord pr = mPidsSelfLocked.get(pid);
5724 if (pr == null) {
5725 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5726 return;
5727 }
5728 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5729 if (oldToken != null) {
5730 oldToken.token.unlinkToDeath(oldToken, 0);
5731 mForegroundProcesses.remove(pid);
5732 pr.forcingToForeground = null;
5733 changed = true;
5734 }
5735 if (isForeground && token != null) {
5736 ForegroundToken newToken = new ForegroundToken() {
5737 public void binderDied() {
5738 foregroundTokenDied(this);
5739 }
5740 };
5741 newToken.pid = pid;
5742 newToken.token = token;
5743 try {
5744 token.linkToDeath(newToken, 0);
5745 mForegroundProcesses.put(pid, newToken);
5746 pr.forcingToForeground = token;
5747 changed = true;
5748 } catch (RemoteException e) {
5749 // If the process died while doing this, we will later
5750 // do the cleanup with the process death link.
5751 }
5752 }
5753 }
5754
5755 if (changed) {
5756 updateOomAdjLocked();
5757 }
5758 }
5759 }
5760
5761 // =========================================================
5762 // PERMISSIONS
5763 // =========================================================
5764
5765 static class PermissionController extends IPermissionController.Stub {
5766 ActivityManagerService mActivityManagerService;
5767 PermissionController(ActivityManagerService activityManagerService) {
5768 mActivityManagerService = activityManagerService;
5769 }
5770
5771 public boolean checkPermission(String permission, int pid, int uid) {
5772 return mActivityManagerService.checkPermission(permission, pid,
5773 uid) == PackageManager.PERMISSION_GRANTED;
5774 }
5775 }
5776
5777 /**
5778 * This can be called with or without the global lock held.
5779 */
5780 int checkComponentPermission(String permission, int pid, int uid,
5781 int reqUid) {
5782 // We might be performing an operation on behalf of an indirect binder
5783 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5784 // client identity accordingly before proceeding.
5785 Identity tlsIdentity = sCallerIdentity.get();
5786 if (tlsIdentity != null) {
5787 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5788 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5789 uid = tlsIdentity.uid;
5790 pid = tlsIdentity.pid;
5791 }
5792
5793 // Root, system server and our own process get to do everything.
5794 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5795 !Process.supportsProcesses()) {
5796 return PackageManager.PERMISSION_GRANTED;
5797 }
5798 // If the target requires a specific UID, always fail for others.
5799 if (reqUid >= 0 && uid != reqUid) {
5800 return PackageManager.PERMISSION_DENIED;
5801 }
5802 if (permission == null) {
5803 return PackageManager.PERMISSION_GRANTED;
5804 }
5805 try {
5806 return ActivityThread.getPackageManager()
5807 .checkUidPermission(permission, uid);
5808 } catch (RemoteException e) {
5809 // Should never happen, but if it does... deny!
5810 Log.e(TAG, "PackageManager is dead?!?", e);
5811 }
5812 return PackageManager.PERMISSION_DENIED;
5813 }
5814
5815 /**
5816 * As the only public entry point for permissions checking, this method
5817 * can enforce the semantic that requesting a check on a null global
5818 * permission is automatically denied. (Internally a null permission
5819 * string is used when calling {@link #checkComponentPermission} in cases
5820 * when only uid-based security is needed.)
5821 *
5822 * This can be called with or without the global lock held.
5823 */
5824 public int checkPermission(String permission, int pid, int uid) {
5825 if (permission == null) {
5826 return PackageManager.PERMISSION_DENIED;
5827 }
5828 return checkComponentPermission(permission, pid, uid, -1);
5829 }
5830
5831 /**
5832 * Binder IPC calls go through the public entry point.
5833 * This can be called with or without the global lock held.
5834 */
5835 int checkCallingPermission(String permission) {
5836 return checkPermission(permission,
5837 Binder.getCallingPid(),
5838 Binder.getCallingUid());
5839 }
5840
5841 /**
5842 * This can be called with or without the global lock held.
5843 */
5844 void enforceCallingPermission(String permission, String func) {
5845 if (checkCallingPermission(permission)
5846 == PackageManager.PERMISSION_GRANTED) {
5847 return;
5848 }
5849
5850 String msg = "Permission Denial: " + func + " from pid="
5851 + Binder.getCallingPid()
5852 + ", uid=" + Binder.getCallingUid()
5853 + " requires " + permission;
5854 Log.w(TAG, msg);
5855 throw new SecurityException(msg);
5856 }
5857
5858 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5859 ProviderInfo pi, int uid, int modeFlags) {
5860 try {
5861 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5862 if ((pi.readPermission != null) &&
5863 (pm.checkUidPermission(pi.readPermission, uid)
5864 != PackageManager.PERMISSION_GRANTED)) {
5865 return false;
5866 }
5867 }
5868 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5869 if ((pi.writePermission != null) &&
5870 (pm.checkUidPermission(pi.writePermission, uid)
5871 != PackageManager.PERMISSION_GRANTED)) {
5872 return false;
5873 }
5874 }
5875 return true;
5876 } catch (RemoteException e) {
5877 return false;
5878 }
5879 }
5880
5881 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5882 int modeFlags) {
5883 // Root gets to do everything.
5884 if (uid == 0 || !Process.supportsProcesses()) {
5885 return true;
5886 }
5887 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5888 if (perms == null) return false;
5889 UriPermission perm = perms.get(uri);
5890 if (perm == null) return false;
5891 return (modeFlags&perm.modeFlags) == modeFlags;
5892 }
5893
5894 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5895 // Another redirected-binder-call permissions check as in
5896 // {@link checkComponentPermission}.
5897 Identity tlsIdentity = sCallerIdentity.get();
5898 if (tlsIdentity != null) {
5899 uid = tlsIdentity.uid;
5900 pid = tlsIdentity.pid;
5901 }
5902
5903 // Our own process gets to do everything.
5904 if (pid == MY_PID) {
5905 return PackageManager.PERMISSION_GRANTED;
5906 }
5907 synchronized(this) {
5908 return checkUriPermissionLocked(uri, uid, modeFlags)
5909 ? PackageManager.PERMISSION_GRANTED
5910 : PackageManager.PERMISSION_DENIED;
5911 }
5912 }
5913
5914 private void grantUriPermissionLocked(int callingUid,
5915 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5916 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5917 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5918 if (modeFlags == 0) {
5919 return;
5920 }
5921
5922 final IPackageManager pm = ActivityThread.getPackageManager();
5923
5924 // If this is not a content: uri, we can't do anything with it.
5925 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5926 return;
5927 }
5928
5929 String name = uri.getAuthority();
5930 ProviderInfo pi = null;
5931 ContentProviderRecord cpr
5932 = (ContentProviderRecord)mProvidersByName.get(name);
5933 if (cpr != null) {
5934 pi = cpr.info;
5935 } else {
5936 try {
5937 pi = pm.resolveContentProvider(name,
5938 PackageManager.GET_URI_PERMISSION_PATTERNS);
5939 } catch (RemoteException ex) {
5940 }
5941 }
5942 if (pi == null) {
5943 Log.w(TAG, "No content provider found for: " + name);
5944 return;
5945 }
5946
5947 int targetUid;
5948 try {
5949 targetUid = pm.getPackageUid(targetPkg);
5950 if (targetUid < 0) {
5951 return;
5952 }
5953 } catch (RemoteException ex) {
5954 return;
5955 }
5956
5957 // First... does the target actually need this permission?
5958 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5959 // No need to grant the target this permission.
5960 return;
5961 }
5962
5963 // Second... maybe someone else has already granted the
5964 // permission?
5965 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5966 // No need to grant the target this permission.
5967 return;
5968 }
5969
5970 // Third... is the provider allowing granting of URI permissions?
5971 if (!pi.grantUriPermissions) {
5972 throw new SecurityException("Provider " + pi.packageName
5973 + "/" + pi.name
5974 + " does not allow granting of Uri permissions (uri "
5975 + uri + ")");
5976 }
5977 if (pi.uriPermissionPatterns != null) {
5978 final int N = pi.uriPermissionPatterns.length;
5979 boolean allowed = false;
5980 for (int i=0; i<N; i++) {
5981 if (pi.uriPermissionPatterns[i] != null
5982 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5983 allowed = true;
5984 break;
5985 }
5986 }
5987 if (!allowed) {
5988 throw new SecurityException("Provider " + pi.packageName
5989 + "/" + pi.name
5990 + " does not allow granting of permission to path of Uri "
5991 + uri);
5992 }
5993 }
5994
5995 // Fourth... does the caller itself have permission to access
5996 // this uri?
5997 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5998 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5999 throw new SecurityException("Uid " + callingUid
6000 + " does not have permission to uri " + uri);
6001 }
6002 }
6003
6004 // Okay! So here we are: the caller has the assumed permission
6005 // to the uri, and the target doesn't. Let's now give this to
6006 // the target.
6007
6008 HashMap<Uri, UriPermission> targetUris
6009 = mGrantedUriPermissions.get(targetUid);
6010 if (targetUris == null) {
6011 targetUris = new HashMap<Uri, UriPermission>();
6012 mGrantedUriPermissions.put(targetUid, targetUris);
6013 }
6014
6015 UriPermission perm = targetUris.get(uri);
6016 if (perm == null) {
6017 perm = new UriPermission(targetUid, uri);
6018 targetUris.put(uri, perm);
6019
6020 }
6021 perm.modeFlags |= modeFlags;
6022 if (activity == null) {
6023 perm.globalModeFlags |= modeFlags;
6024 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6025 perm.readActivities.add(activity);
6026 if (activity.readUriPermissions == null) {
6027 activity.readUriPermissions = new HashSet<UriPermission>();
6028 }
6029 activity.readUriPermissions.add(perm);
6030 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6031 perm.writeActivities.add(activity);
6032 if (activity.writeUriPermissions == null) {
6033 activity.writeUriPermissions = new HashSet<UriPermission>();
6034 }
6035 activity.writeUriPermissions.add(perm);
6036 }
6037 }
6038
6039 private void grantUriPermissionFromIntentLocked(int callingUid,
6040 String targetPkg, Intent intent, HistoryRecord activity) {
6041 if (intent == null) {
6042 return;
6043 }
6044 Uri data = intent.getData();
6045 if (data == null) {
6046 return;
6047 }
6048 grantUriPermissionLocked(callingUid, targetPkg, data,
6049 intent.getFlags(), activity);
6050 }
6051
6052 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6053 Uri uri, int modeFlags) {
6054 synchronized(this) {
6055 final ProcessRecord r = getRecordForAppLocked(caller);
6056 if (r == null) {
6057 throw new SecurityException("Unable to find app for caller "
6058 + caller
6059 + " when granting permission to uri " + uri);
6060 }
6061 if (targetPkg == null) {
6062 Log.w(TAG, "grantUriPermission: null target");
6063 return;
6064 }
6065 if (uri == null) {
6066 Log.w(TAG, "grantUriPermission: null uri");
6067 return;
6068 }
6069
6070 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6071 null);
6072 }
6073 }
6074
6075 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6076 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6077 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6078 HashMap<Uri, UriPermission> perms
6079 = mGrantedUriPermissions.get(perm.uid);
6080 if (perms != null) {
6081 perms.remove(perm.uri);
6082 if (perms.size() == 0) {
6083 mGrantedUriPermissions.remove(perm.uid);
6084 }
6085 }
6086 }
6087 }
6088
6089 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6090 if (activity.readUriPermissions != null) {
6091 for (UriPermission perm : activity.readUriPermissions) {
6092 perm.readActivities.remove(activity);
6093 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6094 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6095 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6096 removeUriPermissionIfNeededLocked(perm);
6097 }
6098 }
6099 }
6100 if (activity.writeUriPermissions != null) {
6101 for (UriPermission perm : activity.writeUriPermissions) {
6102 perm.writeActivities.remove(activity);
6103 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6104 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6105 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6106 removeUriPermissionIfNeededLocked(perm);
6107 }
6108 }
6109 }
6110 }
6111
6112 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6113 int modeFlags) {
6114 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6115 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6116 if (modeFlags == 0) {
6117 return;
6118 }
6119
6120 final IPackageManager pm = ActivityThread.getPackageManager();
6121
6122 final String authority = uri.getAuthority();
6123 ProviderInfo pi = null;
6124 ContentProviderRecord cpr
6125 = (ContentProviderRecord)mProvidersByName.get(authority);
6126 if (cpr != null) {
6127 pi = cpr.info;
6128 } else {
6129 try {
6130 pi = pm.resolveContentProvider(authority,
6131 PackageManager.GET_URI_PERMISSION_PATTERNS);
6132 } catch (RemoteException ex) {
6133 }
6134 }
6135 if (pi == null) {
6136 Log.w(TAG, "No content provider found for: " + authority);
6137 return;
6138 }
6139
6140 // Does the caller have this permission on the URI?
6141 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6142 // Right now, if you are not the original owner of the permission,
6143 // you are not allowed to revoke it.
6144 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6145 throw new SecurityException("Uid " + callingUid
6146 + " does not have permission to uri " + uri);
6147 //}
6148 }
6149
6150 // Go through all of the permissions and remove any that match.
6151 final List<String> SEGMENTS = uri.getPathSegments();
6152 if (SEGMENTS != null) {
6153 final int NS = SEGMENTS.size();
6154 int N = mGrantedUriPermissions.size();
6155 for (int i=0; i<N; i++) {
6156 HashMap<Uri, UriPermission> perms
6157 = mGrantedUriPermissions.valueAt(i);
6158 Iterator<UriPermission> it = perms.values().iterator();
6159 toploop:
6160 while (it.hasNext()) {
6161 UriPermission perm = it.next();
6162 Uri targetUri = perm.uri;
6163 if (!authority.equals(targetUri.getAuthority())) {
6164 continue;
6165 }
6166 List<String> targetSegments = targetUri.getPathSegments();
6167 if (targetSegments == null) {
6168 continue;
6169 }
6170 if (targetSegments.size() < NS) {
6171 continue;
6172 }
6173 for (int j=0; j<NS; j++) {
6174 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6175 continue toploop;
6176 }
6177 }
6178 perm.clearModes(modeFlags);
6179 if (perm.modeFlags == 0) {
6180 it.remove();
6181 }
6182 }
6183 if (perms.size() == 0) {
6184 mGrantedUriPermissions.remove(
6185 mGrantedUriPermissions.keyAt(i));
6186 N--;
6187 i--;
6188 }
6189 }
6190 }
6191 }
6192
6193 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6194 int modeFlags) {
6195 synchronized(this) {
6196 final ProcessRecord r = getRecordForAppLocked(caller);
6197 if (r == null) {
6198 throw new SecurityException("Unable to find app for caller "
6199 + caller
6200 + " when revoking permission to uri " + uri);
6201 }
6202 if (uri == null) {
6203 Log.w(TAG, "revokeUriPermission: null uri");
6204 return;
6205 }
6206
6207 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6208 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6209 if (modeFlags == 0) {
6210 return;
6211 }
6212
6213 final IPackageManager pm = ActivityThread.getPackageManager();
6214
6215 final String authority = uri.getAuthority();
6216 ProviderInfo pi = null;
6217 ContentProviderRecord cpr
6218 = (ContentProviderRecord)mProvidersByName.get(authority);
6219 if (cpr != null) {
6220 pi = cpr.info;
6221 } else {
6222 try {
6223 pi = pm.resolveContentProvider(authority,
6224 PackageManager.GET_URI_PERMISSION_PATTERNS);
6225 } catch (RemoteException ex) {
6226 }
6227 }
6228 if (pi == null) {
6229 Log.w(TAG, "No content provider found for: " + authority);
6230 return;
6231 }
6232
6233 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6234 }
6235 }
6236
6237 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6238 synchronized (this) {
6239 ProcessRecord app =
6240 who != null ? getRecordForAppLocked(who) : null;
6241 if (app == null) return;
6242
6243 Message msg = Message.obtain();
6244 msg.what = WAIT_FOR_DEBUGGER_MSG;
6245 msg.obj = app;
6246 msg.arg1 = waiting ? 1 : 0;
6247 mHandler.sendMessage(msg);
6248 }
6249 }
6250
6251 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6252 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006253 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006254 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006255 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006256 }
6257
6258 // =========================================================
6259 // TASK MANAGEMENT
6260 // =========================================================
6261
6262 public List getTasks(int maxNum, int flags,
6263 IThumbnailReceiver receiver) {
6264 ArrayList list = new ArrayList();
6265
6266 PendingThumbnailsRecord pending = null;
6267 IApplicationThread topThumbnail = null;
6268 HistoryRecord topRecord = null;
6269
6270 synchronized(this) {
6271 if (localLOGV) Log.v(
6272 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6273 + ", receiver=" + receiver);
6274
6275 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6276 != PackageManager.PERMISSION_GRANTED) {
6277 if (receiver != null) {
6278 // If the caller wants to wait for pending thumbnails,
6279 // it ain't gonna get them.
6280 try {
6281 receiver.finished();
6282 } catch (RemoteException ex) {
6283 }
6284 }
6285 String msg = "Permission Denial: getTasks() from pid="
6286 + Binder.getCallingPid()
6287 + ", uid=" + Binder.getCallingUid()
6288 + " requires " + android.Manifest.permission.GET_TASKS;
6289 Log.w(TAG, msg);
6290 throw new SecurityException(msg);
6291 }
6292
6293 int pos = mHistory.size()-1;
6294 HistoryRecord next =
6295 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6296 HistoryRecord top = null;
6297 CharSequence topDescription = null;
6298 TaskRecord curTask = null;
6299 int numActivities = 0;
6300 int numRunning = 0;
6301 while (pos >= 0 && maxNum > 0) {
6302 final HistoryRecord r = next;
6303 pos--;
6304 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6305
6306 // Initialize state for next task if needed.
6307 if (top == null ||
6308 (top.state == ActivityState.INITIALIZING
6309 && top.task == r.task)) {
6310 top = r;
6311 topDescription = r.description;
6312 curTask = r.task;
6313 numActivities = numRunning = 0;
6314 }
6315
6316 // Add 'r' into the current task.
6317 numActivities++;
6318 if (r.app != null && r.app.thread != null) {
6319 numRunning++;
6320 }
6321 if (topDescription == null) {
6322 topDescription = r.description;
6323 }
6324
6325 if (localLOGV) Log.v(
6326 TAG, r.intent.getComponent().flattenToShortString()
6327 + ": task=" + r.task);
6328
6329 // If the next one is a different task, generate a new
6330 // TaskInfo entry for what we have.
6331 if (next == null || next.task != curTask) {
6332 ActivityManager.RunningTaskInfo ci
6333 = new ActivityManager.RunningTaskInfo();
6334 ci.id = curTask.taskId;
6335 ci.baseActivity = r.intent.getComponent();
6336 ci.topActivity = top.intent.getComponent();
6337 ci.thumbnail = top.thumbnail;
6338 ci.description = topDescription;
6339 ci.numActivities = numActivities;
6340 ci.numRunning = numRunning;
6341 //System.out.println(
6342 // "#" + maxNum + ": " + " descr=" + ci.description);
6343 if (ci.thumbnail == null && receiver != null) {
6344 if (localLOGV) Log.v(
6345 TAG, "State=" + top.state + "Idle=" + top.idle
6346 + " app=" + top.app
6347 + " thr=" + (top.app != null ? top.app.thread : null));
6348 if (top.state == ActivityState.RESUMED
6349 || top.state == ActivityState.PAUSING) {
6350 if (top.idle && top.app != null
6351 && top.app.thread != null) {
6352 topRecord = top;
6353 topThumbnail = top.app.thread;
6354 } else {
6355 top.thumbnailNeeded = true;
6356 }
6357 }
6358 if (pending == null) {
6359 pending = new PendingThumbnailsRecord(receiver);
6360 }
6361 pending.pendingRecords.add(top);
6362 }
6363 list.add(ci);
6364 maxNum--;
6365 top = null;
6366 }
6367 }
6368
6369 if (pending != null) {
6370 mPendingThumbnails.add(pending);
6371 }
6372 }
6373
6374 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6375
6376 if (topThumbnail != null) {
6377 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6378 try {
6379 topThumbnail.requestThumbnail(topRecord);
6380 } catch (Exception e) {
6381 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6382 sendPendingThumbnail(null, topRecord, null, null, true);
6383 }
6384 }
6385
6386 if (pending == null && receiver != null) {
6387 // In this case all thumbnails were available and the client
6388 // is being asked to be told when the remaining ones come in...
6389 // which is unusually, since the top-most currently running
6390 // activity should never have a canned thumbnail! Oh well.
6391 try {
6392 receiver.finished();
6393 } catch (RemoteException ex) {
6394 }
6395 }
6396
6397 return list;
6398 }
6399
6400 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6401 int flags) {
6402 synchronized (this) {
6403 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6404 "getRecentTasks()");
6405
6406 final int N = mRecentTasks.size();
6407 ArrayList<ActivityManager.RecentTaskInfo> res
6408 = new ArrayList<ActivityManager.RecentTaskInfo>(
6409 maxNum < N ? maxNum : N);
6410 for (int i=0; i<N && maxNum > 0; i++) {
6411 TaskRecord tr = mRecentTasks.get(i);
6412 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6413 || (tr.intent == null)
6414 || ((tr.intent.getFlags()
6415 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6416 ActivityManager.RecentTaskInfo rti
6417 = new ActivityManager.RecentTaskInfo();
6418 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6419 rti.baseIntent = new Intent(
6420 tr.intent != null ? tr.intent : tr.affinityIntent);
6421 rti.origActivity = tr.origActivity;
6422 res.add(rti);
6423 maxNum--;
6424 }
6425 }
6426 return res;
6427 }
6428 }
6429
6430 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6431 int j;
6432 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6433 TaskRecord jt = startTask;
6434
6435 // First look backwards
6436 for (j=startIndex-1; j>=0; j--) {
6437 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6438 if (r.task != jt) {
6439 jt = r.task;
6440 if (affinity.equals(jt.affinity)) {
6441 return j;
6442 }
6443 }
6444 }
6445
6446 // Now look forwards
6447 final int N = mHistory.size();
6448 jt = startTask;
6449 for (j=startIndex+1; j<N; j++) {
6450 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6451 if (r.task != jt) {
6452 if (affinity.equals(jt.affinity)) {
6453 return j;
6454 }
6455 jt = r.task;
6456 }
6457 }
6458
6459 // Might it be at the top?
6460 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6461 return N-1;
6462 }
6463
6464 return -1;
6465 }
6466
6467 /**
6468 * Perform a reset of the given task, if needed as part of launching it.
6469 * Returns the new HistoryRecord at the top of the task.
6470 */
6471 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6472 HistoryRecord newActivity) {
6473 boolean forceReset = (newActivity.info.flags
6474 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6475 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6476 if ((newActivity.info.flags
6477 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6478 forceReset = true;
6479 }
6480 }
6481
6482 final TaskRecord task = taskTop.task;
6483
6484 // We are going to move through the history list so that we can look
6485 // at each activity 'target' with 'below' either the interesting
6486 // activity immediately below it in the stack or null.
6487 HistoryRecord target = null;
6488 int targetI = 0;
6489 int taskTopI = -1;
6490 int replyChainEnd = -1;
6491 int lastReparentPos = -1;
6492 for (int i=mHistory.size()-1; i>=-1; i--) {
6493 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6494
6495 if (below != null && below.finishing) {
6496 continue;
6497 }
6498 if (target == null) {
6499 target = below;
6500 targetI = i;
6501 // If we were in the middle of a reply chain before this
6502 // task, it doesn't appear like the root of the chain wants
6503 // anything interesting, so drop it.
6504 replyChainEnd = -1;
6505 continue;
6506 }
6507
6508 final int flags = target.info.flags;
6509
6510 final boolean finishOnTaskLaunch =
6511 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6512 final boolean allowTaskReparenting =
6513 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6514
6515 if (target.task == task) {
6516 // We are inside of the task being reset... we'll either
6517 // finish this activity, push it out for another task,
6518 // or leave it as-is. We only do this
6519 // for activities that are not the root of the task (since
6520 // if we finish the root, we may no longer have the task!).
6521 if (taskTopI < 0) {
6522 taskTopI = targetI;
6523 }
6524 if (below != null && below.task == task) {
6525 final boolean clearWhenTaskReset =
6526 (target.intent.getFlags()
6527 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006528 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006529 // If this activity is sending a reply to a previous
6530 // activity, we can't do anything with it now until
6531 // we reach the start of the reply chain.
6532 // XXX note that we are assuming the result is always
6533 // to the previous activity, which is almost always
6534 // the case but we really shouldn't count on.
6535 if (replyChainEnd < 0) {
6536 replyChainEnd = targetI;
6537 }
Ed Heyl73798232009-03-24 21:32:21 -07006538 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006539 && target.taskAffinity != null
6540 && !target.taskAffinity.equals(task.affinity)) {
6541 // If this activity has an affinity for another
6542 // task, then we need to move it out of here. We will
6543 // move it as far out of the way as possible, to the
6544 // bottom of the activity stack. This also keeps it
6545 // correctly ordered with any activities we previously
6546 // moved.
6547 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6548 if (target.taskAffinity != null
6549 && target.taskAffinity.equals(p.task.affinity)) {
6550 // If the activity currently at the bottom has the
6551 // same task affinity as the one we are moving,
6552 // then merge it into the same task.
6553 target.task = p.task;
6554 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6555 + " out to bottom task " + p.task);
6556 } else {
6557 mCurTask++;
6558 if (mCurTask <= 0) {
6559 mCurTask = 1;
6560 }
6561 target.task = new TaskRecord(mCurTask, target.info, null,
6562 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6563 target.task.affinityIntent = target.intent;
6564 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6565 + " out to new task " + target.task);
6566 }
6567 mWindowManager.setAppGroupId(target, task.taskId);
6568 if (replyChainEnd < 0) {
6569 replyChainEnd = targetI;
6570 }
6571 int dstPos = 0;
6572 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6573 p = (HistoryRecord)mHistory.get(srcPos);
6574 if (p.finishing) {
6575 continue;
6576 }
6577 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6578 + " out to target's task " + target.task);
6579 task.numActivities--;
6580 p.task = target.task;
6581 target.task.numActivities++;
6582 mHistory.remove(srcPos);
6583 mHistory.add(dstPos, p);
6584 mWindowManager.moveAppToken(dstPos, p);
6585 mWindowManager.setAppGroupId(p, p.task.taskId);
6586 dstPos++;
6587 if (VALIDATE_TOKENS) {
6588 mWindowManager.validateAppTokens(mHistory);
6589 }
6590 i++;
6591 }
6592 if (taskTop == p) {
6593 taskTop = below;
6594 }
6595 if (taskTopI == replyChainEnd) {
6596 taskTopI = -1;
6597 }
6598 replyChainEnd = -1;
6599 addRecentTask(target.task);
6600 } else if (forceReset || finishOnTaskLaunch
6601 || clearWhenTaskReset) {
6602 // If the activity should just be removed -- either
6603 // because it asks for it, or the task should be
6604 // cleared -- then finish it and anything that is
6605 // part of its reply chain.
6606 if (clearWhenTaskReset) {
6607 // In this case, we want to finish this activity
6608 // and everything above it, so be sneaky and pretend
6609 // like these are all in the reply chain.
6610 replyChainEnd = targetI+1;
6611 while (replyChainEnd < mHistory.size() &&
6612 ((HistoryRecord)mHistory.get(
6613 replyChainEnd)).task == task) {
6614 replyChainEnd++;
6615 }
6616 replyChainEnd--;
6617 } else if (replyChainEnd < 0) {
6618 replyChainEnd = targetI;
6619 }
6620 HistoryRecord p = null;
6621 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6622 p = (HistoryRecord)mHistory.get(srcPos);
6623 if (p.finishing) {
6624 continue;
6625 }
6626 if (finishActivityLocked(p, srcPos,
6627 Activity.RESULT_CANCELED, null, "reset")) {
6628 replyChainEnd--;
6629 srcPos--;
6630 }
6631 }
6632 if (taskTop == p) {
6633 taskTop = below;
6634 }
6635 if (taskTopI == replyChainEnd) {
6636 taskTopI = -1;
6637 }
6638 replyChainEnd = -1;
6639 } else {
6640 // If we were in the middle of a chain, well the
6641 // activity that started it all doesn't want anything
6642 // special, so leave it all as-is.
6643 replyChainEnd = -1;
6644 }
6645 } else {
6646 // Reached the bottom of the task -- any reply chain
6647 // should be left as-is.
6648 replyChainEnd = -1;
6649 }
6650
6651 } else if (target.resultTo != null) {
6652 // If this activity is sending a reply to a previous
6653 // activity, we can't do anything with it now until
6654 // we reach the start of the reply chain.
6655 // XXX note that we are assuming the result is always
6656 // to the previous activity, which is almost always
6657 // the case but we really shouldn't count on.
6658 if (replyChainEnd < 0) {
6659 replyChainEnd = targetI;
6660 }
6661
6662 } else if (taskTopI >= 0 && allowTaskReparenting
6663 && task.affinity != null
6664 && task.affinity.equals(target.taskAffinity)) {
6665 // We are inside of another task... if this activity has
6666 // an affinity for our task, then either remove it if we are
6667 // clearing or move it over to our task. Note that
6668 // we currently punt on the case where we are resetting a
6669 // task that is not at the top but who has activities above
6670 // with an affinity to it... this is really not a normal
6671 // case, and we will need to later pull that task to the front
6672 // and usually at that point we will do the reset and pick
6673 // up those remaining activities. (This only happens if
6674 // someone starts an activity in a new task from an activity
6675 // in a task that is not currently on top.)
6676 if (forceReset || finishOnTaskLaunch) {
6677 if (replyChainEnd < 0) {
6678 replyChainEnd = targetI;
6679 }
6680 HistoryRecord p = null;
6681 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6682 p = (HistoryRecord)mHistory.get(srcPos);
6683 if (p.finishing) {
6684 continue;
6685 }
6686 if (finishActivityLocked(p, srcPos,
6687 Activity.RESULT_CANCELED, null, "reset")) {
6688 taskTopI--;
6689 lastReparentPos--;
6690 replyChainEnd--;
6691 srcPos--;
6692 }
6693 }
6694 replyChainEnd = -1;
6695 } else {
6696 if (replyChainEnd < 0) {
6697 replyChainEnd = targetI;
6698 }
6699 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6700 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6701 if (p.finishing) {
6702 continue;
6703 }
6704 if (lastReparentPos < 0) {
6705 lastReparentPos = taskTopI;
6706 taskTop = p;
6707 } else {
6708 lastReparentPos--;
6709 }
6710 mHistory.remove(srcPos);
6711 p.task.numActivities--;
6712 p.task = task;
6713 mHistory.add(lastReparentPos, p);
6714 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6715 + " in to resetting task " + task);
6716 task.numActivities++;
6717 mWindowManager.moveAppToken(lastReparentPos, p);
6718 mWindowManager.setAppGroupId(p, p.task.taskId);
6719 if (VALIDATE_TOKENS) {
6720 mWindowManager.validateAppTokens(mHistory);
6721 }
6722 }
6723 replyChainEnd = -1;
6724
6725 // Now we've moved it in to place... but what if this is
6726 // a singleTop activity and we have put it on top of another
6727 // instance of the same activity? Then we drop the instance
6728 // below so it remains singleTop.
6729 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6730 for (int j=lastReparentPos-1; j>=0; j--) {
6731 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6732 if (p.finishing) {
6733 continue;
6734 }
6735 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6736 if (finishActivityLocked(p, j,
6737 Activity.RESULT_CANCELED, null, "replace")) {
6738 taskTopI--;
6739 lastReparentPos--;
6740 }
6741 }
6742 }
6743 }
6744 }
6745 }
6746
6747 target = below;
6748 targetI = i;
6749 }
6750
6751 return taskTop;
6752 }
6753
6754 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006755 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006756 */
6757 public void moveTaskToFront(int task) {
6758 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6759 "moveTaskToFront()");
6760
6761 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006762 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6763 Binder.getCallingUid(), "Task to front")) {
6764 return;
6765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006766 final long origId = Binder.clearCallingIdentity();
6767 try {
6768 int N = mRecentTasks.size();
6769 for (int i=0; i<N; i++) {
6770 TaskRecord tr = mRecentTasks.get(i);
6771 if (tr.taskId == task) {
6772 moveTaskToFrontLocked(tr);
6773 return;
6774 }
6775 }
6776 for (int i=mHistory.size()-1; i>=0; i--) {
6777 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6778 if (hr.task.taskId == task) {
6779 moveTaskToFrontLocked(hr.task);
6780 return;
6781 }
6782 }
6783 } finally {
6784 Binder.restoreCallingIdentity(origId);
6785 }
6786 }
6787 }
6788
6789 private final void moveTaskToFrontLocked(TaskRecord tr) {
6790 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6791
6792 final int task = tr.taskId;
6793 int top = mHistory.size()-1;
6794
6795 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6796 // nothing to do!
6797 return;
6798 }
6799
6800 if (DEBUG_TRANSITION) Log.v(TAG,
6801 "Prepare to front transition: task=" + tr);
6802 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6803
6804 ArrayList moved = new ArrayList();
6805
6806 // Applying the affinities may have removed entries from the history,
6807 // so get the size again.
6808 top = mHistory.size()-1;
6809 int pos = top;
6810
6811 // Shift all activities with this task up to the top
6812 // of the stack, keeping them in the same internal order.
6813 while (pos >= 0) {
6814 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6815 if (localLOGV) Log.v(
6816 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6817 boolean first = true;
6818 if (r.task.taskId == task) {
6819 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6820 mHistory.remove(pos);
6821 mHistory.add(top, r);
6822 moved.add(0, r);
6823 top--;
6824 if (first) {
6825 addRecentTask(r.task);
6826 first = false;
6827 }
6828 }
6829 pos--;
6830 }
6831
6832 mWindowManager.moveAppTokensToTop(moved);
6833 if (VALIDATE_TOKENS) {
6834 mWindowManager.validateAppTokens(mHistory);
6835 }
6836
6837 finishTaskMove(task);
6838 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6839 }
6840
6841 private final void finishTaskMove(int task) {
6842 resumeTopActivityLocked(null);
6843 }
6844
6845 public void moveTaskToBack(int task) {
6846 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6847 "moveTaskToBack()");
6848
6849 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006850 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6851 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6852 Binder.getCallingUid(), "Task to back")) {
6853 return;
6854 }
6855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006856 final long origId = Binder.clearCallingIdentity();
6857 moveTaskToBackLocked(task);
6858 Binder.restoreCallingIdentity(origId);
6859 }
6860 }
6861
6862 /**
6863 * Moves an activity, and all of the other activities within the same task, to the bottom
6864 * of the history stack. The activity's order within the task is unchanged.
6865 *
6866 * @param token A reference to the activity we wish to move
6867 * @param nonRoot If false then this only works if the activity is the root
6868 * of a task; if true it will work for any activity in a task.
6869 * @return Returns true if the move completed, false if not.
6870 */
6871 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6872 synchronized(this) {
6873 final long origId = Binder.clearCallingIdentity();
6874 int taskId = getTaskForActivityLocked(token, !nonRoot);
6875 if (taskId >= 0) {
6876 return moveTaskToBackLocked(taskId);
6877 }
6878 Binder.restoreCallingIdentity(origId);
6879 }
6880 return false;
6881 }
6882
6883 /**
6884 * Worker method for rearranging history stack. Implements the function of moving all
6885 * activities for a specific task (gathering them if disjoint) into a single group at the
6886 * bottom of the stack.
6887 *
6888 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6889 * to premeptively cancel the move.
6890 *
6891 * @param task The taskId to collect and move to the bottom.
6892 * @return Returns true if the move completed, false if not.
6893 */
6894 private final boolean moveTaskToBackLocked(int task) {
6895 Log.i(TAG, "moveTaskToBack: " + task);
6896
6897 // If we have a watcher, preflight the move before committing to it. First check
6898 // for *other* available tasks, but if none are available, then try again allowing the
6899 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006900 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006901 HistoryRecord next = topRunningActivityLocked(null, task);
6902 if (next == null) {
6903 next = topRunningActivityLocked(null, 0);
6904 }
6905 if (next != null) {
6906 // ask watcher if this is allowed
6907 boolean moveOK = true;
6908 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006909 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006910 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006911 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006912 }
6913 if (!moveOK) {
6914 return false;
6915 }
6916 }
6917 }
6918
6919 ArrayList moved = new ArrayList();
6920
6921 if (DEBUG_TRANSITION) Log.v(TAG,
6922 "Prepare to back transition: task=" + task);
6923 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6924
6925 final int N = mHistory.size();
6926 int bottom = 0;
6927 int pos = 0;
6928
6929 // Shift all activities with this task down to the bottom
6930 // of the stack, keeping them in the same internal order.
6931 while (pos < N) {
6932 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6933 if (localLOGV) Log.v(
6934 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6935 if (r.task.taskId == task) {
6936 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6937 mHistory.remove(pos);
6938 mHistory.add(bottom, r);
6939 moved.add(r);
6940 bottom++;
6941 }
6942 pos++;
6943 }
6944
6945 mWindowManager.moveAppTokensToBottom(moved);
6946 if (VALIDATE_TOKENS) {
6947 mWindowManager.validateAppTokens(mHistory);
6948 }
6949
6950 finishTaskMove(task);
6951 return true;
6952 }
6953
6954 public void moveTaskBackwards(int task) {
6955 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6956 "moveTaskBackwards()");
6957
6958 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006959 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6960 Binder.getCallingUid(), "Task backwards")) {
6961 return;
6962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006963 final long origId = Binder.clearCallingIdentity();
6964 moveTaskBackwardsLocked(task);
6965 Binder.restoreCallingIdentity(origId);
6966 }
6967 }
6968
6969 private final void moveTaskBackwardsLocked(int task) {
6970 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6971 }
6972
6973 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6974 synchronized(this) {
6975 return getTaskForActivityLocked(token, onlyRoot);
6976 }
6977 }
6978
6979 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6980 final int N = mHistory.size();
6981 TaskRecord lastTask = null;
6982 for (int i=0; i<N; i++) {
6983 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6984 if (r == token) {
6985 if (!onlyRoot || lastTask != r.task) {
6986 return r.task.taskId;
6987 }
6988 return -1;
6989 }
6990 lastTask = r.task;
6991 }
6992
6993 return -1;
6994 }
6995
6996 /**
6997 * Returns the top activity in any existing task matching the given
6998 * Intent. Returns null if no such task is found.
6999 */
7000 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7001 ComponentName cls = intent.getComponent();
7002 if (info.targetActivity != null) {
7003 cls = new ComponentName(info.packageName, info.targetActivity);
7004 }
7005
7006 TaskRecord cp = null;
7007
7008 final int N = mHistory.size();
7009 for (int i=(N-1); i>=0; i--) {
7010 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7011 if (!r.finishing && r.task != cp
7012 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7013 cp = r.task;
7014 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7015 // + "/aff=" + r.task.affinity + " to new cls="
7016 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7017 if (r.task.affinity != null) {
7018 if (r.task.affinity.equals(info.taskAffinity)) {
7019 //Log.i(TAG, "Found matching affinity!");
7020 return r;
7021 }
7022 } else if (r.task.intent != null
7023 && r.task.intent.getComponent().equals(cls)) {
7024 //Log.i(TAG, "Found matching class!");
7025 //dump();
7026 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7027 return r;
7028 } else if (r.task.affinityIntent != null
7029 && r.task.affinityIntent.getComponent().equals(cls)) {
7030 //Log.i(TAG, "Found matching class!");
7031 //dump();
7032 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7033 return r;
7034 }
7035 }
7036 }
7037
7038 return null;
7039 }
7040
7041 /**
7042 * Returns the first activity (starting from the top of the stack) that
7043 * is the same as the given activity. Returns null if no such activity
7044 * is found.
7045 */
7046 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7047 ComponentName cls = intent.getComponent();
7048 if (info.targetActivity != null) {
7049 cls = new ComponentName(info.packageName, info.targetActivity);
7050 }
7051
7052 final int N = mHistory.size();
7053 for (int i=(N-1); i>=0; i--) {
7054 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7055 if (!r.finishing) {
7056 if (r.intent.getComponent().equals(cls)) {
7057 //Log.i(TAG, "Found matching class!");
7058 //dump();
7059 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7060 return r;
7061 }
7062 }
7063 }
7064
7065 return null;
7066 }
7067
7068 public void finishOtherInstances(IBinder token, ComponentName className) {
7069 synchronized(this) {
7070 final long origId = Binder.clearCallingIdentity();
7071
7072 int N = mHistory.size();
7073 TaskRecord lastTask = null;
7074 for (int i=0; i<N; i++) {
7075 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7076 if (r.realActivity.equals(className)
7077 && r != token && lastTask != r.task) {
7078 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7079 null, "others")) {
7080 i--;
7081 N--;
7082 }
7083 }
7084 lastTask = r.task;
7085 }
7086
7087 Binder.restoreCallingIdentity(origId);
7088 }
7089 }
7090
7091 // =========================================================
7092 // THUMBNAILS
7093 // =========================================================
7094
7095 public void reportThumbnail(IBinder token,
7096 Bitmap thumbnail, CharSequence description) {
7097 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7098 final long origId = Binder.clearCallingIdentity();
7099 sendPendingThumbnail(null, token, thumbnail, description, true);
7100 Binder.restoreCallingIdentity(origId);
7101 }
7102
7103 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7104 Bitmap thumbnail, CharSequence description, boolean always) {
7105 TaskRecord task = null;
7106 ArrayList receivers = null;
7107
7108 //System.out.println("Send pending thumbnail: " + r);
7109
7110 synchronized(this) {
7111 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007112 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007113 if (index < 0) {
7114 return;
7115 }
7116 r = (HistoryRecord)mHistory.get(index);
7117 }
7118 if (thumbnail == null) {
7119 thumbnail = r.thumbnail;
7120 description = r.description;
7121 }
7122 if (thumbnail == null && !always) {
7123 // If there is no thumbnail, and this entry is not actually
7124 // going away, then abort for now and pick up the next
7125 // thumbnail we get.
7126 return;
7127 }
7128 task = r.task;
7129
7130 int N = mPendingThumbnails.size();
7131 int i=0;
7132 while (i<N) {
7133 PendingThumbnailsRecord pr =
7134 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7135 //System.out.println("Looking in " + pr.pendingRecords);
7136 if (pr.pendingRecords.remove(r)) {
7137 if (receivers == null) {
7138 receivers = new ArrayList();
7139 }
7140 receivers.add(pr);
7141 if (pr.pendingRecords.size() == 0) {
7142 pr.finished = true;
7143 mPendingThumbnails.remove(i);
7144 N--;
7145 continue;
7146 }
7147 }
7148 i++;
7149 }
7150 }
7151
7152 if (receivers != null) {
7153 final int N = receivers.size();
7154 for (int i=0; i<N; i++) {
7155 try {
7156 PendingThumbnailsRecord pr =
7157 (PendingThumbnailsRecord)receivers.get(i);
7158 pr.receiver.newThumbnail(
7159 task != null ? task.taskId : -1, thumbnail, description);
7160 if (pr.finished) {
7161 pr.receiver.finished();
7162 }
7163 } catch (Exception e) {
7164 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7165 }
7166 }
7167 }
7168 }
7169
7170 // =========================================================
7171 // CONTENT PROVIDERS
7172 // =========================================================
7173
7174 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7175 List providers = null;
7176 try {
7177 providers = ActivityThread.getPackageManager().
7178 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007179 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007180 } catch (RemoteException ex) {
7181 }
7182 if (providers != null) {
7183 final int N = providers.size();
7184 for (int i=0; i<N; i++) {
7185 ProviderInfo cpi =
7186 (ProviderInfo)providers.get(i);
7187 ContentProviderRecord cpr =
7188 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7189 if (cpr == null) {
7190 cpr = new ContentProviderRecord(cpi, app.info);
7191 mProvidersByClass.put(cpi.name, cpr);
7192 }
7193 app.pubProviders.put(cpi.name, cpr);
7194 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007195 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007196 }
7197 }
7198 return providers;
7199 }
7200
7201 private final String checkContentProviderPermissionLocked(
7202 ProviderInfo cpi, ProcessRecord r, int mode) {
7203 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7204 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7205 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7206 cpi.exported ? -1 : cpi.applicationInfo.uid)
7207 == PackageManager.PERMISSION_GRANTED
7208 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7209 return null;
7210 }
7211 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7212 cpi.exported ? -1 : cpi.applicationInfo.uid)
7213 == PackageManager.PERMISSION_GRANTED) {
7214 return null;
7215 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007216
7217 PathPermission[] pps = cpi.pathPermissions;
7218 if (pps != null) {
7219 int i = pps.length;
7220 while (i > 0) {
7221 i--;
7222 PathPermission pp = pps[i];
7223 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7224 cpi.exported ? -1 : cpi.applicationInfo.uid)
7225 == PackageManager.PERMISSION_GRANTED
7226 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7227 return null;
7228 }
7229 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7230 cpi.exported ? -1 : cpi.applicationInfo.uid)
7231 == PackageManager.PERMISSION_GRANTED) {
7232 return null;
7233 }
7234 }
7235 }
7236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007237 String msg = "Permission Denial: opening provider " + cpi.name
7238 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7239 + ", uid=" + callingUid + ") requires "
7240 + cpi.readPermission + " or " + cpi.writePermission;
7241 Log.w(TAG, msg);
7242 return msg;
7243 }
7244
7245 private final ContentProviderHolder getContentProviderImpl(
7246 IApplicationThread caller, String name) {
7247 ContentProviderRecord cpr;
7248 ProviderInfo cpi = null;
7249
7250 synchronized(this) {
7251 ProcessRecord r = null;
7252 if (caller != null) {
7253 r = getRecordForAppLocked(caller);
7254 if (r == null) {
7255 throw new SecurityException(
7256 "Unable to find app for caller " + caller
7257 + " (pid=" + Binder.getCallingPid()
7258 + ") when getting content provider " + name);
7259 }
7260 }
7261
7262 // First check if this content provider has been published...
7263 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7264 if (cpr != null) {
7265 cpi = cpr.info;
7266 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7267 return new ContentProviderHolder(cpi,
7268 cpi.readPermission != null
7269 ? cpi.readPermission : cpi.writePermission);
7270 }
7271
7272 if (r != null && cpr.canRunHere(r)) {
7273 // This provider has been published or is in the process
7274 // of being published... but it is also allowed to run
7275 // in the caller's process, so don't make a connection
7276 // and just let the caller instantiate its own instance.
7277 if (cpr.provider != null) {
7278 // don't give caller the provider object, it needs
7279 // to make its own.
7280 cpr = new ContentProviderRecord(cpr);
7281 }
7282 return cpr;
7283 }
7284
7285 final long origId = Binder.clearCallingIdentity();
7286
7287 // In this case the provider is a single instance, so we can
7288 // return it right away.
7289 if (r != null) {
7290 r.conProviders.add(cpr);
7291 cpr.clients.add(r);
7292 } else {
7293 cpr.externals++;
7294 }
7295
7296 if (cpr.app != null) {
7297 updateOomAdjLocked(cpr.app);
7298 }
7299
7300 Binder.restoreCallingIdentity(origId);
7301
7302 } else {
7303 try {
7304 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007305 resolveContentProvider(name,
7306 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007307 } catch (RemoteException ex) {
7308 }
7309 if (cpi == null) {
7310 return null;
7311 }
7312
7313 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7314 return new ContentProviderHolder(cpi,
7315 cpi.readPermission != null
7316 ? cpi.readPermission : cpi.writePermission);
7317 }
7318
7319 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7320 final boolean firstClass = cpr == null;
7321 if (firstClass) {
7322 try {
7323 ApplicationInfo ai =
7324 ActivityThread.getPackageManager().
7325 getApplicationInfo(
7326 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007327 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007328 if (ai == null) {
7329 Log.w(TAG, "No package info for content provider "
7330 + cpi.name);
7331 return null;
7332 }
7333 cpr = new ContentProviderRecord(cpi, ai);
7334 } catch (RemoteException ex) {
7335 // pm is in same process, this will never happen.
7336 }
7337 }
7338
7339 if (r != null && cpr.canRunHere(r)) {
7340 // If this is a multiprocess provider, then just return its
7341 // info and allow the caller to instantiate it. Only do
7342 // this if the provider is the same user as the caller's
7343 // process, or can run as root (so can be in any process).
7344 return cpr;
7345 }
7346
7347 if (false) {
7348 RuntimeException e = new RuntimeException("foo");
7349 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7350 // + " pruid " + ai.uid + "): " + cpi.className, e);
7351 }
7352
7353 // This is single process, and our app is now connecting to it.
7354 // See if we are already in the process of launching this
7355 // provider.
7356 final int N = mLaunchingProviders.size();
7357 int i;
7358 for (i=0; i<N; i++) {
7359 if (mLaunchingProviders.get(i) == cpr) {
7360 break;
7361 }
7362 if (false) {
7363 final ContentProviderRecord rec =
7364 (ContentProviderRecord)mLaunchingProviders.get(i);
7365 if (rec.info.name.equals(cpr.info.name)) {
7366 cpr = rec;
7367 break;
7368 }
7369 }
7370 }
7371
7372 // If the provider is not already being launched, then get it
7373 // started.
7374 if (i >= N) {
7375 final long origId = Binder.clearCallingIdentity();
7376 ProcessRecord proc = startProcessLocked(cpi.processName,
7377 cpr.appInfo, false, 0, "content provider",
7378 new ComponentName(cpi.applicationInfo.packageName,
7379 cpi.name));
7380 if (proc == null) {
7381 Log.w(TAG, "Unable to launch app "
7382 + cpi.applicationInfo.packageName + "/"
7383 + cpi.applicationInfo.uid + " for provider "
7384 + name + ": process is bad");
7385 return null;
7386 }
7387 cpr.launchingApp = proc;
7388 mLaunchingProviders.add(cpr);
7389 Binder.restoreCallingIdentity(origId);
7390 }
7391
7392 // Make sure the provider is published (the same provider class
7393 // may be published under multiple names).
7394 if (firstClass) {
7395 mProvidersByClass.put(cpi.name, cpr);
7396 }
7397 mProvidersByName.put(name, cpr);
7398
7399 if (r != null) {
7400 r.conProviders.add(cpr);
7401 cpr.clients.add(r);
7402 } else {
7403 cpr.externals++;
7404 }
7405 }
7406 }
7407
7408 // Wait for the provider to be published...
7409 synchronized (cpr) {
7410 while (cpr.provider == null) {
7411 if (cpr.launchingApp == null) {
7412 Log.w(TAG, "Unable to launch app "
7413 + cpi.applicationInfo.packageName + "/"
7414 + cpi.applicationInfo.uid + " for provider "
7415 + name + ": launching app became null");
7416 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7417 cpi.applicationInfo.packageName,
7418 cpi.applicationInfo.uid, name);
7419 return null;
7420 }
7421 try {
7422 cpr.wait();
7423 } catch (InterruptedException ex) {
7424 }
7425 }
7426 }
7427 return cpr;
7428 }
7429
7430 public final ContentProviderHolder getContentProvider(
7431 IApplicationThread caller, String name) {
7432 if (caller == null) {
7433 String msg = "null IApplicationThread when getting content provider "
7434 + name;
7435 Log.w(TAG, msg);
7436 throw new SecurityException(msg);
7437 }
7438
7439 return getContentProviderImpl(caller, name);
7440 }
7441
7442 private ContentProviderHolder getContentProviderExternal(String name) {
7443 return getContentProviderImpl(null, name);
7444 }
7445
7446 /**
7447 * Drop a content provider from a ProcessRecord's bookkeeping
7448 * @param cpr
7449 */
7450 public void removeContentProvider(IApplicationThread caller, String name) {
7451 synchronized (this) {
7452 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7453 if(cpr == null) {
7454 //remove from mProvidersByClass
7455 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7456 return;
7457 }
7458 final ProcessRecord r = getRecordForAppLocked(caller);
7459 if (r == null) {
7460 throw new SecurityException(
7461 "Unable to find app for caller " + caller +
7462 " when removing content provider " + name);
7463 }
7464 //update content provider record entry info
7465 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7466 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7467 r.info.processName+" from process "+localCpr.appInfo.processName);
7468 if(localCpr.appInfo.processName == r.info.processName) {
7469 //should not happen. taken care of as a local provider
7470 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7471 return;
7472 } else {
7473 localCpr.clients.remove(r);
7474 r.conProviders.remove(localCpr);
7475 }
7476 updateOomAdjLocked();
7477 }
7478 }
7479
7480 private void removeContentProviderExternal(String name) {
7481 synchronized (this) {
7482 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7483 if(cpr == null) {
7484 //remove from mProvidersByClass
7485 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7486 return;
7487 }
7488
7489 //update content provider record entry info
7490 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7491 localCpr.externals--;
7492 if (localCpr.externals < 0) {
7493 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7494 }
7495 updateOomAdjLocked();
7496 }
7497 }
7498
7499 public final void publishContentProviders(IApplicationThread caller,
7500 List<ContentProviderHolder> providers) {
7501 if (providers == null) {
7502 return;
7503 }
7504
7505 synchronized(this) {
7506 final ProcessRecord r = getRecordForAppLocked(caller);
7507 if (r == null) {
7508 throw new SecurityException(
7509 "Unable to find app for caller " + caller
7510 + " (pid=" + Binder.getCallingPid()
7511 + ") when publishing content providers");
7512 }
7513
7514 final long origId = Binder.clearCallingIdentity();
7515
7516 final int N = providers.size();
7517 for (int i=0; i<N; i++) {
7518 ContentProviderHolder src = providers.get(i);
7519 if (src == null || src.info == null || src.provider == null) {
7520 continue;
7521 }
7522 ContentProviderRecord dst =
7523 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7524 if (dst != null) {
7525 mProvidersByClass.put(dst.info.name, dst);
7526 String names[] = dst.info.authority.split(";");
7527 for (int j = 0; j < names.length; j++) {
7528 mProvidersByName.put(names[j], dst);
7529 }
7530
7531 int NL = mLaunchingProviders.size();
7532 int j;
7533 for (j=0; j<NL; j++) {
7534 if (mLaunchingProviders.get(j) == dst) {
7535 mLaunchingProviders.remove(j);
7536 j--;
7537 NL--;
7538 }
7539 }
7540 synchronized (dst) {
7541 dst.provider = src.provider;
7542 dst.app = r;
7543 dst.notifyAll();
7544 }
7545 updateOomAdjLocked(r);
7546 }
7547 }
7548
7549 Binder.restoreCallingIdentity(origId);
7550 }
7551 }
7552
7553 public static final void installSystemProviders() {
7554 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7555 List providers = mSelf.generateApplicationProvidersLocked(app);
7556 mSystemThread.installSystemProviders(providers);
7557 }
7558
7559 // =========================================================
7560 // GLOBAL MANAGEMENT
7561 // =========================================================
7562
7563 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7564 ApplicationInfo info, String customProcess) {
7565 String proc = customProcess != null ? customProcess : info.processName;
7566 BatteryStatsImpl.Uid.Proc ps = null;
7567 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7568 synchronized (stats) {
7569 ps = stats.getProcessStatsLocked(info.uid, proc);
7570 }
7571 return new ProcessRecord(ps, thread, info, proc);
7572 }
7573
7574 final ProcessRecord addAppLocked(ApplicationInfo info) {
7575 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7576
7577 if (app == null) {
7578 app = newProcessRecordLocked(null, info, null);
7579 mProcessNames.put(info.processName, info.uid, app);
7580 updateLRUListLocked(app, true);
7581 }
7582
7583 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7584 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7585 app.persistent = true;
7586 app.maxAdj = CORE_SERVER_ADJ;
7587 }
7588 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7589 mPersistentStartingProcesses.add(app);
7590 startProcessLocked(app, "added application", app.processName);
7591 }
7592
7593 return app;
7594 }
7595
7596 public void unhandledBack() {
7597 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7598 "unhandledBack()");
7599
7600 synchronized(this) {
7601 int count = mHistory.size();
7602 if (Config.LOGD) Log.d(
7603 TAG, "Performing unhandledBack(): stack size = " + count);
7604 if (count > 1) {
7605 final long origId = Binder.clearCallingIdentity();
7606 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7607 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7608 Binder.restoreCallingIdentity(origId);
7609 }
7610 }
7611 }
7612
7613 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7614 String name = uri.getAuthority();
7615 ContentProviderHolder cph = getContentProviderExternal(name);
7616 ParcelFileDescriptor pfd = null;
7617 if (cph != null) {
7618 // We record the binder invoker's uid in thread-local storage before
7619 // going to the content provider to open the file. Later, in the code
7620 // that handles all permissions checks, we look for this uid and use
7621 // that rather than the Activity Manager's own uid. The effect is that
7622 // we do the check against the caller's permissions even though it looks
7623 // to the content provider like the Activity Manager itself is making
7624 // the request.
7625 sCallerIdentity.set(new Identity(
7626 Binder.getCallingPid(), Binder.getCallingUid()));
7627 try {
7628 pfd = cph.provider.openFile(uri, "r");
7629 } catch (FileNotFoundException e) {
7630 // do nothing; pfd will be returned null
7631 } finally {
7632 // Ensure that whatever happens, we clean up the identity state
7633 sCallerIdentity.remove();
7634 }
7635
7636 // We've got the fd now, so we're done with the provider.
7637 removeContentProviderExternal(name);
7638 } else {
7639 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7640 }
7641 return pfd;
7642 }
7643
7644 public void goingToSleep() {
7645 synchronized(this) {
7646 mSleeping = true;
7647 mWindowManager.setEventDispatching(false);
7648
7649 if (mResumedActivity != null) {
7650 pauseIfSleepingLocked();
7651 } else {
7652 Log.w(TAG, "goingToSleep with no resumed activity!");
7653 }
7654 }
7655 }
7656
Dianne Hackborn55280a92009-05-07 15:53:46 -07007657 public boolean shutdown(int timeout) {
7658 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7659 != PackageManager.PERMISSION_GRANTED) {
7660 throw new SecurityException("Requires permission "
7661 + android.Manifest.permission.SHUTDOWN);
7662 }
7663
7664 boolean timedout = false;
7665
7666 synchronized(this) {
7667 mShuttingDown = true;
7668 mWindowManager.setEventDispatching(false);
7669
7670 if (mResumedActivity != null) {
7671 pauseIfSleepingLocked();
7672 final long endTime = System.currentTimeMillis() + timeout;
7673 while (mResumedActivity != null || mPausingActivity != null) {
7674 long delay = endTime - System.currentTimeMillis();
7675 if (delay <= 0) {
7676 Log.w(TAG, "Activity manager shutdown timed out");
7677 timedout = true;
7678 break;
7679 }
7680 try {
7681 this.wait();
7682 } catch (InterruptedException e) {
7683 }
7684 }
7685 }
7686 }
7687
7688 mUsageStatsService.shutdown();
7689 mBatteryStatsService.shutdown();
7690
7691 return timedout;
7692 }
7693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007694 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007695 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007696 if (!mGoingToSleep.isHeld()) {
7697 mGoingToSleep.acquire();
7698 if (mLaunchingActivity.isHeld()) {
7699 mLaunchingActivity.release();
7700 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7701 }
7702 }
7703
7704 // If we are not currently pausing an activity, get the current
7705 // one to pause. If we are pausing one, we will just let that stuff
7706 // run and release the wake lock when all done.
7707 if (mPausingActivity == null) {
7708 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7709 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7710 startPausingLocked(false, true);
7711 }
7712 }
7713 }
7714
7715 public void wakingUp() {
7716 synchronized(this) {
7717 if (mGoingToSleep.isHeld()) {
7718 mGoingToSleep.release();
7719 }
7720 mWindowManager.setEventDispatching(true);
7721 mSleeping = false;
7722 resumeTopActivityLocked(null);
7723 }
7724 }
7725
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007726 public void stopAppSwitches() {
7727 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7728 != PackageManager.PERMISSION_GRANTED) {
7729 throw new SecurityException("Requires permission "
7730 + android.Manifest.permission.STOP_APP_SWITCHES);
7731 }
7732
7733 synchronized(this) {
7734 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7735 + APP_SWITCH_DELAY_TIME;
7736 mDidAppSwitch = false;
7737 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7738 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7739 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7740 }
7741 }
7742
7743 public void resumeAppSwitches() {
7744 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7745 != PackageManager.PERMISSION_GRANTED) {
7746 throw new SecurityException("Requires permission "
7747 + android.Manifest.permission.STOP_APP_SWITCHES);
7748 }
7749
7750 synchronized(this) {
7751 // Note that we don't execute any pending app switches... we will
7752 // let those wait until either the timeout, or the next start
7753 // activity request.
7754 mAppSwitchesAllowedTime = 0;
7755 }
7756 }
7757
7758 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7759 String name) {
7760 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7761 return true;
7762 }
7763
7764 final int perm = checkComponentPermission(
7765 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7766 callingUid, -1);
7767 if (perm == PackageManager.PERMISSION_GRANTED) {
7768 return true;
7769 }
7770
7771 Log.w(TAG, name + " request from " + callingUid + " stopped");
7772 return false;
7773 }
7774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007775 public void setDebugApp(String packageName, boolean waitForDebugger,
7776 boolean persistent) {
7777 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7778 "setDebugApp()");
7779
7780 // Note that this is not really thread safe if there are multiple
7781 // callers into it at the same time, but that's not a situation we
7782 // care about.
7783 if (persistent) {
7784 final ContentResolver resolver = mContext.getContentResolver();
7785 Settings.System.putString(
7786 resolver, Settings.System.DEBUG_APP,
7787 packageName);
7788 Settings.System.putInt(
7789 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7790 waitForDebugger ? 1 : 0);
7791 }
7792
7793 synchronized (this) {
7794 if (!persistent) {
7795 mOrigDebugApp = mDebugApp;
7796 mOrigWaitForDebugger = mWaitForDebugger;
7797 }
7798 mDebugApp = packageName;
7799 mWaitForDebugger = waitForDebugger;
7800 mDebugTransient = !persistent;
7801 if (packageName != null) {
7802 final long origId = Binder.clearCallingIdentity();
7803 uninstallPackageLocked(packageName, -1, false);
7804 Binder.restoreCallingIdentity(origId);
7805 }
7806 }
7807 }
7808
7809 public void setAlwaysFinish(boolean enabled) {
7810 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7811 "setAlwaysFinish()");
7812
7813 Settings.System.putInt(
7814 mContext.getContentResolver(),
7815 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7816
7817 synchronized (this) {
7818 mAlwaysFinishActivities = enabled;
7819 }
7820 }
7821
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007822 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007823 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007824 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007825 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007826 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007827 }
7828 }
7829
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007830 public void registerActivityWatcher(IActivityWatcher watcher) {
7831 mWatchers.register(watcher);
7832 }
7833
7834 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7835 mWatchers.unregister(watcher);
7836 }
7837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007838 public final void enterSafeMode() {
7839 synchronized(this) {
7840 // It only makes sense to do this before the system is ready
7841 // and started launching other packages.
7842 if (!mSystemReady) {
7843 try {
7844 ActivityThread.getPackageManager().enterSafeMode();
7845 } catch (RemoteException e) {
7846 }
7847
7848 View v = LayoutInflater.from(mContext).inflate(
7849 com.android.internal.R.layout.safe_mode, null);
7850 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7851 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7852 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7853 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7854 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7855 lp.format = v.getBackground().getOpacity();
7856 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7857 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7858 ((WindowManager)mContext.getSystemService(
7859 Context.WINDOW_SERVICE)).addView(v, lp);
7860 }
7861 }
7862 }
7863
7864 public void noteWakeupAlarm(IIntentSender sender) {
7865 if (!(sender instanceof PendingIntentRecord)) {
7866 return;
7867 }
7868 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7869 synchronized (stats) {
7870 if (mBatteryStatsService.isOnBattery()) {
7871 mBatteryStatsService.enforceCallingPermission();
7872 PendingIntentRecord rec = (PendingIntentRecord)sender;
7873 int MY_UID = Binder.getCallingUid();
7874 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7875 BatteryStatsImpl.Uid.Pkg pkg =
7876 stats.getPackageStatsLocked(uid, rec.key.packageName);
7877 pkg.incWakeupsLocked();
7878 }
7879 }
7880 }
7881
7882 public boolean killPidsForMemory(int[] pids) {
7883 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7884 throw new SecurityException("killPidsForMemory only available to the system");
7885 }
7886
7887 // XXX Note: don't acquire main activity lock here, because the window
7888 // manager calls in with its locks held.
7889
7890 boolean killed = false;
7891 synchronized (mPidsSelfLocked) {
7892 int[] types = new int[pids.length];
7893 int worstType = 0;
7894 for (int i=0; i<pids.length; i++) {
7895 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7896 if (proc != null) {
7897 int type = proc.setAdj;
7898 types[i] = type;
7899 if (type > worstType) {
7900 worstType = type;
7901 }
7902 }
7903 }
7904
7905 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7906 // then constrain it so we will kill all hidden procs.
7907 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7908 worstType = HIDDEN_APP_MIN_ADJ;
7909 }
7910 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7911 for (int i=0; i<pids.length; i++) {
7912 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7913 if (proc == null) {
7914 continue;
7915 }
7916 int adj = proc.setAdj;
7917 if (adj >= worstType) {
7918 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7919 + adj + ")");
7920 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7921 proc.processName, adj);
7922 killed = true;
7923 Process.killProcess(pids[i]);
7924 }
7925 }
7926 }
7927 return killed;
7928 }
7929
7930 public void reportPss(IApplicationThread caller, int pss) {
7931 Watchdog.PssRequestor req;
7932 String name;
7933 ProcessRecord callerApp;
7934 synchronized (this) {
7935 if (caller == null) {
7936 return;
7937 }
7938 callerApp = getRecordForAppLocked(caller);
7939 if (callerApp == null) {
7940 return;
7941 }
7942 callerApp.lastPss = pss;
7943 req = callerApp;
7944 name = callerApp.processName;
7945 }
7946 Watchdog.getInstance().reportPss(req, name, pss);
7947 if (!callerApp.persistent) {
7948 removeRequestedPss(callerApp);
7949 }
7950 }
7951
7952 public void requestPss(Runnable completeCallback) {
7953 ArrayList<ProcessRecord> procs;
7954 synchronized (this) {
7955 mRequestPssCallback = completeCallback;
7956 mRequestPssList.clear();
7957 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7958 ProcessRecord proc = mLRUProcesses.get(i);
7959 if (!proc.persistent) {
7960 mRequestPssList.add(proc);
7961 }
7962 }
7963 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7964 }
7965
7966 int oldPri = Process.getThreadPriority(Process.myTid());
7967 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7968 for (int i=procs.size()-1; i>=0; i--) {
7969 ProcessRecord proc = procs.get(i);
7970 proc.lastPss = 0;
7971 proc.requestPss();
7972 }
7973 Process.setThreadPriority(oldPri);
7974 }
7975
7976 void removeRequestedPss(ProcessRecord proc) {
7977 Runnable callback = null;
7978 synchronized (this) {
7979 if (mRequestPssList.remove(proc)) {
7980 if (mRequestPssList.size() == 0) {
7981 callback = mRequestPssCallback;
7982 mRequestPssCallback = null;
7983 }
7984 }
7985 }
7986
7987 if (callback != null) {
7988 callback.run();
7989 }
7990 }
7991
7992 public void collectPss(Watchdog.PssStats stats) {
7993 stats.mEmptyPss = 0;
7994 stats.mEmptyCount = 0;
7995 stats.mBackgroundPss = 0;
7996 stats.mBackgroundCount = 0;
7997 stats.mServicePss = 0;
7998 stats.mServiceCount = 0;
7999 stats.mVisiblePss = 0;
8000 stats.mVisibleCount = 0;
8001 stats.mForegroundPss = 0;
8002 stats.mForegroundCount = 0;
8003 stats.mNoPssCount = 0;
8004 synchronized (this) {
8005 int i;
8006 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8007 ? mProcDeaths.length : stats.mProcDeaths.length;
8008 int aggr = 0;
8009 for (i=0; i<NPD; i++) {
8010 aggr += mProcDeaths[i];
8011 stats.mProcDeaths[i] = aggr;
8012 }
8013 while (i<stats.mProcDeaths.length) {
8014 stats.mProcDeaths[i] = 0;
8015 i++;
8016 }
8017
8018 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8019 ProcessRecord proc = mLRUProcesses.get(i);
8020 if (proc.persistent) {
8021 continue;
8022 }
8023 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8024 if (proc.lastPss == 0) {
8025 stats.mNoPssCount++;
8026 continue;
8027 }
8028 if (proc.setAdj == EMPTY_APP_ADJ) {
8029 stats.mEmptyPss += proc.lastPss;
8030 stats.mEmptyCount++;
8031 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8032 stats.mEmptyPss += proc.lastPss;
8033 stats.mEmptyCount++;
8034 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8035 stats.mBackgroundPss += proc.lastPss;
8036 stats.mBackgroundCount++;
8037 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8038 stats.mVisiblePss += proc.lastPss;
8039 stats.mVisibleCount++;
8040 } else {
8041 stats.mForegroundPss += proc.lastPss;
8042 stats.mForegroundCount++;
8043 }
8044 }
8045 }
8046 }
8047
8048 public final void startRunning(String pkg, String cls, String action,
8049 String data) {
8050 synchronized(this) {
8051 if (mStartRunning) {
8052 return;
8053 }
8054 mStartRunning = true;
8055 mTopComponent = pkg != null && cls != null
8056 ? new ComponentName(pkg, cls) : null;
8057 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8058 mTopData = data;
8059 if (!mSystemReady) {
8060 return;
8061 }
8062 }
8063
8064 systemReady();
8065 }
8066
8067 private void retrieveSettings() {
8068 final ContentResolver resolver = mContext.getContentResolver();
8069 String debugApp = Settings.System.getString(
8070 resolver, Settings.System.DEBUG_APP);
8071 boolean waitForDebugger = Settings.System.getInt(
8072 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8073 boolean alwaysFinishActivities = Settings.System.getInt(
8074 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8075
8076 Configuration configuration = new Configuration();
8077 Settings.System.getConfiguration(resolver, configuration);
8078
8079 synchronized (this) {
8080 mDebugApp = mOrigDebugApp = debugApp;
8081 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8082 mAlwaysFinishActivities = alwaysFinishActivities;
8083 // This happens before any activities are started, so we can
8084 // change mConfiguration in-place.
8085 mConfiguration.updateFrom(configuration);
8086 }
8087 }
8088
8089 public boolean testIsSystemReady() {
8090 // no need to synchronize(this) just to read & return the value
8091 return mSystemReady;
8092 }
8093
8094 public void systemReady() {
8095 // In the simulator, startRunning will never have been called, which
8096 // normally sets a few crucial variables. Do it here instead.
8097 if (!Process.supportsProcesses()) {
8098 mStartRunning = true;
8099 mTopAction = Intent.ACTION_MAIN;
8100 }
8101
8102 synchronized(this) {
8103 if (mSystemReady) {
8104 return;
8105 }
8106 mSystemReady = true;
8107 if (!mStartRunning) {
8108 return;
8109 }
8110 }
8111
8112 if (Config.LOGD) Log.d(TAG, "Start running!");
8113 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8114 SystemClock.uptimeMillis());
8115
8116 synchronized(this) {
8117 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8118 ResolveInfo ri = mContext.getPackageManager()
8119 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008120 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008121 CharSequence errorMsg = null;
8122 if (ri != null) {
8123 ActivityInfo ai = ri.activityInfo;
8124 ApplicationInfo app = ai.applicationInfo;
8125 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8126 mTopAction = Intent.ACTION_FACTORY_TEST;
8127 mTopData = null;
8128 mTopComponent = new ComponentName(app.packageName,
8129 ai.name);
8130 } else {
8131 errorMsg = mContext.getResources().getText(
8132 com.android.internal.R.string.factorytest_not_system);
8133 }
8134 } else {
8135 errorMsg = mContext.getResources().getText(
8136 com.android.internal.R.string.factorytest_no_action);
8137 }
8138 if (errorMsg != null) {
8139 mTopAction = null;
8140 mTopData = null;
8141 mTopComponent = null;
8142 Message msg = Message.obtain();
8143 msg.what = SHOW_FACTORY_ERROR_MSG;
8144 msg.getData().putCharSequence("msg", errorMsg);
8145 mHandler.sendMessage(msg);
8146 }
8147 }
8148 }
8149
8150 retrieveSettings();
8151
8152 synchronized (this) {
8153 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8154 try {
8155 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008156 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008157 if (apps != null) {
8158 int N = apps.size();
8159 int i;
8160 for (i=0; i<N; i++) {
8161 ApplicationInfo info
8162 = (ApplicationInfo)apps.get(i);
8163 if (info != null &&
8164 !info.packageName.equals("android")) {
8165 addAppLocked(info);
8166 }
8167 }
8168 }
8169 } catch (RemoteException ex) {
8170 // pm is in same process, this will never happen.
8171 }
8172 }
8173
8174 try {
8175 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8176 Message msg = Message.obtain();
8177 msg.what = SHOW_UID_ERROR_MSG;
8178 mHandler.sendMessage(msg);
8179 }
8180 } catch (RemoteException e) {
8181 }
8182
8183 // Start up initial activity.
8184 mBooting = true;
8185 resumeTopActivityLocked(null);
8186 }
8187 }
8188
8189 boolean makeAppCrashingLocked(ProcessRecord app,
8190 String tag, String shortMsg, String longMsg, byte[] crashData) {
8191 app.crashing = true;
8192 app.crashingReport = generateProcessError(app,
8193 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8194 startAppProblemLocked(app);
8195 app.stopFreezingAllLocked();
8196 return handleAppCrashLocked(app);
8197 }
8198
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008199 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8200 IPackageManager pm = ActivityThread.getPackageManager();
8201 try {
8202 // was an installer package name specified when this app was
8203 // installed?
8204 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8205 if (installerPackageName == null) {
8206 return null;
8207 }
8208
8209 // is there an Activity in this package that handles ACTION_APP_ERROR?
8210 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008211 intent.setPackage(installerPackageName);
8212 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008213 if (info == null || info.activityInfo == null) {
8214 return null;
8215 }
8216
8217 return new ComponentName(installerPackageName, info.activityInfo.name);
8218 } catch (RemoteException e) {
8219 // will return null and no error report will be delivered
8220 }
8221 return null;
8222 }
8223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008224 void makeAppNotRespondingLocked(ProcessRecord app,
8225 String tag, String shortMsg, String longMsg, byte[] crashData) {
8226 app.notResponding = true;
8227 app.notRespondingReport = generateProcessError(app,
8228 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8229 crashData);
8230 startAppProblemLocked(app);
8231 app.stopFreezingAllLocked();
8232 }
8233
8234 /**
8235 * Generate a process error record, suitable for attachment to a ProcessRecord.
8236 *
8237 * @param app The ProcessRecord in which the error occurred.
8238 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8239 * ActivityManager.AppErrorStateInfo
8240 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8241 * @param shortMsg Short message describing the crash.
8242 * @param longMsg Long message describing the crash.
8243 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8244 *
8245 * @return Returns a fully-formed AppErrorStateInfo record.
8246 */
8247 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8248 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8249 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8250
8251 report.condition = condition;
8252 report.processName = app.processName;
8253 report.pid = app.pid;
8254 report.uid = app.info.uid;
8255 report.tag = tag;
8256 report.shortMsg = shortMsg;
8257 report.longMsg = longMsg;
8258 report.crashData = crashData;
8259
8260 return report;
8261 }
8262
8263 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8264 boolean crashed) {
8265 synchronized (this) {
8266 app.crashing = false;
8267 app.crashingReport = null;
8268 app.notResponding = false;
8269 app.notRespondingReport = null;
8270 if (app.anrDialog == fromDialog) {
8271 app.anrDialog = null;
8272 }
8273 if (app.waitDialog == fromDialog) {
8274 app.waitDialog = null;
8275 }
8276 if (app.pid > 0 && app.pid != MY_PID) {
8277 if (crashed) {
8278 handleAppCrashLocked(app);
8279 }
8280 Log.i(ActivityManagerService.TAG, "Killing process "
8281 + app.processName
8282 + " (pid=" + app.pid + ") at user's request");
8283 Process.killProcess(app.pid);
8284 }
8285
8286 }
8287 }
8288
8289 boolean handleAppCrashLocked(ProcessRecord app) {
8290 long now = SystemClock.uptimeMillis();
8291
8292 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8293 app.info.uid);
8294 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8295 // This process loses!
8296 Log.w(TAG, "Process " + app.info.processName
8297 + " has crashed too many times: killing!");
8298 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8299 app.info.processName, app.info.uid);
8300 killServicesLocked(app, false);
8301 for (int i=mHistory.size()-1; i>=0; i--) {
8302 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8303 if (r.app == app) {
8304 if (Config.LOGD) Log.d(
8305 TAG, " Force finishing activity "
8306 + r.intent.getComponent().flattenToShortString());
8307 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8308 }
8309 }
8310 if (!app.persistent) {
8311 // We don't want to start this process again until the user
8312 // explicitly does so... but for persistent process, we really
8313 // need to keep it running. If a persistent process is actually
8314 // repeatedly crashing, then badness for everyone.
8315 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8316 app.info.processName);
8317 mBadProcesses.put(app.info.processName, app.info.uid, now);
8318 app.bad = true;
8319 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8320 app.removed = true;
8321 removeProcessLocked(app, false);
8322 return false;
8323 }
8324 }
8325
8326 // Bump up the crash count of any services currently running in the proc.
8327 if (app.services.size() != 0) {
8328 // Any services running in the application need to be placed
8329 // back in the pending list.
8330 Iterator it = app.services.iterator();
8331 while (it.hasNext()) {
8332 ServiceRecord sr = (ServiceRecord)it.next();
8333 sr.crashCount++;
8334 }
8335 }
8336
8337 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8338 return true;
8339 }
8340
8341 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008342 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008343 skipCurrentReceiverLocked(app);
8344 }
8345
8346 void skipCurrentReceiverLocked(ProcessRecord app) {
8347 boolean reschedule = false;
8348 BroadcastRecord r = app.curReceiver;
8349 if (r != null) {
8350 // The current broadcast is waiting for this app's receiver
8351 // to be finished. Looks like that's not going to happen, so
8352 // let the broadcast continue.
8353 logBroadcastReceiverDiscard(r);
8354 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8355 r.resultExtras, r.resultAbort, true);
8356 reschedule = true;
8357 }
8358 r = mPendingBroadcast;
8359 if (r != null && r.curApp == app) {
8360 if (DEBUG_BROADCAST) Log.v(TAG,
8361 "skip & discard pending app " + r);
8362 logBroadcastReceiverDiscard(r);
8363 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8364 r.resultExtras, r.resultAbort, true);
8365 reschedule = true;
8366 }
8367 if (reschedule) {
8368 scheduleBroadcastsLocked();
8369 }
8370 }
8371
8372 public int handleApplicationError(IBinder app, int flags,
8373 String tag, String shortMsg, String longMsg, byte[] crashData) {
8374 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008375 ProcessRecord r = null;
8376 synchronized (this) {
8377 if (app != null) {
8378 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8379 final int NA = apps.size();
8380 for (int ia=0; ia<NA; ia++) {
8381 ProcessRecord p = apps.valueAt(ia);
8382 if (p.thread != null && p.thread.asBinder() == app) {
8383 r = p;
8384 break;
8385 }
8386 }
8387 }
8388 }
8389
8390 if (r != null) {
8391 // The application has crashed. Send the SIGQUIT to the process so
8392 // that it can dump its state.
8393 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8394 //Log.i(TAG, "Current system threads:");
8395 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8396 }
8397
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008398 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008399 try {
8400 String name = r != null ? r.processName : null;
8401 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008402 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008403 shortMsg, longMsg, crashData)) {
8404 Log.w(TAG, "Force-killing crashed app " + name
8405 + " at watcher's request");
8406 Process.killProcess(pid);
8407 return 0;
8408 }
8409 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008410 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008411 }
8412 }
8413
8414 final long origId = Binder.clearCallingIdentity();
8415
8416 // If this process is running instrumentation, finish it.
8417 if (r != null && r.instrumentationClass != null) {
8418 Log.w(TAG, "Error in app " + r.processName
8419 + " running instrumentation " + r.instrumentationClass + ":");
8420 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8421 if (longMsg != null) Log.w(TAG, " " + longMsg);
8422 Bundle info = new Bundle();
8423 info.putString("shortMsg", shortMsg);
8424 info.putString("longMsg", longMsg);
8425 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8426 Binder.restoreCallingIdentity(origId);
8427 return 0;
8428 }
8429
8430 if (r != null) {
8431 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8432 return 0;
8433 }
8434 } else {
8435 Log.w(TAG, "Some application object " + app + " tag " + tag
8436 + " has crashed, but I don't know who it is.");
8437 Log.w(TAG, "ShortMsg:" + shortMsg);
8438 Log.w(TAG, "LongMsg:" + longMsg);
8439 Binder.restoreCallingIdentity(origId);
8440 return 0;
8441 }
8442
8443 Message msg = Message.obtain();
8444 msg.what = SHOW_ERROR_MSG;
8445 HashMap data = new HashMap();
8446 data.put("result", result);
8447 data.put("app", r);
8448 data.put("flags", flags);
8449 data.put("shortMsg", shortMsg);
8450 data.put("longMsg", longMsg);
8451 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8452 // For system processes, submit crash data to the server.
8453 data.put("crashData", crashData);
8454 }
8455 msg.obj = data;
8456 mHandler.sendMessage(msg);
8457
8458 Binder.restoreCallingIdentity(origId);
8459 }
8460
8461 int res = result.get();
8462
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008463 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008464 synchronized (this) {
8465 if (r != null) {
8466 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8467 SystemClock.uptimeMillis());
8468 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008469 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8470 appErrorIntent = createAppErrorIntentLocked(r);
8471 res = AppErrorDialog.FORCE_QUIT;
8472 }
8473 }
8474
8475 if (appErrorIntent != null) {
8476 try {
8477 mContext.startActivity(appErrorIntent);
8478 } catch (ActivityNotFoundException e) {
8479 Log.w(TAG, "bug report receiver dissappeared", e);
8480 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008481 }
8482
8483 return res;
8484 }
8485
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008486 Intent createAppErrorIntentLocked(ProcessRecord r) {
8487 ApplicationErrorReport report = createAppErrorReportLocked(r);
8488 if (report == null) {
8489 return null;
8490 }
8491 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8492 result.setComponent(r.errorReportReceiver);
8493 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8494 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8495 return result;
8496 }
8497
8498 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8499 if (r.errorReportReceiver == null) {
8500 return null;
8501 }
8502
8503 if (!r.crashing && !r.notResponding) {
8504 return null;
8505 }
8506
8507 try {
8508 ApplicationErrorReport report = new ApplicationErrorReport();
8509 report.packageName = r.info.packageName;
8510 report.installerPackageName = r.errorReportReceiver.getPackageName();
8511 report.processName = r.processName;
8512
8513 if (r.crashing) {
8514 report.type = ApplicationErrorReport.TYPE_CRASH;
8515 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8516
8517 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8518 r.crashingReport.crashData);
8519 DataInputStream dataStream = new DataInputStream(byteStream);
8520 CrashData crashData = new CrashData(dataStream);
8521 ThrowableData throwData = crashData.getThrowableData();
8522
8523 report.time = crashData.getTime();
8524 report.crashInfo.stackTrace = throwData.toString();
8525
Jacek Surazskif829a782009-06-11 22:47:02 +02008526 // Extract the source of the exception, useful for report
8527 // clustering. Also extract the "deepest" non-null exception
8528 // message.
8529 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008530 while (throwData.getCause() != null) {
8531 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008532 String msg = throwData.getMessage();
8533 if (msg != null && msg.length() > 0) {
8534 exceptionMessage = msg;
8535 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008536 }
8537 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008538 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008539 report.crashInfo.exceptionClassName = throwData.getType();
8540 report.crashInfo.throwFileName = trace.getFileName();
8541 report.crashInfo.throwClassName = trace.getClassName();
8542 report.crashInfo.throwMethodName = trace.getMethodName();
8543 } else if (r.notResponding) {
8544 report.type = ApplicationErrorReport.TYPE_ANR;
8545 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8546
8547 report.anrInfo.activity = r.notRespondingReport.tag;
8548 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8549 report.anrInfo.info = r.notRespondingReport.longMsg;
8550 }
8551
8552 return report;
8553 } catch (IOException e) {
8554 // we don't send it
8555 }
8556
8557 return null;
8558 }
8559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008560 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8561 // assume our apps are happy - lazy create the list
8562 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8563
8564 synchronized (this) {
8565
8566 // iterate across all processes
8567 final int N = mLRUProcesses.size();
8568 for (int i = 0; i < N; i++) {
8569 ProcessRecord app = mLRUProcesses.get(i);
8570 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8571 // This one's in trouble, so we'll generate a report for it
8572 // crashes are higher priority (in case there's a crash *and* an anr)
8573 ActivityManager.ProcessErrorStateInfo report = null;
8574 if (app.crashing) {
8575 report = app.crashingReport;
8576 } else if (app.notResponding) {
8577 report = app.notRespondingReport;
8578 }
8579
8580 if (report != null) {
8581 if (errList == null) {
8582 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8583 }
8584 errList.add(report);
8585 } else {
8586 Log.w(TAG, "Missing app error report, app = " + app.processName +
8587 " crashing = " + app.crashing +
8588 " notResponding = " + app.notResponding);
8589 }
8590 }
8591 }
8592 }
8593
8594 return errList;
8595 }
8596
8597 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8598 // Lazy instantiation of list
8599 List<ActivityManager.RunningAppProcessInfo> runList = null;
8600 synchronized (this) {
8601 // Iterate across all processes
8602 final int N = mLRUProcesses.size();
8603 for (int i = 0; i < N; i++) {
8604 ProcessRecord app = mLRUProcesses.get(i);
8605 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8606 // Generate process state info for running application
8607 ActivityManager.RunningAppProcessInfo currApp =
8608 new ActivityManager.RunningAppProcessInfo(app.processName,
8609 app.pid, app.getPackageList());
8610 int adj = app.curAdj;
8611 if (adj >= CONTENT_PROVIDER_ADJ) {
8612 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8613 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8614 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008615 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8616 } else if (adj >= HOME_APP_ADJ) {
8617 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8618 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008619 } else if (adj >= SECONDARY_SERVER_ADJ) {
8620 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8621 } else if (adj >= VISIBLE_APP_ADJ) {
8622 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8623 } else {
8624 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8625 }
8626 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8627 // + " lru=" + currApp.lru);
8628 if (runList == null) {
8629 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8630 }
8631 runList.add(currApp);
8632 }
8633 }
8634 }
8635 return runList;
8636 }
8637
8638 @Override
8639 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8640 synchronized (this) {
8641 if (checkCallingPermission(android.Manifest.permission.DUMP)
8642 != PackageManager.PERMISSION_GRANTED) {
8643 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8644 + Binder.getCallingPid()
8645 + ", uid=" + Binder.getCallingUid()
8646 + " without permission "
8647 + android.Manifest.permission.DUMP);
8648 return;
8649 }
8650 if (args.length != 0 && "service".equals(args[0])) {
8651 dumpService(fd, pw, args);
8652 return;
8653 }
8654 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008655 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008656 pw.println(" ");
8657 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008658 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008659 if (mWaitingVisibleActivities.size() > 0) {
8660 pw.println(" ");
8661 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008662 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008663 }
8664 if (mStoppingActivities.size() > 0) {
8665 pw.println(" ");
8666 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008667 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008668 }
8669 if (mFinishingActivities.size() > 0) {
8670 pw.println(" ");
8671 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008672 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008673 }
8674
8675 pw.println(" ");
8676 pw.println(" mPausingActivity: " + mPausingActivity);
8677 pw.println(" mResumedActivity: " + mResumedActivity);
8678 pw.println(" mFocusedActivity: " + mFocusedActivity);
8679 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8680
8681 if (mRecentTasks.size() > 0) {
8682 pw.println(" ");
8683 pw.println("Recent tasks in Current Activity Manager State:");
8684
8685 final int N = mRecentTasks.size();
8686 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008687 TaskRecord tr = mRecentTasks.get(i);
8688 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8689 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008690 mRecentTasks.get(i).dump(pw, " ");
8691 }
8692 }
8693
8694 pw.println(" ");
8695 pw.println(" mCurTask: " + mCurTask);
8696
8697 pw.println(" ");
8698 pw.println("Processes in Current Activity Manager State:");
8699
8700 boolean needSep = false;
8701 int numPers = 0;
8702
8703 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8704 final int NA = procs.size();
8705 for (int ia=0; ia<NA; ia++) {
8706 if (!needSep) {
8707 pw.println(" All known processes:");
8708 needSep = true;
8709 }
8710 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008711 pw.print(r.persistent ? " *PERS*" : " *APP*");
8712 pw.print(" UID "); pw.print(procs.keyAt(ia));
8713 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008714 r.dump(pw, " ");
8715 if (r.persistent) {
8716 numPers++;
8717 }
8718 }
8719 }
8720
8721 if (mLRUProcesses.size() > 0) {
8722 if (needSep) pw.println(" ");
8723 needSep = true;
8724 pw.println(" Running processes (most recent first):");
8725 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008726 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008727 needSep = true;
8728 }
8729
8730 synchronized (mPidsSelfLocked) {
8731 if (mPidsSelfLocked.size() > 0) {
8732 if (needSep) pw.println(" ");
8733 needSep = true;
8734 pw.println(" PID mappings:");
8735 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008736 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8737 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008738 }
8739 }
8740 }
8741
8742 if (mForegroundProcesses.size() > 0) {
8743 if (needSep) pw.println(" ");
8744 needSep = true;
8745 pw.println(" Foreground Processes:");
8746 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008747 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8748 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008749 }
8750 }
8751
8752 if (mPersistentStartingProcesses.size() > 0) {
8753 if (needSep) pw.println(" ");
8754 needSep = true;
8755 pw.println(" Persisent processes that are starting:");
8756 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008757 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008758 }
8759
8760 if (mStartingProcesses.size() > 0) {
8761 if (needSep) pw.println(" ");
8762 needSep = true;
8763 pw.println(" Processes that are starting:");
8764 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008765 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008766 }
8767
8768 if (mRemovedProcesses.size() > 0) {
8769 if (needSep) pw.println(" ");
8770 needSep = true;
8771 pw.println(" Processes that are being removed:");
8772 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008773 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008774 }
8775
8776 if (mProcessesOnHold.size() > 0) {
8777 if (needSep) pw.println(" ");
8778 needSep = true;
8779 pw.println(" Processes that are on old until the system is ready:");
8780 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008781 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008782 }
8783
8784 if (mProcessCrashTimes.getMap().size() > 0) {
8785 if (needSep) pw.println(" ");
8786 needSep = true;
8787 pw.println(" Time since processes crashed:");
8788 long now = SystemClock.uptimeMillis();
8789 for (Map.Entry<String, SparseArray<Long>> procs
8790 : mProcessCrashTimes.getMap().entrySet()) {
8791 SparseArray<Long> uids = procs.getValue();
8792 final int N = uids.size();
8793 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008794 pw.print(" Process "); pw.print(procs.getKey());
8795 pw.print(" uid "); pw.print(uids.keyAt(i));
8796 pw.print(": last crashed ");
8797 pw.print((now-uids.valueAt(i)));
8798 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008799 }
8800 }
8801 }
8802
8803 if (mBadProcesses.getMap().size() > 0) {
8804 if (needSep) pw.println(" ");
8805 needSep = true;
8806 pw.println(" Bad processes:");
8807 for (Map.Entry<String, SparseArray<Long>> procs
8808 : mBadProcesses.getMap().entrySet()) {
8809 SparseArray<Long> uids = procs.getValue();
8810 final int N = uids.size();
8811 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008812 pw.print(" Bad process "); pw.print(procs.getKey());
8813 pw.print(" uid "); pw.print(uids.keyAt(i));
8814 pw.print(": crashed at time ");
8815 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008816 }
8817 }
8818 }
8819
8820 pw.println(" ");
8821 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008822 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008823 pw.println(" mConfiguration: " + mConfiguration);
8824 pw.println(" mStartRunning=" + mStartRunning
8825 + " mSystemReady=" + mSystemReady
8826 + " mBooting=" + mBooting
8827 + " mBooted=" + mBooted
8828 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008829 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008830 pw.println(" mGoingToSleep=" + mGoingToSleep);
8831 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8832 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8833 + " mDebugTransient=" + mDebugTransient
8834 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8835 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008836 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008837 }
8838 }
8839
8840 /**
8841 * There are three ways to call this:
8842 * - no service specified: dump all the services
8843 * - a flattened component name that matched an existing service was specified as the
8844 * first arg: dump that one service
8845 * - the first arg isn't the flattened component name of an existing service:
8846 * dump all services whose component contains the first arg as a substring
8847 */
8848 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8849 String[] newArgs;
8850 String componentNameString;
8851 ServiceRecord r;
8852 if (args.length == 1) {
8853 componentNameString = null;
8854 newArgs = EMPTY_STRING_ARRAY;
8855 r = null;
8856 } else {
8857 componentNameString = args[1];
8858 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8859 r = componentName != null ? mServices.get(componentName) : null;
8860 newArgs = new String[args.length - 2];
8861 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8862 }
8863
8864 if (r != null) {
8865 dumpService(fd, pw, r, newArgs);
8866 } else {
8867 for (ServiceRecord r1 : mServices.values()) {
8868 if (componentNameString == null
8869 || r1.name.flattenToString().contains(componentNameString)) {
8870 dumpService(fd, pw, r1, newArgs);
8871 }
8872 }
8873 }
8874 }
8875
8876 /**
8877 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8878 * there is a thread associated with the service.
8879 */
8880 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8881 pw.println(" Service " + r.name.flattenToString());
8882 if (r.app != null && r.app.thread != null) {
8883 try {
8884 // flush anything that is already in the PrintWriter since the thread is going
8885 // to write to the file descriptor directly
8886 pw.flush();
8887 r.app.thread.dumpService(fd, r, args);
8888 pw.print("\n");
8889 } catch (RemoteException e) {
8890 pw.println("got a RemoteException while dumping the service");
8891 }
8892 }
8893 }
8894
8895 void dumpBroadcasts(PrintWriter pw) {
8896 synchronized (this) {
8897 if (checkCallingPermission(android.Manifest.permission.DUMP)
8898 != PackageManager.PERMISSION_GRANTED) {
8899 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8900 + Binder.getCallingPid()
8901 + ", uid=" + Binder.getCallingUid()
8902 + " without permission "
8903 + android.Manifest.permission.DUMP);
8904 return;
8905 }
8906 pw.println("Broadcasts in Current Activity Manager State:");
8907
8908 if (mRegisteredReceivers.size() > 0) {
8909 pw.println(" ");
8910 pw.println(" Registered Receivers:");
8911 Iterator it = mRegisteredReceivers.values().iterator();
8912 while (it.hasNext()) {
8913 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008914 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008915 r.dump(pw, " ");
8916 }
8917 }
8918
8919 pw.println(" ");
8920 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008921 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008922
8923 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8924 || mPendingBroadcast != null) {
8925 if (mParallelBroadcasts.size() > 0) {
8926 pw.println(" ");
8927 pw.println(" Active broadcasts:");
8928 }
8929 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8930 pw.println(" Broadcast #" + i + ":");
8931 mParallelBroadcasts.get(i).dump(pw, " ");
8932 }
8933 if (mOrderedBroadcasts.size() > 0) {
8934 pw.println(" ");
8935 pw.println(" Active serialized broadcasts:");
8936 }
8937 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8938 pw.println(" Serialized Broadcast #" + i + ":");
8939 mOrderedBroadcasts.get(i).dump(pw, " ");
8940 }
8941 pw.println(" ");
8942 pw.println(" Pending broadcast:");
8943 if (mPendingBroadcast != null) {
8944 mPendingBroadcast.dump(pw, " ");
8945 } else {
8946 pw.println(" (null)");
8947 }
8948 }
8949
8950 pw.println(" ");
8951 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8952 if (mStickyBroadcasts != null) {
8953 pw.println(" ");
8954 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008955 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008956 for (Map.Entry<String, ArrayList<Intent>> ent
8957 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008958 pw.print(" * Sticky action "); pw.print(ent.getKey());
8959 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008960 ArrayList<Intent> intents = ent.getValue();
8961 final int N = intents.size();
8962 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008963 sb.setLength(0);
8964 sb.append(" Intent: ");
8965 intents.get(i).toShortString(sb, true, false);
8966 pw.println(sb.toString());
8967 Bundle bundle = intents.get(i).getExtras();
8968 if (bundle != null) {
8969 pw.print(" ");
8970 pw.println(bundle.toString());
8971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 }
8973 }
8974 }
8975
8976 pw.println(" ");
8977 pw.println(" mHandler:");
8978 mHandler.dump(new PrintWriterPrinter(pw), " ");
8979 }
8980 }
8981
8982 void dumpServices(PrintWriter pw) {
8983 synchronized (this) {
8984 if (checkCallingPermission(android.Manifest.permission.DUMP)
8985 != PackageManager.PERMISSION_GRANTED) {
8986 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8987 + Binder.getCallingPid()
8988 + ", uid=" + Binder.getCallingUid()
8989 + " without permission "
8990 + android.Manifest.permission.DUMP);
8991 return;
8992 }
8993 pw.println("Services in Current Activity Manager State:");
8994
8995 boolean needSep = false;
8996
8997 if (mServices.size() > 0) {
8998 pw.println(" Active services:");
8999 Iterator<ServiceRecord> it = mServices.values().iterator();
9000 while (it.hasNext()) {
9001 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009002 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009003 r.dump(pw, " ");
9004 }
9005 needSep = true;
9006 }
9007
9008 if (mPendingServices.size() > 0) {
9009 if (needSep) pw.println(" ");
9010 pw.println(" Pending services:");
9011 for (int i=0; i<mPendingServices.size(); i++) {
9012 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009013 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009014 r.dump(pw, " ");
9015 }
9016 needSep = true;
9017 }
9018
9019 if (mRestartingServices.size() > 0) {
9020 if (needSep) pw.println(" ");
9021 pw.println(" Restarting services:");
9022 for (int i=0; i<mRestartingServices.size(); i++) {
9023 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009024 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009025 r.dump(pw, " ");
9026 }
9027 needSep = true;
9028 }
9029
9030 if (mStoppingServices.size() > 0) {
9031 if (needSep) pw.println(" ");
9032 pw.println(" Stopping services:");
9033 for (int i=0; i<mStoppingServices.size(); i++) {
9034 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009035 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036 r.dump(pw, " ");
9037 }
9038 needSep = true;
9039 }
9040
9041 if (mServiceConnections.size() > 0) {
9042 if (needSep) pw.println(" ");
9043 pw.println(" Connection bindings to services:");
9044 Iterator<ConnectionRecord> it
9045 = mServiceConnections.values().iterator();
9046 while (it.hasNext()) {
9047 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009048 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 r.dump(pw, " ");
9050 }
9051 }
9052 }
9053 }
9054
9055 void dumpProviders(PrintWriter pw) {
9056 synchronized (this) {
9057 if (checkCallingPermission(android.Manifest.permission.DUMP)
9058 != PackageManager.PERMISSION_GRANTED) {
9059 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9060 + Binder.getCallingPid()
9061 + ", uid=" + Binder.getCallingUid()
9062 + " without permission "
9063 + android.Manifest.permission.DUMP);
9064 return;
9065 }
9066
9067 pw.println("Content Providers in Current Activity Manager State:");
9068
9069 boolean needSep = false;
9070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 if (mProvidersByClass.size() > 0) {
9072 if (needSep) pw.println(" ");
9073 pw.println(" Published content providers (by class):");
9074 Iterator it = mProvidersByClass.entrySet().iterator();
9075 while (it.hasNext()) {
9076 Map.Entry e = (Map.Entry)it.next();
9077 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009078 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009079 r.dump(pw, " ");
9080 }
9081 needSep = true;
9082 }
9083
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009084 if (mProvidersByName.size() > 0) {
9085 pw.println(" ");
9086 pw.println(" Authority to provider mappings:");
9087 Iterator it = mProvidersByName.entrySet().iterator();
9088 while (it.hasNext()) {
9089 Map.Entry e = (Map.Entry)it.next();
9090 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9091 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9092 pw.println(r);
9093 }
9094 needSep = true;
9095 }
9096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009097 if (mLaunchingProviders.size() > 0) {
9098 if (needSep) pw.println(" ");
9099 pw.println(" Launching content providers:");
9100 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009101 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9102 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009103 }
9104 needSep = true;
9105 }
9106
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009107 if (mGrantedUriPermissions.size() > 0) {
9108 pw.println();
9109 pw.println("Granted Uri Permissions:");
9110 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9111 int uid = mGrantedUriPermissions.keyAt(i);
9112 HashMap<Uri, UriPermission> perms
9113 = mGrantedUriPermissions.valueAt(i);
9114 pw.print(" * UID "); pw.print(uid);
9115 pw.println(" holds:");
9116 for (UriPermission perm : perms.values()) {
9117 pw.print(" "); pw.println(perm);
9118 perm.dump(pw, " ");
9119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009120 }
9121 }
9122 }
9123 }
9124
9125 void dumpSenders(PrintWriter pw) {
9126 synchronized (this) {
9127 if (checkCallingPermission(android.Manifest.permission.DUMP)
9128 != PackageManager.PERMISSION_GRANTED) {
9129 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9130 + Binder.getCallingPid()
9131 + ", uid=" + Binder.getCallingUid()
9132 + " without permission "
9133 + android.Manifest.permission.DUMP);
9134 return;
9135 }
9136
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009137 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009138
9139 if (this.mIntentSenderRecords.size() > 0) {
9140 Iterator<WeakReference<PendingIntentRecord>> it
9141 = mIntentSenderRecords.values().iterator();
9142 while (it.hasNext()) {
9143 WeakReference<PendingIntentRecord> ref = it.next();
9144 PendingIntentRecord rec = ref != null ? ref.get(): null;
9145 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009146 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 rec.dump(pw, " ");
9148 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009149 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009150 }
9151 }
9152 }
9153 }
9154 }
9155
9156 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009157 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009158 TaskRecord lastTask = null;
9159 for (int i=list.size()-1; i>=0; i--) {
9160 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009161 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009162 if (lastTask != r.task) {
9163 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009164 pw.print(prefix);
9165 pw.print(full ? "* " : " ");
9166 pw.println(lastTask);
9167 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009168 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009170 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009171 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9172 pw.print(" #"); pw.print(i); pw.print(": ");
9173 pw.println(r);
9174 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009175 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009177 }
9178 }
9179
9180 private static final int dumpProcessList(PrintWriter pw, List list,
9181 String prefix, String normalLabel, String persistentLabel,
9182 boolean inclOomAdj) {
9183 int numPers = 0;
9184 for (int i=list.size()-1; i>=0; i--) {
9185 ProcessRecord r = (ProcessRecord)list.get(i);
9186 if (false) {
9187 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9188 + " #" + i + ":");
9189 r.dump(pw, prefix + " ");
9190 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009191 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009192 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009193 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9194 if (r.adjSource != null || r.adjTarget != null) {
9195 pw.println(prefix + " " + r.adjTarget
9196 + " used by " + r.adjSource);
9197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009198 } else {
9199 pw.println(String.format("%s%s #%2d: %s",
9200 prefix, (r.persistent ? persistentLabel : normalLabel),
9201 i, r.toString()));
9202 }
9203 if (r.persistent) {
9204 numPers++;
9205 }
9206 }
9207 return numPers;
9208 }
9209
9210 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9211 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009212 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009213 long uptime = SystemClock.uptimeMillis();
9214 long realtime = SystemClock.elapsedRealtime();
9215
9216 if (isCheckinRequest) {
9217 // short checkin version
9218 pw.println(uptime + "," + realtime);
9219 pw.flush();
9220 } else {
9221 pw.println("Applications Memory Usage (kB):");
9222 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9223 }
9224 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9225 ProcessRecord r = (ProcessRecord)list.get(i);
9226 if (r.thread != null) {
9227 if (!isCheckinRequest) {
9228 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9229 pw.flush();
9230 }
9231 try {
9232 r.thread.asBinder().dump(fd, args);
9233 } catch (RemoteException e) {
9234 if (!isCheckinRequest) {
9235 pw.println("Got RemoteException!");
9236 pw.flush();
9237 }
9238 }
9239 }
9240 }
9241 }
9242
9243 /**
9244 * Searches array of arguments for the specified string
9245 * @param args array of argument strings
9246 * @param value value to search for
9247 * @return true if the value is contained in the array
9248 */
9249 private static boolean scanArgs(String[] args, String value) {
9250 if (args != null) {
9251 for (String arg : args) {
9252 if (value.equals(arg)) {
9253 return true;
9254 }
9255 }
9256 }
9257 return false;
9258 }
9259
Dianne Hackborn75b03852009-06-12 15:43:26 -07009260 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009261 int count = mHistory.size();
9262
9263 // convert the token to an entry in the history.
9264 HistoryRecord r = null;
9265 int index = -1;
9266 for (int i=count-1; i>=0; i--) {
9267 Object o = mHistory.get(i);
9268 if (o == token) {
9269 r = (HistoryRecord)o;
9270 index = i;
9271 break;
9272 }
9273 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009274
9275 return index;
9276 }
9277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009278 private final void killServicesLocked(ProcessRecord app,
9279 boolean allowRestart) {
9280 // Report disconnected services.
9281 if (false) {
9282 // XXX we are letting the client link to the service for
9283 // death notifications.
9284 if (app.services.size() > 0) {
9285 Iterator it = app.services.iterator();
9286 while (it.hasNext()) {
9287 ServiceRecord r = (ServiceRecord)it.next();
9288 if (r.connections.size() > 0) {
9289 Iterator<ConnectionRecord> jt
9290 = r.connections.values().iterator();
9291 while (jt.hasNext()) {
9292 ConnectionRecord c = jt.next();
9293 if (c.binding.client != app) {
9294 try {
9295 //c.conn.connected(r.className, null);
9296 } catch (Exception e) {
9297 // todo: this should be asynchronous!
9298 Log.w(TAG, "Exception thrown disconnected servce "
9299 + r.shortName
9300 + " from app " + app.processName, e);
9301 }
9302 }
9303 }
9304 }
9305 }
9306 }
9307 }
9308
9309 // Clean up any connections this application has to other services.
9310 if (app.connections.size() > 0) {
9311 Iterator<ConnectionRecord> it = app.connections.iterator();
9312 while (it.hasNext()) {
9313 ConnectionRecord r = it.next();
9314 removeConnectionLocked(r, app, null);
9315 }
9316 }
9317 app.connections.clear();
9318
9319 if (app.services.size() != 0) {
9320 // Any services running in the application need to be placed
9321 // back in the pending list.
9322 Iterator it = app.services.iterator();
9323 while (it.hasNext()) {
9324 ServiceRecord sr = (ServiceRecord)it.next();
9325 synchronized (sr.stats.getBatteryStats()) {
9326 sr.stats.stopLaunchedLocked();
9327 }
9328 sr.app = null;
9329 sr.executeNesting = 0;
9330 mStoppingServices.remove(sr);
9331 if (sr.bindings.size() > 0) {
9332 Iterator<IntentBindRecord> bindings
9333 = sr.bindings.values().iterator();
9334 while (bindings.hasNext()) {
9335 IntentBindRecord b = bindings.next();
9336 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9337 + ": shouldUnbind=" + b.hasBound);
9338 b.binder = null;
9339 b.requested = b.received = b.hasBound = false;
9340 }
9341 }
9342
9343 if (sr.crashCount >= 2) {
9344 Log.w(TAG, "Service crashed " + sr.crashCount
9345 + " times, stopping: " + sr);
9346 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9347 sr.crashCount, sr.shortName, app.pid);
9348 bringDownServiceLocked(sr, true);
9349 } else if (!allowRestart) {
9350 bringDownServiceLocked(sr, true);
9351 } else {
9352 scheduleServiceRestartLocked(sr);
9353 }
9354 }
9355
9356 if (!allowRestart) {
9357 app.services.clear();
9358 }
9359 }
9360
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009361 // Make sure we have no more records on the stopping list.
9362 int i = mStoppingServices.size();
9363 while (i > 0) {
9364 i--;
9365 ServiceRecord sr = mStoppingServices.get(i);
9366 if (sr.app == app) {
9367 mStoppingServices.remove(i);
9368 }
9369 }
9370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009371 app.executingServices.clear();
9372 }
9373
9374 private final void removeDyingProviderLocked(ProcessRecord proc,
9375 ContentProviderRecord cpr) {
9376 synchronized (cpr) {
9377 cpr.launchingApp = null;
9378 cpr.notifyAll();
9379 }
9380
9381 mProvidersByClass.remove(cpr.info.name);
9382 String names[] = cpr.info.authority.split(";");
9383 for (int j = 0; j < names.length; j++) {
9384 mProvidersByName.remove(names[j]);
9385 }
9386
9387 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9388 while (cit.hasNext()) {
9389 ProcessRecord capp = cit.next();
9390 if (!capp.persistent && capp.thread != null
9391 && capp.pid != 0
9392 && capp.pid != MY_PID) {
9393 Log.i(TAG, "Killing app " + capp.processName
9394 + " (pid " + capp.pid
9395 + ") because provider " + cpr.info.name
9396 + " is in dying process " + proc.processName);
9397 Process.killProcess(capp.pid);
9398 }
9399 }
9400
9401 mLaunchingProviders.remove(cpr);
9402 }
9403
9404 /**
9405 * Main code for cleaning up a process when it has gone away. This is
9406 * called both as a result of the process dying, or directly when stopping
9407 * a process when running in single process mode.
9408 */
9409 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9410 boolean restarting, int index) {
9411 if (index >= 0) {
9412 mLRUProcesses.remove(index);
9413 }
9414
9415 // Dismiss any open dialogs.
9416 if (app.crashDialog != null) {
9417 app.crashDialog.dismiss();
9418 app.crashDialog = null;
9419 }
9420 if (app.anrDialog != null) {
9421 app.anrDialog.dismiss();
9422 app.anrDialog = null;
9423 }
9424 if (app.waitDialog != null) {
9425 app.waitDialog.dismiss();
9426 app.waitDialog = null;
9427 }
9428
9429 app.crashing = false;
9430 app.notResponding = false;
9431
9432 app.resetPackageList();
9433 app.thread = null;
9434 app.forcingToForeground = null;
9435 app.foregroundServices = false;
9436
9437 killServicesLocked(app, true);
9438
9439 boolean restart = false;
9440
9441 int NL = mLaunchingProviders.size();
9442
9443 // Remove published content providers.
9444 if (!app.pubProviders.isEmpty()) {
9445 Iterator it = app.pubProviders.values().iterator();
9446 while (it.hasNext()) {
9447 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9448 cpr.provider = null;
9449 cpr.app = null;
9450
9451 // See if someone is waiting for this provider... in which
9452 // case we don't remove it, but just let it restart.
9453 int i = 0;
9454 if (!app.bad) {
9455 for (; i<NL; i++) {
9456 if (mLaunchingProviders.get(i) == cpr) {
9457 restart = true;
9458 break;
9459 }
9460 }
9461 } else {
9462 i = NL;
9463 }
9464
9465 if (i >= NL) {
9466 removeDyingProviderLocked(app, cpr);
9467 NL = mLaunchingProviders.size();
9468 }
9469 }
9470 app.pubProviders.clear();
9471 }
9472
9473 // Look through the content providers we are waiting to have launched,
9474 // and if any run in this process then either schedule a restart of
9475 // the process or kill the client waiting for it if this process has
9476 // gone bad.
9477 for (int i=0; i<NL; i++) {
9478 ContentProviderRecord cpr = (ContentProviderRecord)
9479 mLaunchingProviders.get(i);
9480 if (cpr.launchingApp == app) {
9481 if (!app.bad) {
9482 restart = true;
9483 } else {
9484 removeDyingProviderLocked(app, cpr);
9485 NL = mLaunchingProviders.size();
9486 }
9487 }
9488 }
9489
9490 // Unregister from connected content providers.
9491 if (!app.conProviders.isEmpty()) {
9492 Iterator it = app.conProviders.iterator();
9493 while (it.hasNext()) {
9494 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9495 cpr.clients.remove(app);
9496 }
9497 app.conProviders.clear();
9498 }
9499
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009500 // At this point there may be remaining entries in mLaunchingProviders
9501 // where we were the only one waiting, so they are no longer of use.
9502 // Look for these and clean up if found.
9503 // XXX Commented out for now. Trying to figure out a way to reproduce
9504 // the actual situation to identify what is actually going on.
9505 if (false) {
9506 for (int i=0; i<NL; i++) {
9507 ContentProviderRecord cpr = (ContentProviderRecord)
9508 mLaunchingProviders.get(i);
9509 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9510 synchronized (cpr) {
9511 cpr.launchingApp = null;
9512 cpr.notifyAll();
9513 }
9514 }
9515 }
9516 }
9517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009518 skipCurrentReceiverLocked(app);
9519
9520 // Unregister any receivers.
9521 if (app.receivers.size() > 0) {
9522 Iterator<ReceiverList> it = app.receivers.iterator();
9523 while (it.hasNext()) {
9524 removeReceiverLocked(it.next());
9525 }
9526 app.receivers.clear();
9527 }
9528
Christopher Tate181fafa2009-05-14 11:12:14 -07009529 // If the app is undergoing backup, tell the backup manager about it
9530 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9531 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9532 try {
9533 IBackupManager bm = IBackupManager.Stub.asInterface(
9534 ServiceManager.getService(Context.BACKUP_SERVICE));
9535 bm.agentDisconnected(app.info.packageName);
9536 } catch (RemoteException e) {
9537 // can't happen; backup manager is local
9538 }
9539 }
9540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009541 // If the caller is restarting this app, then leave it in its
9542 // current lists and let the caller take care of it.
9543 if (restarting) {
9544 return;
9545 }
9546
9547 if (!app.persistent) {
9548 if (DEBUG_PROCESSES) Log.v(TAG,
9549 "Removing non-persistent process during cleanup: " + app);
9550 mProcessNames.remove(app.processName, app.info.uid);
9551 } else if (!app.removed) {
9552 // This app is persistent, so we need to keep its record around.
9553 // If it is not already on the pending app list, add it there
9554 // and start a new process for it.
9555 app.thread = null;
9556 app.forcingToForeground = null;
9557 app.foregroundServices = false;
9558 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9559 mPersistentStartingProcesses.add(app);
9560 restart = true;
9561 }
9562 }
9563 mProcessesOnHold.remove(app);
9564
The Android Open Source Project4df24232009-03-05 14:34:35 -08009565 if (app == mHomeProcess) {
9566 mHomeProcess = null;
9567 }
9568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009569 if (restart) {
9570 // We have components that still need to be running in the
9571 // process, so re-launch it.
9572 mProcessNames.put(app.processName, app.info.uid, app);
9573 startProcessLocked(app, "restart", app.processName);
9574 } else if (app.pid > 0 && app.pid != MY_PID) {
9575 // Goodbye!
9576 synchronized (mPidsSelfLocked) {
9577 mPidsSelfLocked.remove(app.pid);
9578 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9579 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009580 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009581 }
9582 }
9583
9584 // =========================================================
9585 // SERVICES
9586 // =========================================================
9587
9588 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9589 ActivityManager.RunningServiceInfo info =
9590 new ActivityManager.RunningServiceInfo();
9591 info.service = r.name;
9592 if (r.app != null) {
9593 info.pid = r.app.pid;
9594 }
9595 info.process = r.processName;
9596 info.foreground = r.isForeground;
9597 info.activeSince = r.createTime;
9598 info.started = r.startRequested;
9599 info.clientCount = r.connections.size();
9600 info.crashCount = r.crashCount;
9601 info.lastActivityTime = r.lastActivity;
9602 return info;
9603 }
9604
9605 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9606 int flags) {
9607 synchronized (this) {
9608 ArrayList<ActivityManager.RunningServiceInfo> res
9609 = new ArrayList<ActivityManager.RunningServiceInfo>();
9610
9611 if (mServices.size() > 0) {
9612 Iterator<ServiceRecord> it = mServices.values().iterator();
9613 while (it.hasNext() && res.size() < maxNum) {
9614 res.add(makeRunningServiceInfoLocked(it.next()));
9615 }
9616 }
9617
9618 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9619 ServiceRecord r = mRestartingServices.get(i);
9620 ActivityManager.RunningServiceInfo info =
9621 makeRunningServiceInfoLocked(r);
9622 info.restarting = r.nextRestartTime;
9623 res.add(info);
9624 }
9625
9626 return res;
9627 }
9628 }
9629
9630 private final ServiceRecord findServiceLocked(ComponentName name,
9631 IBinder token) {
9632 ServiceRecord r = mServices.get(name);
9633 return r == token ? r : null;
9634 }
9635
9636 private final class ServiceLookupResult {
9637 final ServiceRecord record;
9638 final String permission;
9639
9640 ServiceLookupResult(ServiceRecord _record, String _permission) {
9641 record = _record;
9642 permission = _permission;
9643 }
9644 };
9645
9646 private ServiceLookupResult findServiceLocked(Intent service,
9647 String resolvedType) {
9648 ServiceRecord r = null;
9649 if (service.getComponent() != null) {
9650 r = mServices.get(service.getComponent());
9651 }
9652 if (r == null) {
9653 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9654 r = mServicesByIntent.get(filter);
9655 }
9656
9657 if (r == null) {
9658 try {
9659 ResolveInfo rInfo =
9660 ActivityThread.getPackageManager().resolveService(
9661 service, resolvedType, 0);
9662 ServiceInfo sInfo =
9663 rInfo != null ? rInfo.serviceInfo : null;
9664 if (sInfo == null) {
9665 return null;
9666 }
9667
9668 ComponentName name = new ComponentName(
9669 sInfo.applicationInfo.packageName, sInfo.name);
9670 r = mServices.get(name);
9671 } catch (RemoteException ex) {
9672 // pm is in same process, this will never happen.
9673 }
9674 }
9675 if (r != null) {
9676 int callingPid = Binder.getCallingPid();
9677 int callingUid = Binder.getCallingUid();
9678 if (checkComponentPermission(r.permission,
9679 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9680 != PackageManager.PERMISSION_GRANTED) {
9681 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9682 + " from pid=" + callingPid
9683 + ", uid=" + callingUid
9684 + " requires " + r.permission);
9685 return new ServiceLookupResult(null, r.permission);
9686 }
9687 return new ServiceLookupResult(r, null);
9688 }
9689 return null;
9690 }
9691
9692 private class ServiceRestarter implements Runnable {
9693 private ServiceRecord mService;
9694
9695 void setService(ServiceRecord service) {
9696 mService = service;
9697 }
9698
9699 public void run() {
9700 synchronized(ActivityManagerService.this) {
9701 performServiceRestartLocked(mService);
9702 }
9703 }
9704 }
9705
9706 private ServiceLookupResult retrieveServiceLocked(Intent service,
9707 String resolvedType, int callingPid, int callingUid) {
9708 ServiceRecord r = null;
9709 if (service.getComponent() != null) {
9710 r = mServices.get(service.getComponent());
9711 }
9712 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9713 r = mServicesByIntent.get(filter);
9714 if (r == null) {
9715 try {
9716 ResolveInfo rInfo =
9717 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009718 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009719 ServiceInfo sInfo =
9720 rInfo != null ? rInfo.serviceInfo : null;
9721 if (sInfo == null) {
9722 Log.w(TAG, "Unable to start service " + service +
9723 ": not found");
9724 return null;
9725 }
9726
9727 ComponentName name = new ComponentName(
9728 sInfo.applicationInfo.packageName, sInfo.name);
9729 r = mServices.get(name);
9730 if (r == null) {
9731 filter = new Intent.FilterComparison(service.cloneFilter());
9732 ServiceRestarter res = new ServiceRestarter();
9733 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9734 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9735 synchronized (stats) {
9736 ss = stats.getServiceStatsLocked(
9737 sInfo.applicationInfo.uid, sInfo.packageName,
9738 sInfo.name);
9739 }
9740 r = new ServiceRecord(ss, name, filter, sInfo, res);
9741 res.setService(r);
9742 mServices.put(name, r);
9743 mServicesByIntent.put(filter, r);
9744
9745 // Make sure this component isn't in the pending list.
9746 int N = mPendingServices.size();
9747 for (int i=0; i<N; i++) {
9748 ServiceRecord pr = mPendingServices.get(i);
9749 if (pr.name.equals(name)) {
9750 mPendingServices.remove(i);
9751 i--;
9752 N--;
9753 }
9754 }
9755 }
9756 } catch (RemoteException ex) {
9757 // pm is in same process, this will never happen.
9758 }
9759 }
9760 if (r != null) {
9761 if (checkComponentPermission(r.permission,
9762 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9763 != PackageManager.PERMISSION_GRANTED) {
9764 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9765 + " from pid=" + Binder.getCallingPid()
9766 + ", uid=" + Binder.getCallingUid()
9767 + " requires " + r.permission);
9768 return new ServiceLookupResult(null, r.permission);
9769 }
9770 return new ServiceLookupResult(r, null);
9771 }
9772 return null;
9773 }
9774
9775 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9776 long now = SystemClock.uptimeMillis();
9777 if (r.executeNesting == 0 && r.app != null) {
9778 if (r.app.executingServices.size() == 0) {
9779 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9780 msg.obj = r.app;
9781 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9782 }
9783 r.app.executingServices.add(r);
9784 }
9785 r.executeNesting++;
9786 r.executingStart = now;
9787 }
9788
9789 private final void sendServiceArgsLocked(ServiceRecord r,
9790 boolean oomAdjusted) {
9791 final int N = r.startArgs.size();
9792 if (N == 0) {
9793 return;
9794 }
9795
9796 final int BASEID = r.lastStartId - N + 1;
9797 int i = 0;
9798 while (i < N) {
9799 try {
9800 Intent args = r.startArgs.get(i);
9801 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9802 + r.name + " " + r.intent + " args=" + args);
9803 bumpServiceExecutingLocked(r);
9804 if (!oomAdjusted) {
9805 oomAdjusted = true;
9806 updateOomAdjLocked(r.app);
9807 }
9808 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9809 i++;
9810 } catch (Exception e) {
9811 break;
9812 }
9813 }
9814 if (i == N) {
9815 r.startArgs.clear();
9816 } else {
9817 while (i > 0) {
9818 r.startArgs.remove(0);
9819 i--;
9820 }
9821 }
9822 }
9823
9824 private final boolean requestServiceBindingLocked(ServiceRecord r,
9825 IntentBindRecord i, boolean rebind) {
9826 if (r.app == null || r.app.thread == null) {
9827 // If service is not currently running, can't yet bind.
9828 return false;
9829 }
9830 if ((!i.requested || rebind) && i.apps.size() > 0) {
9831 try {
9832 bumpServiceExecutingLocked(r);
9833 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9834 + ": shouldUnbind=" + i.hasBound);
9835 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9836 if (!rebind) {
9837 i.requested = true;
9838 }
9839 i.hasBound = true;
9840 i.doRebind = false;
9841 } catch (RemoteException e) {
9842 return false;
9843 }
9844 }
9845 return true;
9846 }
9847
9848 private final void requestServiceBindingsLocked(ServiceRecord r) {
9849 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9850 while (bindings.hasNext()) {
9851 IntentBindRecord i = bindings.next();
9852 if (!requestServiceBindingLocked(r, i, false)) {
9853 break;
9854 }
9855 }
9856 }
9857
9858 private final void realStartServiceLocked(ServiceRecord r,
9859 ProcessRecord app) throws RemoteException {
9860 if (app.thread == null) {
9861 throw new RemoteException();
9862 }
9863
9864 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009865 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009866
9867 app.services.add(r);
9868 bumpServiceExecutingLocked(r);
9869 updateLRUListLocked(app, true);
9870
9871 boolean created = false;
9872 try {
9873 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9874 + r.name + " " + r.intent);
9875 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9876 System.identityHashCode(r), r.shortName,
9877 r.intent.getIntent().toString(), r.app.pid);
9878 synchronized (r.stats.getBatteryStats()) {
9879 r.stats.startLaunchedLocked();
9880 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009881 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009882 app.thread.scheduleCreateService(r, r.serviceInfo);
9883 created = true;
9884 } finally {
9885 if (!created) {
9886 app.services.remove(r);
9887 scheduleServiceRestartLocked(r);
9888 }
9889 }
9890
9891 requestServiceBindingsLocked(r);
9892 sendServiceArgsLocked(r, true);
9893 }
9894
9895 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9896 r.totalRestartCount++;
9897 if (r.restartDelay == 0) {
9898 r.restartCount++;
9899 r.restartDelay = SERVICE_RESTART_DURATION;
9900 } else {
9901 // If it has been a "reasonably long time" since the service
9902 // was started, then reset our restart duration back to
9903 // the beginning, so we don't infinitely increase the duration
9904 // on a service that just occasionally gets killed (which is
9905 // a normal case, due to process being killed to reclaim memory).
9906 long now = SystemClock.uptimeMillis();
9907 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9908 r.restartCount = 1;
9909 r.restartDelay = SERVICE_RESTART_DURATION;
9910 } else {
9911 r.restartDelay *= 2;
9912 }
9913 }
9914 if (!mRestartingServices.contains(r)) {
9915 mRestartingServices.add(r);
9916 }
9917 mHandler.removeCallbacks(r.restarter);
9918 mHandler.postDelayed(r.restarter, r.restartDelay);
9919 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9920 Log.w(TAG, "Scheduling restart of crashed service "
9921 + r.shortName + " in " + r.restartDelay + "ms");
9922 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9923 r.shortName, r.restartDelay);
9924
9925 Message msg = Message.obtain();
9926 msg.what = SERVICE_ERROR_MSG;
9927 msg.obj = r;
9928 mHandler.sendMessage(msg);
9929 }
9930
9931 final void performServiceRestartLocked(ServiceRecord r) {
9932 if (!mRestartingServices.contains(r)) {
9933 return;
9934 }
9935 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9936 }
9937
9938 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9939 if (r.restartDelay == 0) {
9940 return false;
9941 }
9942 r.resetRestartCounter();
9943 mRestartingServices.remove(r);
9944 mHandler.removeCallbacks(r.restarter);
9945 return true;
9946 }
9947
9948 private final boolean bringUpServiceLocked(ServiceRecord r,
9949 int intentFlags, boolean whileRestarting) {
9950 //Log.i(TAG, "Bring up service:");
9951 //r.dump(" ");
9952
9953 if (r.app != null) {
9954 sendServiceArgsLocked(r, false);
9955 return true;
9956 }
9957
9958 if (!whileRestarting && r.restartDelay > 0) {
9959 // If waiting for a restart, then do nothing.
9960 return true;
9961 }
9962
9963 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9964 + " " + r.intent);
9965
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009966 // We are now bringing the service up, so no longer in the
9967 // restarting state.
9968 mRestartingServices.remove(r);
9969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009970 final String appName = r.processName;
9971 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9972 if (app != null && app.thread != null) {
9973 try {
9974 realStartServiceLocked(r, app);
9975 return true;
9976 } catch (RemoteException e) {
9977 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9978 }
9979
9980 // If a dead object exception was thrown -- fall through to
9981 // restart the application.
9982 }
9983
9984 if (!mPendingServices.contains(r)) {
9985 // Not running -- get it started, and enqueue this service record
9986 // to be executed when the app comes up.
9987 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9988 "service", r.name) == null) {
9989 Log.w(TAG, "Unable to launch app "
9990 + r.appInfo.packageName + "/"
9991 + r.appInfo.uid + " for service "
9992 + r.intent.getIntent() + ": process is bad");
9993 bringDownServiceLocked(r, true);
9994 return false;
9995 }
9996 mPendingServices.add(r);
9997 }
9998 return true;
9999 }
10000
10001 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10002 //Log.i(TAG, "Bring down service:");
10003 //r.dump(" ");
10004
10005 // Does it still need to run?
10006 if (!force && r.startRequested) {
10007 return;
10008 }
10009 if (r.connections.size() > 0) {
10010 if (!force) {
10011 // XXX should probably keep a count of the number of auto-create
10012 // connections directly in the service.
10013 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10014 while (it.hasNext()) {
10015 ConnectionRecord cr = it.next();
10016 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10017 return;
10018 }
10019 }
10020 }
10021
10022 // Report to all of the connections that the service is no longer
10023 // available.
10024 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10025 while (it.hasNext()) {
10026 ConnectionRecord c = it.next();
10027 try {
10028 // todo: shouldn't be a synchronous call!
10029 c.conn.connected(r.name, null);
10030 } catch (Exception e) {
10031 Log.w(TAG, "Failure disconnecting service " + r.name +
10032 " to connection " + c.conn.asBinder() +
10033 " (in " + c.binding.client.processName + ")", e);
10034 }
10035 }
10036 }
10037
10038 // Tell the service that it has been unbound.
10039 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10040 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10041 while (it.hasNext()) {
10042 IntentBindRecord ibr = it.next();
10043 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10044 + ": hasBound=" + ibr.hasBound);
10045 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10046 try {
10047 bumpServiceExecutingLocked(r);
10048 updateOomAdjLocked(r.app);
10049 ibr.hasBound = false;
10050 r.app.thread.scheduleUnbindService(r,
10051 ibr.intent.getIntent());
10052 } catch (Exception e) {
10053 Log.w(TAG, "Exception when unbinding service "
10054 + r.shortName, e);
10055 serviceDoneExecutingLocked(r, true);
10056 }
10057 }
10058 }
10059 }
10060
10061 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10062 + " " + r.intent);
10063 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10064 System.identityHashCode(r), r.shortName,
10065 (r.app != null) ? r.app.pid : -1);
10066
10067 mServices.remove(r.name);
10068 mServicesByIntent.remove(r.intent);
10069 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10070 r.totalRestartCount = 0;
10071 unscheduleServiceRestartLocked(r);
10072
10073 // Also make sure it is not on the pending list.
10074 int N = mPendingServices.size();
10075 for (int i=0; i<N; i++) {
10076 if (mPendingServices.get(i) == r) {
10077 mPendingServices.remove(i);
10078 if (DEBUG_SERVICE) Log.v(
10079 TAG, "Removed pending service: " + r.shortName);
10080 i--;
10081 N--;
10082 }
10083 }
10084
10085 if (r.app != null) {
10086 synchronized (r.stats.getBatteryStats()) {
10087 r.stats.stopLaunchedLocked();
10088 }
10089 r.app.services.remove(r);
10090 if (r.app.thread != null) {
10091 updateServiceForegroundLocked(r.app, false);
10092 try {
10093 Log.i(TAG, "Stopping service: " + r.shortName);
10094 bumpServiceExecutingLocked(r);
10095 mStoppingServices.add(r);
10096 updateOomAdjLocked(r.app);
10097 r.app.thread.scheduleStopService(r);
10098 } catch (Exception e) {
10099 Log.w(TAG, "Exception when stopping service "
10100 + r.shortName, e);
10101 serviceDoneExecutingLocked(r, true);
10102 }
10103 } else {
10104 if (DEBUG_SERVICE) Log.v(
10105 TAG, "Removed service that has no process: " + r.shortName);
10106 }
10107 } else {
10108 if (DEBUG_SERVICE) Log.v(
10109 TAG, "Removed service that is not running: " + r.shortName);
10110 }
10111 }
10112
10113 ComponentName startServiceLocked(IApplicationThread caller,
10114 Intent service, String resolvedType,
10115 int callingPid, int callingUid) {
10116 synchronized(this) {
10117 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10118 + " type=" + resolvedType + " args=" + service.getExtras());
10119
10120 if (caller != null) {
10121 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10122 if (callerApp == null) {
10123 throw new SecurityException(
10124 "Unable to find app for caller " + caller
10125 + " (pid=" + Binder.getCallingPid()
10126 + ") when starting service " + service);
10127 }
10128 }
10129
10130 ServiceLookupResult res =
10131 retrieveServiceLocked(service, resolvedType,
10132 callingPid, callingUid);
10133 if (res == null) {
10134 return null;
10135 }
10136 if (res.record == null) {
10137 return new ComponentName("!", res.permission != null
10138 ? res.permission : "private to package");
10139 }
10140 ServiceRecord r = res.record;
10141 if (unscheduleServiceRestartLocked(r)) {
10142 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10143 + r.shortName);
10144 }
10145 r.startRequested = true;
10146 r.startArgs.add(service);
10147 r.lastStartId++;
10148 if (r.lastStartId < 1) {
10149 r.lastStartId = 1;
10150 }
10151 r.lastActivity = SystemClock.uptimeMillis();
10152 synchronized (r.stats.getBatteryStats()) {
10153 r.stats.startRunningLocked();
10154 }
10155 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10156 return new ComponentName("!", "Service process is bad");
10157 }
10158 return r.name;
10159 }
10160 }
10161
10162 public ComponentName startService(IApplicationThread caller, Intent service,
10163 String resolvedType) {
10164 // Refuse possible leaked file descriptors
10165 if (service != null && service.hasFileDescriptors() == true) {
10166 throw new IllegalArgumentException("File descriptors passed in Intent");
10167 }
10168
10169 synchronized(this) {
10170 final int callingPid = Binder.getCallingPid();
10171 final int callingUid = Binder.getCallingUid();
10172 final long origId = Binder.clearCallingIdentity();
10173 ComponentName res = startServiceLocked(caller, service,
10174 resolvedType, callingPid, callingUid);
10175 Binder.restoreCallingIdentity(origId);
10176 return res;
10177 }
10178 }
10179
10180 ComponentName startServiceInPackage(int uid,
10181 Intent service, String resolvedType) {
10182 synchronized(this) {
10183 final long origId = Binder.clearCallingIdentity();
10184 ComponentName res = startServiceLocked(null, service,
10185 resolvedType, -1, uid);
10186 Binder.restoreCallingIdentity(origId);
10187 return res;
10188 }
10189 }
10190
10191 public int stopService(IApplicationThread caller, Intent service,
10192 String resolvedType) {
10193 // Refuse possible leaked file descriptors
10194 if (service != null && service.hasFileDescriptors() == true) {
10195 throw new IllegalArgumentException("File descriptors passed in Intent");
10196 }
10197
10198 synchronized(this) {
10199 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10200 + " type=" + resolvedType);
10201
10202 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10203 if (caller != null && callerApp == null) {
10204 throw new SecurityException(
10205 "Unable to find app for caller " + caller
10206 + " (pid=" + Binder.getCallingPid()
10207 + ") when stopping service " + service);
10208 }
10209
10210 // If this service is active, make sure it is stopped.
10211 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10212 if (r != null) {
10213 if (r.record != null) {
10214 synchronized (r.record.stats.getBatteryStats()) {
10215 r.record.stats.stopRunningLocked();
10216 }
10217 r.record.startRequested = false;
10218 final long origId = Binder.clearCallingIdentity();
10219 bringDownServiceLocked(r.record, false);
10220 Binder.restoreCallingIdentity(origId);
10221 return 1;
10222 }
10223 return -1;
10224 }
10225 }
10226
10227 return 0;
10228 }
10229
10230 public IBinder peekService(Intent service, String resolvedType) {
10231 // Refuse possible leaked file descriptors
10232 if (service != null && service.hasFileDescriptors() == true) {
10233 throw new IllegalArgumentException("File descriptors passed in Intent");
10234 }
10235
10236 IBinder ret = null;
10237
10238 synchronized(this) {
10239 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10240
10241 if (r != null) {
10242 // r.record is null if findServiceLocked() failed the caller permission check
10243 if (r.record == null) {
10244 throw new SecurityException(
10245 "Permission Denial: Accessing service " + r.record.name
10246 + " from pid=" + Binder.getCallingPid()
10247 + ", uid=" + Binder.getCallingUid()
10248 + " requires " + r.permission);
10249 }
10250 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10251 if (ib != null) {
10252 ret = ib.binder;
10253 }
10254 }
10255 }
10256
10257 return ret;
10258 }
10259
10260 public boolean stopServiceToken(ComponentName className, IBinder token,
10261 int startId) {
10262 synchronized(this) {
10263 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10264 + " " + token + " startId=" + startId);
10265 ServiceRecord r = findServiceLocked(className, token);
10266 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10267 synchronized (r.stats.getBatteryStats()) {
10268 r.stats.stopRunningLocked();
10269 r.startRequested = false;
10270 }
10271 final long origId = Binder.clearCallingIdentity();
10272 bringDownServiceLocked(r, false);
10273 Binder.restoreCallingIdentity(origId);
10274 return true;
10275 }
10276 }
10277 return false;
10278 }
10279
10280 public void setServiceForeground(ComponentName className, IBinder token,
10281 boolean isForeground) {
10282 synchronized(this) {
10283 ServiceRecord r = findServiceLocked(className, token);
10284 if (r != null) {
10285 if (r.isForeground != isForeground) {
10286 final long origId = Binder.clearCallingIdentity();
10287 r.isForeground = isForeground;
10288 if (r.app != null) {
10289 updateServiceForegroundLocked(r.app, true);
10290 }
10291 Binder.restoreCallingIdentity(origId);
10292 }
10293 }
10294 }
10295 }
10296
10297 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10298 boolean anyForeground = false;
10299 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10300 if (sr.isForeground) {
10301 anyForeground = true;
10302 break;
10303 }
10304 }
10305 if (anyForeground != proc.foregroundServices) {
10306 proc.foregroundServices = anyForeground;
10307 if (oomAdj) {
10308 updateOomAdjLocked();
10309 }
10310 }
10311 }
10312
10313 public int bindService(IApplicationThread caller, IBinder token,
10314 Intent service, String resolvedType,
10315 IServiceConnection connection, int flags) {
10316 // Refuse possible leaked file descriptors
10317 if (service != null && service.hasFileDescriptors() == true) {
10318 throw new IllegalArgumentException("File descriptors passed in Intent");
10319 }
10320
10321 synchronized(this) {
10322 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10323 + " type=" + resolvedType + " conn=" + connection.asBinder()
10324 + " flags=0x" + Integer.toHexString(flags));
10325 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10326 if (callerApp == null) {
10327 throw new SecurityException(
10328 "Unable to find app for caller " + caller
10329 + " (pid=" + Binder.getCallingPid()
10330 + ") when binding service " + service);
10331 }
10332
10333 HistoryRecord activity = null;
10334 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010335 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010336 if (aindex < 0) {
10337 Log.w(TAG, "Binding with unknown activity: " + token);
10338 return 0;
10339 }
10340 activity = (HistoryRecord)mHistory.get(aindex);
10341 }
10342
10343 ServiceLookupResult res =
10344 retrieveServiceLocked(service, resolvedType,
10345 Binder.getCallingPid(), Binder.getCallingUid());
10346 if (res == null) {
10347 return 0;
10348 }
10349 if (res.record == null) {
10350 return -1;
10351 }
10352 ServiceRecord s = res.record;
10353
10354 final long origId = Binder.clearCallingIdentity();
10355
10356 if (unscheduleServiceRestartLocked(s)) {
10357 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10358 + s.shortName);
10359 }
10360
10361 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10362 ConnectionRecord c = new ConnectionRecord(b, activity,
10363 connection, flags);
10364
10365 IBinder binder = connection.asBinder();
10366 s.connections.put(binder, c);
10367 b.connections.add(c);
10368 if (activity != null) {
10369 if (activity.connections == null) {
10370 activity.connections = new HashSet<ConnectionRecord>();
10371 }
10372 activity.connections.add(c);
10373 }
10374 b.client.connections.add(c);
10375 mServiceConnections.put(binder, c);
10376
10377 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10378 s.lastActivity = SystemClock.uptimeMillis();
10379 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10380 return 0;
10381 }
10382 }
10383
10384 if (s.app != null) {
10385 // This could have made the service more important.
10386 updateOomAdjLocked(s.app);
10387 }
10388
10389 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10390 + ": received=" + b.intent.received
10391 + " apps=" + b.intent.apps.size()
10392 + " doRebind=" + b.intent.doRebind);
10393
10394 if (s.app != null && b.intent.received) {
10395 // Service is already running, so we can immediately
10396 // publish the connection.
10397 try {
10398 c.conn.connected(s.name, b.intent.binder);
10399 } catch (Exception e) {
10400 Log.w(TAG, "Failure sending service " + s.shortName
10401 + " to connection " + c.conn.asBinder()
10402 + " (in " + c.binding.client.processName + ")", e);
10403 }
10404
10405 // If this is the first app connected back to this binding,
10406 // and the service had previously asked to be told when
10407 // rebound, then do so.
10408 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10409 requestServiceBindingLocked(s, b.intent, true);
10410 }
10411 } else if (!b.intent.requested) {
10412 requestServiceBindingLocked(s, b.intent, false);
10413 }
10414
10415 Binder.restoreCallingIdentity(origId);
10416 }
10417
10418 return 1;
10419 }
10420
10421 private void removeConnectionLocked(
10422 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10423 IBinder binder = c.conn.asBinder();
10424 AppBindRecord b = c.binding;
10425 ServiceRecord s = b.service;
10426 s.connections.remove(binder);
10427 b.connections.remove(c);
10428 if (c.activity != null && c.activity != skipAct) {
10429 if (c.activity.connections != null) {
10430 c.activity.connections.remove(c);
10431 }
10432 }
10433 if (b.client != skipApp) {
10434 b.client.connections.remove(c);
10435 }
10436 mServiceConnections.remove(binder);
10437
10438 if (b.connections.size() == 0) {
10439 b.intent.apps.remove(b.client);
10440 }
10441
10442 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10443 + ": shouldUnbind=" + b.intent.hasBound);
10444 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10445 && b.intent.hasBound) {
10446 try {
10447 bumpServiceExecutingLocked(s);
10448 updateOomAdjLocked(s.app);
10449 b.intent.hasBound = false;
10450 // Assume the client doesn't want to know about a rebind;
10451 // we will deal with that later if it asks for one.
10452 b.intent.doRebind = false;
10453 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10454 } catch (Exception e) {
10455 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10456 serviceDoneExecutingLocked(s, true);
10457 }
10458 }
10459
10460 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10461 bringDownServiceLocked(s, false);
10462 }
10463 }
10464
10465 public boolean unbindService(IServiceConnection connection) {
10466 synchronized (this) {
10467 IBinder binder = connection.asBinder();
10468 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10469 ConnectionRecord r = mServiceConnections.get(binder);
10470 if (r == null) {
10471 Log.w(TAG, "Unbind failed: could not find connection for "
10472 + connection.asBinder());
10473 return false;
10474 }
10475
10476 final long origId = Binder.clearCallingIdentity();
10477
10478 removeConnectionLocked(r, null, null);
10479
10480 if (r.binding.service.app != null) {
10481 // This could have made the service less important.
10482 updateOomAdjLocked(r.binding.service.app);
10483 }
10484
10485 Binder.restoreCallingIdentity(origId);
10486 }
10487
10488 return true;
10489 }
10490
10491 public void publishService(IBinder token, Intent intent, IBinder service) {
10492 // Refuse possible leaked file descriptors
10493 if (intent != null && intent.hasFileDescriptors() == true) {
10494 throw new IllegalArgumentException("File descriptors passed in Intent");
10495 }
10496
10497 synchronized(this) {
10498 if (!(token instanceof ServiceRecord)) {
10499 throw new IllegalArgumentException("Invalid service token");
10500 }
10501 ServiceRecord r = (ServiceRecord)token;
10502
10503 final long origId = Binder.clearCallingIdentity();
10504
10505 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10506 + " " + intent + ": " + service);
10507 if (r != null) {
10508 Intent.FilterComparison filter
10509 = new Intent.FilterComparison(intent);
10510 IntentBindRecord b = r.bindings.get(filter);
10511 if (b != null && !b.received) {
10512 b.binder = service;
10513 b.requested = true;
10514 b.received = true;
10515 if (r.connections.size() > 0) {
10516 Iterator<ConnectionRecord> it
10517 = r.connections.values().iterator();
10518 while (it.hasNext()) {
10519 ConnectionRecord c = it.next();
10520 if (!filter.equals(c.binding.intent.intent)) {
10521 if (DEBUG_SERVICE) Log.v(
10522 TAG, "Not publishing to: " + c);
10523 if (DEBUG_SERVICE) Log.v(
10524 TAG, "Bound intent: " + c.binding.intent.intent);
10525 if (DEBUG_SERVICE) Log.v(
10526 TAG, "Published intent: " + intent);
10527 continue;
10528 }
10529 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10530 try {
10531 c.conn.connected(r.name, service);
10532 } catch (Exception e) {
10533 Log.w(TAG, "Failure sending service " + r.name +
10534 " to connection " + c.conn.asBinder() +
10535 " (in " + c.binding.client.processName + ")", e);
10536 }
10537 }
10538 }
10539 }
10540
10541 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10542
10543 Binder.restoreCallingIdentity(origId);
10544 }
10545 }
10546 }
10547
10548 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10549 // Refuse possible leaked file descriptors
10550 if (intent != null && intent.hasFileDescriptors() == true) {
10551 throw new IllegalArgumentException("File descriptors passed in Intent");
10552 }
10553
10554 synchronized(this) {
10555 if (!(token instanceof ServiceRecord)) {
10556 throw new IllegalArgumentException("Invalid service token");
10557 }
10558 ServiceRecord r = (ServiceRecord)token;
10559
10560 final long origId = Binder.clearCallingIdentity();
10561
10562 if (r != null) {
10563 Intent.FilterComparison filter
10564 = new Intent.FilterComparison(intent);
10565 IntentBindRecord b = r.bindings.get(filter);
10566 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10567 + " at " + b + ": apps="
10568 + (b != null ? b.apps.size() : 0));
10569 if (b != null) {
10570 if (b.apps.size() > 0) {
10571 // Applications have already bound since the last
10572 // unbind, so just rebind right here.
10573 requestServiceBindingLocked(r, b, true);
10574 } else {
10575 // Note to tell the service the next time there is
10576 // a new client.
10577 b.doRebind = true;
10578 }
10579 }
10580
10581 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10582
10583 Binder.restoreCallingIdentity(origId);
10584 }
10585 }
10586 }
10587
10588 public void serviceDoneExecuting(IBinder token) {
10589 synchronized(this) {
10590 if (!(token instanceof ServiceRecord)) {
10591 throw new IllegalArgumentException("Invalid service token");
10592 }
10593 ServiceRecord r = (ServiceRecord)token;
10594 boolean inStopping = mStoppingServices.contains(token);
10595 if (r != null) {
10596 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10597 + ": nesting=" + r.executeNesting
10598 + ", inStopping=" + inStopping);
10599 if (r != token) {
10600 Log.w(TAG, "Done executing service " + r.name
10601 + " with incorrect token: given " + token
10602 + ", expected " + r);
10603 return;
10604 }
10605
10606 final long origId = Binder.clearCallingIdentity();
10607 serviceDoneExecutingLocked(r, inStopping);
10608 Binder.restoreCallingIdentity(origId);
10609 } else {
10610 Log.w(TAG, "Done executing unknown service " + r.name
10611 + " with token " + token);
10612 }
10613 }
10614 }
10615
10616 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10617 r.executeNesting--;
10618 if (r.executeNesting <= 0 && r.app != null) {
10619 r.app.executingServices.remove(r);
10620 if (r.app.executingServices.size() == 0) {
10621 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10622 }
10623 if (inStopping) {
10624 mStoppingServices.remove(r);
10625 }
10626 updateOomAdjLocked(r.app);
10627 }
10628 }
10629
10630 void serviceTimeout(ProcessRecord proc) {
10631 synchronized(this) {
10632 if (proc.executingServices.size() == 0 || proc.thread == null) {
10633 return;
10634 }
10635 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10636 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10637 ServiceRecord timeout = null;
10638 long nextTime = 0;
10639 while (it.hasNext()) {
10640 ServiceRecord sr = it.next();
10641 if (sr.executingStart < maxTime) {
10642 timeout = sr;
10643 break;
10644 }
10645 if (sr.executingStart > nextTime) {
10646 nextTime = sr.executingStart;
10647 }
10648 }
10649 if (timeout != null && mLRUProcesses.contains(proc)) {
10650 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070010651 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010652 + timeout.name);
10653 } else {
10654 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10655 msg.obj = proc;
10656 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10657 }
10658 }
10659 }
10660
10661 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010662 // BACKUP AND RESTORE
10663 // =========================================================
10664
10665 // Cause the target app to be launched if necessary and its backup agent
10666 // instantiated. The backup agent will invoke backupAgentCreated() on the
10667 // activity manager to announce its creation.
10668 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10669 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10670 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10671
10672 synchronized(this) {
10673 // !!! TODO: currently no check here that we're already bound
10674 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10675 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10676 synchronized (stats) {
10677 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10678 }
10679
10680 BackupRecord r = new BackupRecord(ss, app, backupMode);
10681 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10682 // startProcessLocked() returns existing proc's record if it's already running
10683 ProcessRecord proc = startProcessLocked(app.processName, app,
10684 false, 0, "backup", hostingName);
10685 if (proc == null) {
10686 Log.e(TAG, "Unable to start backup agent process " + r);
10687 return false;
10688 }
10689
10690 r.app = proc;
10691 mBackupTarget = r;
10692 mBackupAppName = app.packageName;
10693
Christopher Tate6fa95972009-06-05 18:43:55 -070010694 // Try not to kill the process during backup
10695 updateOomAdjLocked(proc);
10696
Christopher Tate181fafa2009-05-14 11:12:14 -070010697 // If the process is already attached, schedule the creation of the backup agent now.
10698 // If it is not yet live, this will be done when it attaches to the framework.
10699 if (proc.thread != null) {
10700 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10701 try {
10702 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10703 } catch (RemoteException e) {
10704 // !!! TODO: notify the backup manager that we crashed, or rely on
10705 // death notices, or...?
10706 }
10707 } else {
10708 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10709 }
10710 // Invariants: at this point, the target app process exists and the application
10711 // is either already running or in the process of coming up. mBackupTarget and
10712 // mBackupAppName describe the app, so that when it binds back to the AM we
10713 // know that it's scheduled for a backup-agent operation.
10714 }
10715
10716 return true;
10717 }
10718
10719 // A backup agent has just come up
10720 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10721 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10722 + " = " + agent);
10723
10724 synchronized(this) {
10725 if (!agentPackageName.equals(mBackupAppName)) {
10726 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10727 return;
10728 }
10729
Christopher Tate043dadc2009-06-02 16:11:00 -070010730 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010731 try {
10732 IBackupManager bm = IBackupManager.Stub.asInterface(
10733 ServiceManager.getService(Context.BACKUP_SERVICE));
10734 bm.agentConnected(agentPackageName, agent);
10735 } catch (RemoteException e) {
10736 // can't happen; the backup manager service is local
10737 } catch (Exception e) {
10738 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10739 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010740 } finally {
10741 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010742 }
10743 }
10744 }
10745
10746 // done with this agent
10747 public void unbindBackupAgent(ApplicationInfo appInfo) {
10748 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010749 if (appInfo == null) {
10750 Log.w(TAG, "unbind backup agent for null app");
10751 return;
10752 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010753
10754 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010755 if (mBackupAppName == null) {
10756 Log.w(TAG, "Unbinding backup agent with no active backup");
10757 return;
10758 }
10759
Christopher Tate181fafa2009-05-14 11:12:14 -070010760 if (!mBackupAppName.equals(appInfo.packageName)) {
10761 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10762 return;
10763 }
10764
Christopher Tate6fa95972009-06-05 18:43:55 -070010765 ProcessRecord proc = mBackupTarget.app;
10766 mBackupTarget = null;
10767 mBackupAppName = null;
10768
10769 // Not backing this app up any more; reset its OOM adjustment
10770 updateOomAdjLocked(proc);
10771
Christopher Tatec7b31e32009-06-10 15:49:30 -070010772 // If the app crashed during backup, 'thread' will be null here
10773 if (proc.thread != null) {
10774 try {
10775 proc.thread.scheduleDestroyBackupAgent(appInfo);
10776 } catch (Exception e) {
10777 Log.e(TAG, "Exception when unbinding backup agent:");
10778 e.printStackTrace();
10779 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010780 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010781 }
10782 }
10783 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010784 // BROADCASTS
10785 // =========================================================
10786
10787 private final List getStickies(String action, IntentFilter filter,
10788 List cur) {
10789 final ContentResolver resolver = mContext.getContentResolver();
10790 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10791 if (list == null) {
10792 return cur;
10793 }
10794 int N = list.size();
10795 for (int i=0; i<N; i++) {
10796 Intent intent = list.get(i);
10797 if (filter.match(resolver, intent, true, TAG) >= 0) {
10798 if (cur == null) {
10799 cur = new ArrayList<Intent>();
10800 }
10801 cur.add(intent);
10802 }
10803 }
10804 return cur;
10805 }
10806
10807 private final void scheduleBroadcastsLocked() {
10808 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10809 + mBroadcastsScheduled);
10810
10811 if (mBroadcastsScheduled) {
10812 return;
10813 }
10814 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10815 mBroadcastsScheduled = true;
10816 }
10817
10818 public Intent registerReceiver(IApplicationThread caller,
10819 IIntentReceiver receiver, IntentFilter filter, String permission) {
10820 synchronized(this) {
10821 ProcessRecord callerApp = null;
10822 if (caller != null) {
10823 callerApp = getRecordForAppLocked(caller);
10824 if (callerApp == null) {
10825 throw new SecurityException(
10826 "Unable to find app for caller " + caller
10827 + " (pid=" + Binder.getCallingPid()
10828 + ") when registering receiver " + receiver);
10829 }
10830 }
10831
10832 List allSticky = null;
10833
10834 // Look for any matching sticky broadcasts...
10835 Iterator actions = filter.actionsIterator();
10836 if (actions != null) {
10837 while (actions.hasNext()) {
10838 String action = (String)actions.next();
10839 allSticky = getStickies(action, filter, allSticky);
10840 }
10841 } else {
10842 allSticky = getStickies(null, filter, allSticky);
10843 }
10844
10845 // The first sticky in the list is returned directly back to
10846 // the client.
10847 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10848
10849 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10850 + ": " + sticky);
10851
10852 if (receiver == null) {
10853 return sticky;
10854 }
10855
10856 ReceiverList rl
10857 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10858 if (rl == null) {
10859 rl = new ReceiverList(this, callerApp,
10860 Binder.getCallingPid(),
10861 Binder.getCallingUid(), receiver);
10862 if (rl.app != null) {
10863 rl.app.receivers.add(rl);
10864 } else {
10865 try {
10866 receiver.asBinder().linkToDeath(rl, 0);
10867 } catch (RemoteException e) {
10868 return sticky;
10869 }
10870 rl.linkedToDeath = true;
10871 }
10872 mRegisteredReceivers.put(receiver.asBinder(), rl);
10873 }
10874 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10875 rl.add(bf);
10876 if (!bf.debugCheck()) {
10877 Log.w(TAG, "==> For Dynamic broadast");
10878 }
10879 mReceiverResolver.addFilter(bf);
10880
10881 // Enqueue broadcasts for all existing stickies that match
10882 // this filter.
10883 if (allSticky != null) {
10884 ArrayList receivers = new ArrayList();
10885 receivers.add(bf);
10886
10887 int N = allSticky.size();
10888 for (int i=0; i<N; i++) {
10889 Intent intent = (Intent)allSticky.get(i);
10890 BroadcastRecord r = new BroadcastRecord(intent, null,
10891 null, -1, -1, null, receivers, null, 0, null, null,
10892 false);
10893 if (mParallelBroadcasts.size() == 0) {
10894 scheduleBroadcastsLocked();
10895 }
10896 mParallelBroadcasts.add(r);
10897 }
10898 }
10899
10900 return sticky;
10901 }
10902 }
10903
10904 public void unregisterReceiver(IIntentReceiver receiver) {
10905 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10906
10907 boolean doNext = false;
10908
10909 synchronized(this) {
10910 ReceiverList rl
10911 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10912 if (rl != null) {
10913 if (rl.curBroadcast != null) {
10914 BroadcastRecord r = rl.curBroadcast;
10915 doNext = finishReceiverLocked(
10916 receiver.asBinder(), r.resultCode, r.resultData,
10917 r.resultExtras, r.resultAbort, true);
10918 }
10919
10920 if (rl.app != null) {
10921 rl.app.receivers.remove(rl);
10922 }
10923 removeReceiverLocked(rl);
10924 if (rl.linkedToDeath) {
10925 rl.linkedToDeath = false;
10926 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10927 }
10928 }
10929 }
10930
10931 if (!doNext) {
10932 return;
10933 }
10934
10935 final long origId = Binder.clearCallingIdentity();
10936 processNextBroadcast(false);
10937 trimApplications();
10938 Binder.restoreCallingIdentity(origId);
10939 }
10940
10941 void removeReceiverLocked(ReceiverList rl) {
10942 mRegisteredReceivers.remove(rl.receiver.asBinder());
10943 int N = rl.size();
10944 for (int i=0; i<N; i++) {
10945 mReceiverResolver.removeFilter(rl.get(i));
10946 }
10947 }
10948
10949 private final int broadcastIntentLocked(ProcessRecord callerApp,
10950 String callerPackage, Intent intent, String resolvedType,
10951 IIntentReceiver resultTo, int resultCode, String resultData,
10952 Bundle map, String requiredPermission,
10953 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10954 intent = new Intent(intent);
10955
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010956 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010957 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10958 + " ordered=" + ordered);
10959 if ((resultTo != null) && !ordered) {
10960 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10961 }
10962
10963 // Handle special intents: if this broadcast is from the package
10964 // manager about a package being removed, we need to remove all of
10965 // its activities from the history stack.
10966 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10967 intent.getAction());
10968 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10969 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10970 || uidRemoved) {
10971 if (checkComponentPermission(
10972 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10973 callingPid, callingUid, -1)
10974 == PackageManager.PERMISSION_GRANTED) {
10975 if (uidRemoved) {
10976 final Bundle intentExtras = intent.getExtras();
10977 final int uid = intentExtras != null
10978 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10979 if (uid >= 0) {
10980 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10981 synchronized (bs) {
10982 bs.removeUidStatsLocked(uid);
10983 }
10984 }
10985 } else {
10986 Uri data = intent.getData();
10987 String ssp;
10988 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10989 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10990 uninstallPackageLocked(ssp,
10991 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010992 AttributeCache ac = AttributeCache.instance();
10993 if (ac != null) {
10994 ac.removePackage(ssp);
10995 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010996 }
10997 }
10998 }
10999 } else {
11000 String msg = "Permission Denial: " + intent.getAction()
11001 + " broadcast from " + callerPackage + " (pid=" + callingPid
11002 + ", uid=" + callingUid + ")"
11003 + " requires "
11004 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11005 Log.w(TAG, msg);
11006 throw new SecurityException(msg);
11007 }
11008 }
11009
11010 /*
11011 * If this is the time zone changed action, queue up a message that will reset the timezone
11012 * of all currently running processes. This message will get queued up before the broadcast
11013 * happens.
11014 */
11015 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11016 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11017 }
11018
Dianne Hackborn854060af2009-07-09 18:14:31 -070011019 /*
11020 * Prevent non-system code (defined here to be non-persistent
11021 * processes) from sending protected broadcasts.
11022 */
11023 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11024 || callingUid == Process.SHELL_UID || callingUid == 0) {
11025 // Always okay.
11026 } else if (callerApp == null || !callerApp.persistent) {
11027 try {
11028 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11029 intent.getAction())) {
11030 String msg = "Permission Denial: not allowed to send broadcast "
11031 + intent.getAction() + " from pid="
11032 + callingPid + ", uid=" + callingUid;
11033 Log.w(TAG, msg);
11034 throw new SecurityException(msg);
11035 }
11036 } catch (RemoteException e) {
11037 Log.w(TAG, "Remote exception", e);
11038 return BROADCAST_SUCCESS;
11039 }
11040 }
11041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011042 // Add to the sticky list if requested.
11043 if (sticky) {
11044 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11045 callingPid, callingUid)
11046 != PackageManager.PERMISSION_GRANTED) {
11047 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11048 + callingPid + ", uid=" + callingUid
11049 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11050 Log.w(TAG, msg);
11051 throw new SecurityException(msg);
11052 }
11053 if (requiredPermission != null) {
11054 Log.w(TAG, "Can't broadcast sticky intent " + intent
11055 + " and enforce permission " + requiredPermission);
11056 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11057 }
11058 if (intent.getComponent() != null) {
11059 throw new SecurityException(
11060 "Sticky broadcasts can't target a specific component");
11061 }
11062 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11063 if (list == null) {
11064 list = new ArrayList<Intent>();
11065 mStickyBroadcasts.put(intent.getAction(), list);
11066 }
11067 int N = list.size();
11068 int i;
11069 for (i=0; i<N; i++) {
11070 if (intent.filterEquals(list.get(i))) {
11071 // This sticky already exists, replace it.
11072 list.set(i, new Intent(intent));
11073 break;
11074 }
11075 }
11076 if (i >= N) {
11077 list.add(new Intent(intent));
11078 }
11079 }
11080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011081 // Figure out who all will receive this broadcast.
11082 List receivers = null;
11083 List<BroadcastFilter> registeredReceivers = null;
11084 try {
11085 if (intent.getComponent() != null) {
11086 // Broadcast is going to one specific receiver class...
11087 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011088 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011089 if (ai != null) {
11090 receivers = new ArrayList();
11091 ResolveInfo ri = new ResolveInfo();
11092 ri.activityInfo = ai;
11093 receivers.add(ri);
11094 }
11095 } else {
11096 // Need to resolve the intent to interested receivers...
11097 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11098 == 0) {
11099 receivers =
11100 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011101 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011102 }
Mihai Preda074edef2009-05-18 17:13:31 +020011103 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011104 }
11105 } catch (RemoteException ex) {
11106 // pm is in same process, this will never happen.
11107 }
11108
11109 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11110 if (!ordered && NR > 0) {
11111 // If we are not serializing this broadcast, then send the
11112 // registered receivers separately so they don't wait for the
11113 // components to be launched.
11114 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11115 callerPackage, callingPid, callingUid, requiredPermission,
11116 registeredReceivers, resultTo, resultCode, resultData, map,
11117 ordered);
11118 if (DEBUG_BROADCAST) Log.v(
11119 TAG, "Enqueueing parallel broadcast " + r
11120 + ": prev had " + mParallelBroadcasts.size());
11121 mParallelBroadcasts.add(r);
11122 scheduleBroadcastsLocked();
11123 registeredReceivers = null;
11124 NR = 0;
11125 }
11126
11127 // Merge into one list.
11128 int ir = 0;
11129 if (receivers != null) {
11130 // A special case for PACKAGE_ADDED: do not allow the package
11131 // being added to see this broadcast. This prevents them from
11132 // using this as a back door to get run as soon as they are
11133 // installed. Maybe in the future we want to have a special install
11134 // broadcast or such for apps, but we'd like to deliberately make
11135 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011136 boolean skip = false;
11137 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011138 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011139 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11140 skip = true;
11141 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11142 skip = true;
11143 }
11144 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011145 ? intent.getData().getSchemeSpecificPart()
11146 : null;
11147 if (skipPackage != null && receivers != null) {
11148 int NT = receivers.size();
11149 for (int it=0; it<NT; it++) {
11150 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11151 if (curt.activityInfo.packageName.equals(skipPackage)) {
11152 receivers.remove(it);
11153 it--;
11154 NT--;
11155 }
11156 }
11157 }
11158
11159 int NT = receivers != null ? receivers.size() : 0;
11160 int it = 0;
11161 ResolveInfo curt = null;
11162 BroadcastFilter curr = null;
11163 while (it < NT && ir < NR) {
11164 if (curt == null) {
11165 curt = (ResolveInfo)receivers.get(it);
11166 }
11167 if (curr == null) {
11168 curr = registeredReceivers.get(ir);
11169 }
11170 if (curr.getPriority() >= curt.priority) {
11171 // Insert this broadcast record into the final list.
11172 receivers.add(it, curr);
11173 ir++;
11174 curr = null;
11175 it++;
11176 NT++;
11177 } else {
11178 // Skip to the next ResolveInfo in the final list.
11179 it++;
11180 curt = null;
11181 }
11182 }
11183 }
11184 while (ir < NR) {
11185 if (receivers == null) {
11186 receivers = new ArrayList();
11187 }
11188 receivers.add(registeredReceivers.get(ir));
11189 ir++;
11190 }
11191
11192 if ((receivers != null && receivers.size() > 0)
11193 || resultTo != null) {
11194 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11195 callerPackage, callingPid, callingUid, requiredPermission,
11196 receivers, resultTo, resultCode, resultData, map, ordered);
11197 if (DEBUG_BROADCAST) Log.v(
11198 TAG, "Enqueueing ordered broadcast " + r
11199 + ": prev had " + mOrderedBroadcasts.size());
11200 if (DEBUG_BROADCAST) {
11201 int seq = r.intent.getIntExtra("seq", -1);
11202 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11203 }
11204 mOrderedBroadcasts.add(r);
11205 scheduleBroadcastsLocked();
11206 }
11207
11208 return BROADCAST_SUCCESS;
11209 }
11210
11211 public final int broadcastIntent(IApplicationThread caller,
11212 Intent intent, String resolvedType, IIntentReceiver resultTo,
11213 int resultCode, String resultData, Bundle map,
11214 String requiredPermission, boolean serialized, boolean sticky) {
11215 // Refuse possible leaked file descriptors
11216 if (intent != null && intent.hasFileDescriptors() == true) {
11217 throw new IllegalArgumentException("File descriptors passed in Intent");
11218 }
11219
11220 synchronized(this) {
11221 if (!mSystemReady) {
11222 // if the caller really truly claims to know what they're doing, go
11223 // ahead and allow the broadcast without launching any receivers
11224 int flags = intent.getFlags();
11225 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11226 intent = new Intent(intent);
11227 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11228 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11229 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11230 + " before boot completion");
11231 throw new IllegalStateException("Cannot broadcast before boot completed");
11232 }
11233 }
11234
11235 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11236 final int callingPid = Binder.getCallingPid();
11237 final int callingUid = Binder.getCallingUid();
11238 final long origId = Binder.clearCallingIdentity();
11239 int res = broadcastIntentLocked(callerApp,
11240 callerApp != null ? callerApp.info.packageName : null,
11241 intent, resolvedType, resultTo,
11242 resultCode, resultData, map, requiredPermission, serialized,
11243 sticky, callingPid, callingUid);
11244 Binder.restoreCallingIdentity(origId);
11245 return res;
11246 }
11247 }
11248
11249 int broadcastIntentInPackage(String packageName, int uid,
11250 Intent intent, String resolvedType, IIntentReceiver resultTo,
11251 int resultCode, String resultData, Bundle map,
11252 String requiredPermission, boolean serialized, boolean sticky) {
11253 synchronized(this) {
11254 final long origId = Binder.clearCallingIdentity();
11255 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11256 resultTo, resultCode, resultData, map, requiredPermission,
11257 serialized, sticky, -1, uid);
11258 Binder.restoreCallingIdentity(origId);
11259 return res;
11260 }
11261 }
11262
11263 public final void unbroadcastIntent(IApplicationThread caller,
11264 Intent intent) {
11265 // Refuse possible leaked file descriptors
11266 if (intent != null && intent.hasFileDescriptors() == true) {
11267 throw new IllegalArgumentException("File descriptors passed in Intent");
11268 }
11269
11270 synchronized(this) {
11271 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11272 != PackageManager.PERMISSION_GRANTED) {
11273 String msg = "Permission Denial: unbroadcastIntent() from pid="
11274 + Binder.getCallingPid()
11275 + ", uid=" + Binder.getCallingUid()
11276 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11277 Log.w(TAG, msg);
11278 throw new SecurityException(msg);
11279 }
11280 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11281 if (list != null) {
11282 int N = list.size();
11283 int i;
11284 for (i=0; i<N; i++) {
11285 if (intent.filterEquals(list.get(i))) {
11286 list.remove(i);
11287 break;
11288 }
11289 }
11290 }
11291 }
11292 }
11293
11294 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11295 String resultData, Bundle resultExtras, boolean resultAbort,
11296 boolean explicit) {
11297 if (mOrderedBroadcasts.size() == 0) {
11298 if (explicit) {
11299 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11300 }
11301 return false;
11302 }
11303 BroadcastRecord r = mOrderedBroadcasts.get(0);
11304 if (r.receiver == null) {
11305 if (explicit) {
11306 Log.w(TAG, "finishReceiver called but none active");
11307 }
11308 return false;
11309 }
11310 if (r.receiver != receiver) {
11311 Log.w(TAG, "finishReceiver called but active receiver is different");
11312 return false;
11313 }
11314 int state = r.state;
11315 r.state = r.IDLE;
11316 if (state == r.IDLE) {
11317 if (explicit) {
11318 Log.w(TAG, "finishReceiver called but state is IDLE");
11319 }
11320 }
11321 r.receiver = null;
11322 r.intent.setComponent(null);
11323 if (r.curApp != null) {
11324 r.curApp.curReceiver = null;
11325 }
11326 if (r.curFilter != null) {
11327 r.curFilter.receiverList.curBroadcast = null;
11328 }
11329 r.curFilter = null;
11330 r.curApp = null;
11331 r.curComponent = null;
11332 r.curReceiver = null;
11333 mPendingBroadcast = null;
11334
11335 r.resultCode = resultCode;
11336 r.resultData = resultData;
11337 r.resultExtras = resultExtras;
11338 r.resultAbort = resultAbort;
11339
11340 // We will process the next receiver right now if this is finishing
11341 // an app receiver (which is always asynchronous) or after we have
11342 // come back from calling a receiver.
11343 return state == BroadcastRecord.APP_RECEIVE
11344 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11345 }
11346
11347 public void finishReceiver(IBinder who, int resultCode, String resultData,
11348 Bundle resultExtras, boolean resultAbort) {
11349 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11350
11351 // Refuse possible leaked file descriptors
11352 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11353 throw new IllegalArgumentException("File descriptors passed in Bundle");
11354 }
11355
11356 boolean doNext;
11357
11358 final long origId = Binder.clearCallingIdentity();
11359
11360 synchronized(this) {
11361 doNext = finishReceiverLocked(
11362 who, resultCode, resultData, resultExtras, resultAbort, true);
11363 }
11364
11365 if (doNext) {
11366 processNextBroadcast(false);
11367 }
11368 trimApplications();
11369
11370 Binder.restoreCallingIdentity(origId);
11371 }
11372
11373 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11374 if (r.nextReceiver > 0) {
11375 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11376 if (curReceiver instanceof BroadcastFilter) {
11377 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11378 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11379 System.identityHashCode(r),
11380 r.intent.getAction(),
11381 r.nextReceiver - 1,
11382 System.identityHashCode(bf));
11383 } else {
11384 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11385 System.identityHashCode(r),
11386 r.intent.getAction(),
11387 r.nextReceiver - 1,
11388 ((ResolveInfo)curReceiver).toString());
11389 }
11390 } else {
11391 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11392 + r);
11393 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11394 System.identityHashCode(r),
11395 r.intent.getAction(),
11396 r.nextReceiver,
11397 "NONE");
11398 }
11399 }
11400
11401 private final void broadcastTimeout() {
11402 synchronized (this) {
11403 if (mOrderedBroadcasts.size() == 0) {
11404 return;
11405 }
11406 long now = SystemClock.uptimeMillis();
11407 BroadcastRecord r = mOrderedBroadcasts.get(0);
11408 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11409 if (DEBUG_BROADCAST) Log.v(TAG,
11410 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11411 + (r.startTime + BROADCAST_TIMEOUT));
11412 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11413 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11414 return;
11415 }
11416
11417 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11418 r.startTime = now;
11419 r.anrCount++;
11420
11421 // Current receiver has passed its expiration date.
11422 if (r.nextReceiver <= 0) {
11423 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11424 return;
11425 }
11426
11427 ProcessRecord app = null;
11428
11429 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11430 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11431 logBroadcastReceiverDiscard(r);
11432 if (curReceiver instanceof BroadcastFilter) {
11433 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11434 if (bf.receiverList.pid != 0
11435 && bf.receiverList.pid != MY_PID) {
11436 synchronized (this.mPidsSelfLocked) {
11437 app = this.mPidsSelfLocked.get(
11438 bf.receiverList.pid);
11439 }
11440 }
11441 } else {
11442 app = r.curApp;
11443 }
11444
11445 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011446 appNotRespondingLocked(app, null, null,
11447 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011448 }
11449
11450 if (mPendingBroadcast == r) {
11451 mPendingBroadcast = null;
11452 }
11453
11454 // Move on to the next receiver.
11455 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11456 r.resultExtras, r.resultAbort, true);
11457 scheduleBroadcastsLocked();
11458 }
11459 }
11460
11461 private final void processCurBroadcastLocked(BroadcastRecord r,
11462 ProcessRecord app) throws RemoteException {
11463 if (app.thread == null) {
11464 throw new RemoteException();
11465 }
11466 r.receiver = app.thread.asBinder();
11467 r.curApp = app;
11468 app.curReceiver = r;
11469 updateLRUListLocked(app, true);
11470
11471 // Tell the application to launch this receiver.
11472 r.intent.setComponent(r.curComponent);
11473
11474 boolean started = false;
11475 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011476 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011477 "Delivering to component " + r.curComponent
11478 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011479 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011480 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11481 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11482 started = true;
11483 } finally {
11484 if (!started) {
11485 r.receiver = null;
11486 r.curApp = null;
11487 app.curReceiver = null;
11488 }
11489 }
11490
11491 }
11492
11493 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11494 Intent intent, int resultCode, String data,
11495 Bundle extras, boolean ordered) throws RemoteException {
11496 if (app != null && app.thread != null) {
11497 // If we have an app thread, do the call through that so it is
11498 // correctly ordered with other one-way calls.
11499 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11500 data, extras, ordered);
11501 } else {
11502 receiver.performReceive(intent, resultCode, data, extras, ordered);
11503 }
11504 }
11505
11506 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11507 BroadcastFilter filter, boolean ordered) {
11508 boolean skip = false;
11509 if (filter.requiredPermission != null) {
11510 int perm = checkComponentPermission(filter.requiredPermission,
11511 r.callingPid, r.callingUid, -1);
11512 if (perm != PackageManager.PERMISSION_GRANTED) {
11513 Log.w(TAG, "Permission Denial: broadcasting "
11514 + r.intent.toString()
11515 + " from " + r.callerPackage + " (pid="
11516 + r.callingPid + ", uid=" + r.callingUid + ")"
11517 + " requires " + filter.requiredPermission
11518 + " due to registered receiver " + filter);
11519 skip = true;
11520 }
11521 }
11522 if (r.requiredPermission != null) {
11523 int perm = checkComponentPermission(r.requiredPermission,
11524 filter.receiverList.pid, filter.receiverList.uid, -1);
11525 if (perm != PackageManager.PERMISSION_GRANTED) {
11526 Log.w(TAG, "Permission Denial: receiving "
11527 + r.intent.toString()
11528 + " to " + filter.receiverList.app
11529 + " (pid=" + filter.receiverList.pid
11530 + ", uid=" + filter.receiverList.uid + ")"
11531 + " requires " + r.requiredPermission
11532 + " due to sender " + r.callerPackage
11533 + " (uid " + r.callingUid + ")");
11534 skip = true;
11535 }
11536 }
11537
11538 if (!skip) {
11539 // If this is not being sent as an ordered broadcast, then we
11540 // don't want to touch the fields that keep track of the current
11541 // state of ordered broadcasts.
11542 if (ordered) {
11543 r.receiver = filter.receiverList.receiver.asBinder();
11544 r.curFilter = filter;
11545 filter.receiverList.curBroadcast = r;
11546 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011547 if (filter.receiverList.app != null) {
11548 // Bump hosting application to no longer be in background
11549 // scheduling class. Note that we can't do that if there
11550 // isn't an app... but we can only be in that case for
11551 // things that directly call the IActivityManager API, which
11552 // are already core system stuff so don't matter for this.
11553 r.curApp = filter.receiverList.app;
11554 filter.receiverList.app.curReceiver = r;
11555 updateOomAdjLocked();
11556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011557 }
11558 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011559 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011560 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011561 Log.i(TAG, "Delivering to " + filter.receiverList.app
11562 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011563 }
11564 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11565 new Intent(r.intent), r.resultCode,
11566 r.resultData, r.resultExtras, r.ordered);
11567 if (ordered) {
11568 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11569 }
11570 } catch (RemoteException e) {
11571 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11572 if (ordered) {
11573 r.receiver = null;
11574 r.curFilter = null;
11575 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011576 if (filter.receiverList.app != null) {
11577 filter.receiverList.app.curReceiver = null;
11578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011579 }
11580 }
11581 }
11582 }
11583
11584 private final void processNextBroadcast(boolean fromMsg) {
11585 synchronized(this) {
11586 BroadcastRecord r;
11587
11588 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11589 + mParallelBroadcasts.size() + " broadcasts, "
11590 + mOrderedBroadcasts.size() + " serialized broadcasts");
11591
11592 updateCpuStats();
11593
11594 if (fromMsg) {
11595 mBroadcastsScheduled = false;
11596 }
11597
11598 // First, deliver any non-serialized broadcasts right away.
11599 while (mParallelBroadcasts.size() > 0) {
11600 r = mParallelBroadcasts.remove(0);
11601 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011602 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11603 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011604 for (int i=0; i<N; i++) {
11605 Object target = r.receivers.get(i);
11606 if (DEBUG_BROADCAST) Log.v(TAG,
11607 "Delivering non-serialized to registered "
11608 + target + ": " + r);
11609 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11610 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011611 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11612 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011613 }
11614
11615 // Now take care of the next serialized one...
11616
11617 // If we are waiting for a process to come up to handle the next
11618 // broadcast, then do nothing at this point. Just in case, we
11619 // check that the process we're waiting for still exists.
11620 if (mPendingBroadcast != null) {
11621 Log.i(TAG, "processNextBroadcast: waiting for "
11622 + mPendingBroadcast.curApp);
11623
11624 boolean isDead;
11625 synchronized (mPidsSelfLocked) {
11626 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11627 }
11628 if (!isDead) {
11629 // It's still alive, so keep waiting
11630 return;
11631 } else {
11632 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11633 + " died before responding to broadcast");
11634 mPendingBroadcast = null;
11635 }
11636 }
11637
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011638 boolean looped = false;
11639
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011640 do {
11641 if (mOrderedBroadcasts.size() == 0) {
11642 // No more broadcasts pending, so all done!
11643 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011644 if (looped) {
11645 // If we had finished the last ordered broadcast, then
11646 // make sure all processes have correct oom and sched
11647 // adjustments.
11648 updateOomAdjLocked();
11649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011650 return;
11651 }
11652 r = mOrderedBroadcasts.get(0);
11653 boolean forceReceive = false;
11654
11655 // Ensure that even if something goes awry with the timeout
11656 // detection, we catch "hung" broadcasts here, discard them,
11657 // and continue to make progress.
11658 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11659 long now = SystemClock.uptimeMillis();
11660 if (r.dispatchTime > 0) {
11661 if ((numReceivers > 0) &&
11662 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11663 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11664 + " now=" + now
11665 + " dispatchTime=" + r.dispatchTime
11666 + " startTime=" + r.startTime
11667 + " intent=" + r.intent
11668 + " numReceivers=" + numReceivers
11669 + " nextReceiver=" + r.nextReceiver
11670 + " state=" + r.state);
11671 broadcastTimeout(); // forcibly finish this broadcast
11672 forceReceive = true;
11673 r.state = BroadcastRecord.IDLE;
11674 }
11675 }
11676
11677 if (r.state != BroadcastRecord.IDLE) {
11678 if (DEBUG_BROADCAST) Log.d(TAG,
11679 "processNextBroadcast() called when not idle (state="
11680 + r.state + ")");
11681 return;
11682 }
11683
11684 if (r.receivers == null || r.nextReceiver >= numReceivers
11685 || r.resultAbort || forceReceive) {
11686 // No more receivers for this broadcast! Send the final
11687 // result if requested...
11688 if (r.resultTo != null) {
11689 try {
11690 if (DEBUG_BROADCAST) {
11691 int seq = r.intent.getIntExtra("seq", -1);
11692 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11693 + " seq=" + seq + " app=" + r.callerApp);
11694 }
11695 performReceive(r.callerApp, r.resultTo,
11696 new Intent(r.intent), r.resultCode,
11697 r.resultData, r.resultExtras, false);
11698 } catch (RemoteException e) {
11699 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11700 }
11701 }
11702
11703 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11704 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11705
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011706 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11707 + r);
11708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011709 // ... and on to the next...
11710 mOrderedBroadcasts.remove(0);
11711 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011712 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011713 continue;
11714 }
11715 } while (r == null);
11716
11717 // Get the next receiver...
11718 int recIdx = r.nextReceiver++;
11719
11720 // Keep track of when this receiver started, and make sure there
11721 // is a timeout message pending to kill it if need be.
11722 r.startTime = SystemClock.uptimeMillis();
11723 if (recIdx == 0) {
11724 r.dispatchTime = r.startTime;
11725
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011726 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11727 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011728 if (DEBUG_BROADCAST) Log.v(TAG,
11729 "Submitting BROADCAST_TIMEOUT_MSG for "
11730 + (r.startTime + BROADCAST_TIMEOUT));
11731 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11732 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11733 }
11734
11735 Object nextReceiver = r.receivers.get(recIdx);
11736 if (nextReceiver instanceof BroadcastFilter) {
11737 // Simple case: this is a registered receiver who gets
11738 // a direct call.
11739 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11740 if (DEBUG_BROADCAST) Log.v(TAG,
11741 "Delivering serialized to registered "
11742 + filter + ": " + r);
11743 deliverToRegisteredReceiver(r, filter, r.ordered);
11744 if (r.receiver == null || !r.ordered) {
11745 // The receiver has already finished, so schedule to
11746 // process the next one.
11747 r.state = BroadcastRecord.IDLE;
11748 scheduleBroadcastsLocked();
11749 }
11750 return;
11751 }
11752
11753 // Hard case: need to instantiate the receiver, possibly
11754 // starting its application process to host it.
11755
11756 ResolveInfo info =
11757 (ResolveInfo)nextReceiver;
11758
11759 boolean skip = false;
11760 int perm = checkComponentPermission(info.activityInfo.permission,
11761 r.callingPid, r.callingUid,
11762 info.activityInfo.exported
11763 ? -1 : info.activityInfo.applicationInfo.uid);
11764 if (perm != PackageManager.PERMISSION_GRANTED) {
11765 Log.w(TAG, "Permission Denial: broadcasting "
11766 + r.intent.toString()
11767 + " from " + r.callerPackage + " (pid=" + r.callingPid
11768 + ", uid=" + r.callingUid + ")"
11769 + " requires " + info.activityInfo.permission
11770 + " due to receiver " + info.activityInfo.packageName
11771 + "/" + info.activityInfo.name);
11772 skip = true;
11773 }
11774 if (r.callingUid != Process.SYSTEM_UID &&
11775 r.requiredPermission != null) {
11776 try {
11777 perm = ActivityThread.getPackageManager().
11778 checkPermission(r.requiredPermission,
11779 info.activityInfo.applicationInfo.packageName);
11780 } catch (RemoteException e) {
11781 perm = PackageManager.PERMISSION_DENIED;
11782 }
11783 if (perm != PackageManager.PERMISSION_GRANTED) {
11784 Log.w(TAG, "Permission Denial: receiving "
11785 + r.intent + " to "
11786 + info.activityInfo.applicationInfo.packageName
11787 + " requires " + r.requiredPermission
11788 + " due to sender " + r.callerPackage
11789 + " (uid " + r.callingUid + ")");
11790 skip = true;
11791 }
11792 }
11793 if (r.curApp != null && r.curApp.crashing) {
11794 // If the target process is crashing, just skip it.
11795 skip = true;
11796 }
11797
11798 if (skip) {
11799 r.receiver = null;
11800 r.curFilter = null;
11801 r.state = BroadcastRecord.IDLE;
11802 scheduleBroadcastsLocked();
11803 return;
11804 }
11805
11806 r.state = BroadcastRecord.APP_RECEIVE;
11807 String targetProcess = info.activityInfo.processName;
11808 r.curComponent = new ComponentName(
11809 info.activityInfo.applicationInfo.packageName,
11810 info.activityInfo.name);
11811 r.curReceiver = info.activityInfo;
11812
11813 // Is this receiver's application already running?
11814 ProcessRecord app = getProcessRecordLocked(targetProcess,
11815 info.activityInfo.applicationInfo.uid);
11816 if (app != null && app.thread != null) {
11817 try {
11818 processCurBroadcastLocked(r, app);
11819 return;
11820 } catch (RemoteException e) {
11821 Log.w(TAG, "Exception when sending broadcast to "
11822 + r.curComponent, e);
11823 }
11824
11825 // If a dead object exception was thrown -- fall through to
11826 // restart the application.
11827 }
11828
11829 // Not running -- get it started, and enqueue this history record
11830 // to be executed when the app comes up.
11831 if ((r.curApp=startProcessLocked(targetProcess,
11832 info.activityInfo.applicationInfo, true,
11833 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11834 "broadcast", r.curComponent)) == null) {
11835 // Ah, this recipient is unavailable. Finish it if necessary,
11836 // and mark the broadcast record as ready for the next.
11837 Log.w(TAG, "Unable to launch app "
11838 + info.activityInfo.applicationInfo.packageName + "/"
11839 + info.activityInfo.applicationInfo.uid + " for broadcast "
11840 + r.intent + ": process is bad");
11841 logBroadcastReceiverDiscard(r);
11842 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11843 r.resultExtras, r.resultAbort, true);
11844 scheduleBroadcastsLocked();
11845 r.state = BroadcastRecord.IDLE;
11846 return;
11847 }
11848
11849 mPendingBroadcast = r;
11850 }
11851 }
11852
11853 // =========================================================
11854 // INSTRUMENTATION
11855 // =========================================================
11856
11857 public boolean startInstrumentation(ComponentName className,
11858 String profileFile, int flags, Bundle arguments,
11859 IInstrumentationWatcher watcher) {
11860 // Refuse possible leaked file descriptors
11861 if (arguments != null && arguments.hasFileDescriptors()) {
11862 throw new IllegalArgumentException("File descriptors passed in Bundle");
11863 }
11864
11865 synchronized(this) {
11866 InstrumentationInfo ii = null;
11867 ApplicationInfo ai = null;
11868 try {
11869 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011870 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011871 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011872 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011873 } catch (PackageManager.NameNotFoundException e) {
11874 }
11875 if (ii == null) {
11876 reportStartInstrumentationFailure(watcher, className,
11877 "Unable to find instrumentation info for: " + className);
11878 return false;
11879 }
11880 if (ai == null) {
11881 reportStartInstrumentationFailure(watcher, className,
11882 "Unable to find instrumentation target package: " + ii.targetPackage);
11883 return false;
11884 }
11885
11886 int match = mContext.getPackageManager().checkSignatures(
11887 ii.targetPackage, ii.packageName);
11888 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11889 String msg = "Permission Denial: starting instrumentation "
11890 + className + " from pid="
11891 + Binder.getCallingPid()
11892 + ", uid=" + Binder.getCallingPid()
11893 + " not allowed because package " + ii.packageName
11894 + " does not have a signature matching the target "
11895 + ii.targetPackage;
11896 reportStartInstrumentationFailure(watcher, className, msg);
11897 throw new SecurityException(msg);
11898 }
11899
11900 final long origId = Binder.clearCallingIdentity();
11901 uninstallPackageLocked(ii.targetPackage, -1, true);
11902 ProcessRecord app = addAppLocked(ai);
11903 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011904 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011905 app.instrumentationProfileFile = profileFile;
11906 app.instrumentationArguments = arguments;
11907 app.instrumentationWatcher = watcher;
11908 app.instrumentationResultClass = className;
11909 Binder.restoreCallingIdentity(origId);
11910 }
11911
11912 return true;
11913 }
11914
11915 /**
11916 * Report errors that occur while attempting to start Instrumentation. Always writes the
11917 * error to the logs, but if somebody is watching, send the report there too. This enables
11918 * the "am" command to report errors with more information.
11919 *
11920 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11921 * @param cn The component name of the instrumentation.
11922 * @param report The error report.
11923 */
11924 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11925 ComponentName cn, String report) {
11926 Log.w(TAG, report);
11927 try {
11928 if (watcher != null) {
11929 Bundle results = new Bundle();
11930 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11931 results.putString("Error", report);
11932 watcher.instrumentationStatus(cn, -1, results);
11933 }
11934 } catch (RemoteException e) {
11935 Log.w(TAG, e);
11936 }
11937 }
11938
11939 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11940 if (app.instrumentationWatcher != null) {
11941 try {
11942 // NOTE: IInstrumentationWatcher *must* be oneway here
11943 app.instrumentationWatcher.instrumentationFinished(
11944 app.instrumentationClass,
11945 resultCode,
11946 results);
11947 } catch (RemoteException e) {
11948 }
11949 }
11950 app.instrumentationWatcher = null;
11951 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011952 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011953 app.instrumentationProfileFile = null;
11954 app.instrumentationArguments = null;
11955
11956 uninstallPackageLocked(app.processName, -1, false);
11957 }
11958
11959 public void finishInstrumentation(IApplicationThread target,
11960 int resultCode, Bundle results) {
11961 // Refuse possible leaked file descriptors
11962 if (results != null && results.hasFileDescriptors()) {
11963 throw new IllegalArgumentException("File descriptors passed in Intent");
11964 }
11965
11966 synchronized(this) {
11967 ProcessRecord app = getRecordForAppLocked(target);
11968 if (app == null) {
11969 Log.w(TAG, "finishInstrumentation: no app for " + target);
11970 return;
11971 }
11972 final long origId = Binder.clearCallingIdentity();
11973 finishInstrumentationLocked(app, resultCode, results);
11974 Binder.restoreCallingIdentity(origId);
11975 }
11976 }
11977
11978 // =========================================================
11979 // CONFIGURATION
11980 // =========================================================
11981
11982 public ConfigurationInfo getDeviceConfigurationInfo() {
11983 ConfigurationInfo config = new ConfigurationInfo();
11984 synchronized (this) {
11985 config.reqTouchScreen = mConfiguration.touchscreen;
11986 config.reqKeyboardType = mConfiguration.keyboard;
11987 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011988 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
11989 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011990 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11991 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070011992 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
11993 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011994 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11995 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070011996 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011997 }
11998 return config;
11999 }
12000
12001 public Configuration getConfiguration() {
12002 Configuration ci;
12003 synchronized(this) {
12004 ci = new Configuration(mConfiguration);
12005 }
12006 return ci;
12007 }
12008
12009 public void updateConfiguration(Configuration values) {
12010 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12011 "updateConfiguration()");
12012
12013 synchronized(this) {
12014 if (values == null && mWindowManager != null) {
12015 // sentinel: fetch the current configuration from the window manager
12016 values = mWindowManager.computeNewConfiguration();
12017 }
12018
12019 final long origId = Binder.clearCallingIdentity();
12020 updateConfigurationLocked(values, null);
12021 Binder.restoreCallingIdentity(origId);
12022 }
12023 }
12024
12025 /**
12026 * Do either or both things: (1) change the current configuration, and (2)
12027 * make sure the given activity is running with the (now) current
12028 * configuration. Returns true if the activity has been left running, or
12029 * false if <var>starting</var> is being destroyed to match the new
12030 * configuration.
12031 */
12032 public boolean updateConfigurationLocked(Configuration values,
12033 HistoryRecord starting) {
12034 int changes = 0;
12035
12036 boolean kept = true;
12037
12038 if (values != null) {
12039 Configuration newConfig = new Configuration(mConfiguration);
12040 changes = newConfig.updateFrom(values);
12041 if (changes != 0) {
12042 if (DEBUG_SWITCH) {
12043 Log.i(TAG, "Updating configuration to: " + values);
12044 }
12045
12046 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12047
12048 if (values.locale != null) {
12049 saveLocaleLocked(values.locale,
12050 !values.locale.equals(mConfiguration.locale),
12051 values.userSetLocale);
12052 }
12053
12054 mConfiguration = newConfig;
12055
12056 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12057 msg.obj = new Configuration(mConfiguration);
12058 mHandler.sendMessage(msg);
12059
12060 final int N = mLRUProcesses.size();
12061 for (int i=0; i<N; i++) {
12062 ProcessRecord app = mLRUProcesses.get(i);
12063 try {
12064 if (app.thread != null) {
12065 app.thread.scheduleConfigurationChanged(mConfiguration);
12066 }
12067 } catch (Exception e) {
12068 }
12069 }
12070 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12071 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12072 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012073
12074 AttributeCache ac = AttributeCache.instance();
12075 if (ac != null) {
12076 ac.updateConfiguration(mConfiguration);
12077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012078 }
12079 }
12080
12081 if (changes != 0 && starting == null) {
12082 // If the configuration changed, and the caller is not already
12083 // in the process of starting an activity, then find the top
12084 // activity to check if its configuration needs to change.
12085 starting = topRunningActivityLocked(null);
12086 }
12087
12088 if (starting != null) {
12089 kept = ensureActivityConfigurationLocked(starting, changes);
12090 if (kept) {
12091 // If this didn't result in the starting activity being
12092 // destroyed, then we need to make sure at this point that all
12093 // other activities are made visible.
12094 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12095 + ", ensuring others are correct.");
12096 ensureActivitiesVisibleLocked(starting, changes);
12097 }
12098 }
12099
12100 return kept;
12101 }
12102
12103 private final boolean relaunchActivityLocked(HistoryRecord r,
12104 int changes, boolean andResume) {
12105 List<ResultInfo> results = null;
12106 List<Intent> newIntents = null;
12107 if (andResume) {
12108 results = r.results;
12109 newIntents = r.newIntents;
12110 }
12111 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12112 + " with results=" + results + " newIntents=" + newIntents
12113 + " andResume=" + andResume);
12114 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12115 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12116 r.task.taskId, r.shortComponentName);
12117
12118 r.startFreezingScreenLocked(r.app, 0);
12119
12120 try {
12121 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12122 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12123 changes, !andResume);
12124 // Note: don't need to call pauseIfSleepingLocked() here, because
12125 // the caller will only pass in 'andResume' if this activity is
12126 // currently resumed, which implies we aren't sleeping.
12127 } catch (RemoteException e) {
12128 return false;
12129 }
12130
12131 if (andResume) {
12132 r.results = null;
12133 r.newIntents = null;
12134 }
12135
12136 return true;
12137 }
12138
12139 /**
12140 * Make sure the given activity matches the current configuration. Returns
12141 * false if the activity had to be destroyed. Returns true if the
12142 * configuration is the same, or the activity will remain running as-is
12143 * for whatever reason. Ensures the HistoryRecord is updated with the
12144 * correct configuration and all other bookkeeping is handled.
12145 */
12146 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12147 int globalChanges) {
12148 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12149
12150 // Short circuit: if the two configurations are the exact same
12151 // object (the common case), then there is nothing to do.
12152 Configuration newConfig = mConfiguration;
12153 if (r.configuration == newConfig) {
12154 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12155 return true;
12156 }
12157
12158 // We don't worry about activities that are finishing.
12159 if (r.finishing) {
12160 if (DEBUG_SWITCH) Log.i(TAG,
12161 "Configuration doesn't matter in finishing " + r);
12162 r.stopFreezingScreenLocked(false);
12163 return true;
12164 }
12165
12166 // Okay we now are going to make this activity have the new config.
12167 // But then we need to figure out how it needs to deal with that.
12168 Configuration oldConfig = r.configuration;
12169 r.configuration = newConfig;
12170
12171 // If the activity isn't currently running, just leave the new
12172 // configuration and it will pick that up next time it starts.
12173 if (r.app == null || r.app.thread == null) {
12174 if (DEBUG_SWITCH) Log.i(TAG,
12175 "Configuration doesn't matter not running " + r);
12176 r.stopFreezingScreenLocked(false);
12177 return true;
12178 }
12179
12180 // If the activity isn't persistent, there is a chance we will
12181 // need to restart it.
12182 if (!r.persistent) {
12183
12184 // Figure out what has changed between the two configurations.
12185 int changes = oldConfig.diff(newConfig);
12186 if (DEBUG_SWITCH) {
12187 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12188 + Integer.toHexString(changes) + ", handles=0x"
12189 + Integer.toHexString(r.info.configChanges));
12190 }
12191 if ((changes&(~r.info.configChanges)) != 0) {
12192 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12193 r.configChangeFlags |= changes;
12194 r.startFreezingScreenLocked(r.app, globalChanges);
12195 if (r.app == null || r.app.thread == null) {
12196 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12197 destroyActivityLocked(r, true);
12198 } else if (r.state == ActivityState.PAUSING) {
12199 // A little annoying: we are waiting for this activity to
12200 // finish pausing. Let's not do anything now, but just
12201 // flag that it needs to be restarted when done pausing.
12202 r.configDestroy = true;
12203 return true;
12204 } else if (r.state == ActivityState.RESUMED) {
12205 // Try to optimize this case: the configuration is changing
12206 // and we need to restart the top, resumed activity.
12207 // Instead of doing the normal handshaking, just say
12208 // "restart!".
12209 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12210 relaunchActivityLocked(r, r.configChangeFlags, true);
12211 r.configChangeFlags = 0;
12212 } else {
12213 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12214 relaunchActivityLocked(r, r.configChangeFlags, false);
12215 r.configChangeFlags = 0;
12216 }
12217
12218 // All done... tell the caller we weren't able to keep this
12219 // activity around.
12220 return false;
12221 }
12222 }
12223
12224 // Default case: the activity can handle this new configuration, so
12225 // hand it over. Note that we don't need to give it the new
12226 // configuration, since we always send configuration changes to all
12227 // process when they happen so it can just use whatever configuration
12228 // it last got.
12229 if (r.app != null && r.app.thread != null) {
12230 try {
12231 r.app.thread.scheduleActivityConfigurationChanged(r);
12232 } catch (RemoteException e) {
12233 // If process died, whatever.
12234 }
12235 }
12236 r.stopFreezingScreenLocked(false);
12237
12238 return true;
12239 }
12240
12241 /**
12242 * Save the locale. You must be inside a synchronized (this) block.
12243 */
12244 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12245 if(isDiff) {
12246 SystemProperties.set("user.language", l.getLanguage());
12247 SystemProperties.set("user.region", l.getCountry());
12248 }
12249
12250 if(isPersist) {
12251 SystemProperties.set("persist.sys.language", l.getLanguage());
12252 SystemProperties.set("persist.sys.country", l.getCountry());
12253 SystemProperties.set("persist.sys.localevar", l.getVariant());
12254 }
12255 }
12256
12257 // =========================================================
12258 // LIFETIME MANAGEMENT
12259 // =========================================================
12260
12261 private final int computeOomAdjLocked(
12262 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12263 if (mAdjSeq == app.adjSeq) {
12264 // This adjustment has already been computed.
12265 return app.curAdj;
12266 }
12267
12268 if (app.thread == null) {
12269 app.adjSeq = mAdjSeq;
12270 return (app.curAdj=EMPTY_APP_ADJ);
12271 }
12272
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012273 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12274 // The max adjustment doesn't allow this app to be anything
12275 // below foreground, so it is not worth doing work for it.
12276 app.adjType = "fixed";
12277 app.adjSeq = mAdjSeq;
12278 app.curRawAdj = app.maxAdj;
12279 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12280 return (app.curAdj=app.maxAdj);
12281 }
12282
12283 app.adjSource = null;
12284 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012285
The Android Open Source Project4df24232009-03-05 14:34:35 -080012286 // Determine the importance of the process, starting with most
12287 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012288 int adj;
12289 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012290 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012291 // The last app on the list is the foreground app.
12292 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012293 app.adjType = "top";
12294 } else if (app.instrumentationClass != null) {
12295 // Don't want to kill running instrumentation.
12296 adj = FOREGROUND_APP_ADJ;
12297 app.adjType = "instr";
12298 } else if (app.persistentActivities > 0) {
12299 // Special persistent activities... shouldn't be used these days.
12300 adj = FOREGROUND_APP_ADJ;
12301 app.adjType = "pers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012302 } else if (app.curReceiver != null ||
12303 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12304 // An app that is currently receiving a broadcast also
12305 // counts as being in the foreground.
12306 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012307 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012308 } else if (app.executingServices.size() > 0) {
12309 // An app that is currently executing a service callback also
12310 // counts as being in the foreground.
12311 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012312 app.adjType = "exec-service";
12313 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012314 // The user is aware of this app, so make it visible.
12315 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012316 app.adjType = "foreground-service";
12317 } else if (app.forcingToForeground != null) {
12318 // The user is aware of this app, so make it visible.
12319 adj = VISIBLE_APP_ADJ;
12320 app.adjType = "force-foreground";
12321 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012322 } else if (app == mHomeProcess) {
12323 // This process is hosting what we currently consider to be the
12324 // home app, so we don't want to let it go into the background.
12325 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012326 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012327 } else if ((N=app.activities.size()) != 0) {
12328 // This app is in the background with paused activities.
12329 adj = hiddenAdj;
12330 for (int j=0; j<N; j++) {
12331 if (((HistoryRecord)app.activities.get(j)).visible) {
12332 // This app has a visible activity!
12333 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012334 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012335 break;
12336 }
12337 }
12338 } else {
12339 // A very not-needed process.
12340 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012341 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012342 }
12343
The Android Open Source Project4df24232009-03-05 14:34:35 -080012344 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012345 // there are applications dependent on our services or providers, but
12346 // this gives us a baseline and makes sure we don't get into an
12347 // infinite recursion.
12348 app.adjSeq = mAdjSeq;
12349 app.curRawAdj = adj;
12350 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12351
Christopher Tate6fa95972009-06-05 18:43:55 -070012352 if (mBackupTarget != null && app == mBackupTarget.app) {
12353 // If possible we want to avoid killing apps while they're being backed up
12354 if (adj > BACKUP_APP_ADJ) {
12355 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12356 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012357 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012358 }
12359 }
12360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012361 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12362 // If this process has active services running in it, we would
12363 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012364 // application from running. By default we put the process in
12365 // with the rest of the background processes; as we scan through
12366 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012367 if (adj > hiddenAdj) {
12368 adj = hiddenAdj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012369 app.adjType = "services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012370 }
12371 final long now = SystemClock.uptimeMillis();
12372 // This process is more important if the top activity is
12373 // bound to the service.
12374 Iterator jt = app.services.iterator();
12375 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12376 ServiceRecord s = (ServiceRecord)jt.next();
12377 if (s.startRequested) {
12378 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12379 // This service has seen some activity within
12380 // recent memory, so we will keep its process ahead
12381 // of the background processes.
12382 if (adj > SECONDARY_SERVER_ADJ) {
12383 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012384 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012385 }
12386 }
12387 }
12388 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12389 Iterator<ConnectionRecord> kt
12390 = s.connections.values().iterator();
12391 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12392 // XXX should compute this based on the max of
12393 // all connected clients.
12394 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012395 if (cr.binding.client == app) {
12396 // Binding to ourself is not interesting.
12397 continue;
12398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012399 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12400 ProcessRecord client = cr.binding.client;
12401 int myHiddenAdj = hiddenAdj;
12402 if (myHiddenAdj > client.hiddenAdj) {
12403 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12404 myHiddenAdj = client.hiddenAdj;
12405 } else {
12406 myHiddenAdj = VISIBLE_APP_ADJ;
12407 }
12408 }
12409 int clientAdj = computeOomAdjLocked(
12410 client, myHiddenAdj, TOP_APP);
12411 if (adj > clientAdj) {
12412 adj = clientAdj > VISIBLE_APP_ADJ
12413 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012414 app.adjType = "service";
12415 app.adjSource = cr.binding.client;
12416 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012417 }
12418 }
12419 HistoryRecord a = cr.activity;
12420 //if (a != null) {
12421 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12422 //}
12423 if (a != null && adj > FOREGROUND_APP_ADJ &&
12424 (a.state == ActivityState.RESUMED
12425 || a.state == ActivityState.PAUSING)) {
12426 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012427 app.adjType = "service";
12428 app.adjSource = a;
12429 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012430 }
12431 }
12432 }
12433 }
12434 }
12435
12436 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12437 // If this process has published any content providers, then
12438 // its adjustment makes it at least as important as any of the
12439 // processes using those providers, and no less important than
12440 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12441 if (adj > CONTENT_PROVIDER_ADJ) {
12442 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012443 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012444 }
12445 Iterator jt = app.pubProviders.values().iterator();
12446 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12447 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12448 if (cpr.clients.size() != 0) {
12449 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12450 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12451 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012452 if (client == app) {
12453 // Being our own client is not interesting.
12454 continue;
12455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012456 int myHiddenAdj = hiddenAdj;
12457 if (myHiddenAdj > client.hiddenAdj) {
12458 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12459 myHiddenAdj = client.hiddenAdj;
12460 } else {
12461 myHiddenAdj = FOREGROUND_APP_ADJ;
12462 }
12463 }
12464 int clientAdj = computeOomAdjLocked(
12465 client, myHiddenAdj, TOP_APP);
12466 if (adj > clientAdj) {
12467 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012468 ? clientAdj : FOREGROUND_APP_ADJ;
12469 app.adjType = "provider";
12470 app.adjSource = client;
12471 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012472 }
12473 }
12474 }
12475 // If the provider has external (non-framework) process
12476 // dependencies, ensure that its adjustment is at least
12477 // FOREGROUND_APP_ADJ.
12478 if (cpr.externals != 0) {
12479 if (adj > FOREGROUND_APP_ADJ) {
12480 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012481 app.adjType = "provider";
12482 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012483 }
12484 }
12485 }
12486 }
12487
12488 app.curRawAdj = adj;
12489
12490 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12491 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12492 if (adj > app.maxAdj) {
12493 adj = app.maxAdj;
12494 }
12495
12496 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012497 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012498 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12499 : Process.THREAD_GROUP_DEFAULT;
12500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012501 return adj;
12502 }
12503
12504 /**
12505 * Ask a given process to GC right now.
12506 */
12507 final void performAppGcLocked(ProcessRecord app) {
12508 try {
12509 app.lastRequestedGc = SystemClock.uptimeMillis();
12510 if (app.thread != null) {
12511 app.thread.processInBackground();
12512 }
12513 } catch (Exception e) {
12514 // whatever.
12515 }
12516 }
12517
12518 /**
12519 * Returns true if things are idle enough to perform GCs.
12520 */
12521 private final boolean canGcNow() {
12522 return mParallelBroadcasts.size() == 0
12523 && mOrderedBroadcasts.size() == 0
12524 && (mSleeping || (mResumedActivity != null &&
12525 mResumedActivity.idle));
12526 }
12527
12528 /**
12529 * Perform GCs on all processes that are waiting for it, but only
12530 * if things are idle.
12531 */
12532 final void performAppGcsLocked() {
12533 final int N = mProcessesToGc.size();
12534 if (N <= 0) {
12535 return;
12536 }
12537 if (canGcNow()) {
12538 while (mProcessesToGc.size() > 0) {
12539 ProcessRecord proc = mProcessesToGc.remove(0);
12540 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12541 // To avoid spamming the system, we will GC processes one
12542 // at a time, waiting a few seconds between each.
12543 performAppGcLocked(proc);
12544 scheduleAppGcsLocked();
12545 return;
12546 }
12547 }
12548 }
12549 }
12550
12551 /**
12552 * If all looks good, perform GCs on all processes waiting for them.
12553 */
12554 final void performAppGcsIfAppropriateLocked() {
12555 if (canGcNow()) {
12556 performAppGcsLocked();
12557 return;
12558 }
12559 // Still not idle, wait some more.
12560 scheduleAppGcsLocked();
12561 }
12562
12563 /**
12564 * Schedule the execution of all pending app GCs.
12565 */
12566 final void scheduleAppGcsLocked() {
12567 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12568 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12569 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12570 }
12571
12572 /**
12573 * Set up to ask a process to GC itself. This will either do it
12574 * immediately, or put it on the list of processes to gc the next
12575 * time things are idle.
12576 */
12577 final void scheduleAppGcLocked(ProcessRecord app) {
12578 long now = SystemClock.uptimeMillis();
12579 if ((app.lastRequestedGc+5000) > now) {
12580 return;
12581 }
12582 if (!mProcessesToGc.contains(app)) {
12583 mProcessesToGc.add(app);
12584 scheduleAppGcsLocked();
12585 }
12586 }
12587
12588 private final boolean updateOomAdjLocked(
12589 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12590 app.hiddenAdj = hiddenAdj;
12591
12592 if (app.thread == null) {
12593 return true;
12594 }
12595
12596 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012598 if (app.pid != 0 && app.pid != MY_PID) {
12599 if (app.curRawAdj != app.setRawAdj) {
12600 if (app.curRawAdj > FOREGROUND_APP_ADJ
12601 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12602 // If this app is transitioning from foreground to
12603 // non-foreground, have it do a gc.
12604 scheduleAppGcLocked(app);
12605 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12606 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12607 // Likewise do a gc when an app is moving in to the
12608 // background (such as a service stopping).
12609 scheduleAppGcLocked(app);
12610 }
12611 app.setRawAdj = app.curRawAdj;
12612 }
12613 if (adj != app.setAdj) {
12614 if (Process.setOomAdj(app.pid, adj)) {
12615 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12616 TAG, "Set app " + app.processName +
12617 " oom adj to " + adj);
12618 app.setAdj = adj;
12619 } else {
12620 return false;
12621 }
12622 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012623 if (app.setSchedGroup != app.curSchedGroup) {
12624 app.setSchedGroup = app.curSchedGroup;
12625 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12626 "Setting process group of " + app.processName
12627 + " to " + app.curSchedGroup);
12628 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012629 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012630 try {
12631 Process.setProcessGroup(app.pid, app.curSchedGroup);
12632 } catch (Exception e) {
12633 Log.w(TAG, "Failed setting process group of " + app.pid
12634 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012635 e.printStackTrace();
12636 } finally {
12637 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012638 }
12639 }
12640 if (false) {
12641 if (app.thread != null) {
12642 try {
12643 app.thread.setSchedulingGroup(app.curSchedGroup);
12644 } catch (RemoteException e) {
12645 }
12646 }
12647 }
12648 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012649 }
12650
12651 return true;
12652 }
12653
12654 private final HistoryRecord resumedAppLocked() {
12655 HistoryRecord resumedActivity = mResumedActivity;
12656 if (resumedActivity == null || resumedActivity.app == null) {
12657 resumedActivity = mPausingActivity;
12658 if (resumedActivity == null || resumedActivity.app == null) {
12659 resumedActivity = topRunningActivityLocked(null);
12660 }
12661 }
12662 return resumedActivity;
12663 }
12664
12665 private final boolean updateOomAdjLocked(ProcessRecord app) {
12666 final HistoryRecord TOP_ACT = resumedAppLocked();
12667 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12668 int curAdj = app.curAdj;
12669 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12670 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12671
12672 mAdjSeq++;
12673
12674 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12675 if (res) {
12676 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12677 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12678 if (nowHidden != wasHidden) {
12679 // Changed to/from hidden state, so apps after it in the LRU
12680 // list may also be changed.
12681 updateOomAdjLocked();
12682 }
12683 }
12684 return res;
12685 }
12686
12687 private final boolean updateOomAdjLocked() {
12688 boolean didOomAdj = true;
12689 final HistoryRecord TOP_ACT = resumedAppLocked();
12690 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12691
12692 if (false) {
12693 RuntimeException e = new RuntimeException();
12694 e.fillInStackTrace();
12695 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12696 }
12697
12698 mAdjSeq++;
12699
12700 // First try updating the OOM adjustment for each of the
12701 // application processes based on their current state.
12702 int i = mLRUProcesses.size();
12703 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12704 while (i > 0) {
12705 i--;
12706 ProcessRecord app = mLRUProcesses.get(i);
12707 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12708 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12709 && app.curAdj == curHiddenAdj) {
12710 curHiddenAdj++;
12711 }
12712 } else {
12713 didOomAdj = false;
12714 }
12715 }
12716
12717 // todo: for now pretend like OOM ADJ didn't work, because things
12718 // aren't behaving as expected on Linux -- it's not killing processes.
12719 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12720 }
12721
12722 private final void trimApplications() {
12723 synchronized (this) {
12724 int i;
12725
12726 // First remove any unused application processes whose package
12727 // has been removed.
12728 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12729 final ProcessRecord app = mRemovedProcesses.get(i);
12730 if (app.activities.size() == 0
12731 && app.curReceiver == null && app.services.size() == 0) {
12732 Log.i(
12733 TAG, "Exiting empty application process "
12734 + app.processName + " ("
12735 + (app.thread != null ? app.thread.asBinder() : null)
12736 + ")\n");
12737 if (app.pid > 0 && app.pid != MY_PID) {
12738 Process.killProcess(app.pid);
12739 } else {
12740 try {
12741 app.thread.scheduleExit();
12742 } catch (Exception e) {
12743 // Ignore exceptions.
12744 }
12745 }
12746 cleanUpApplicationRecordLocked(app, false, -1);
12747 mRemovedProcesses.remove(i);
12748
12749 if (app.persistent) {
12750 if (app.persistent) {
12751 addAppLocked(app.info);
12752 }
12753 }
12754 }
12755 }
12756
12757 // Now try updating the OOM adjustment for each of the
12758 // application processes based on their current state.
12759 // If the setOomAdj() API is not supported, then go with our
12760 // back-up plan...
12761 if (!updateOomAdjLocked()) {
12762
12763 // Count how many processes are running services.
12764 int numServiceProcs = 0;
12765 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12766 final ProcessRecord app = mLRUProcesses.get(i);
12767
12768 if (app.persistent || app.services.size() != 0
12769 || app.curReceiver != null
12770 || app.persistentActivities > 0) {
12771 // Don't count processes holding services against our
12772 // maximum process count.
12773 if (localLOGV) Log.v(
12774 TAG, "Not trimming app " + app + " with services: "
12775 + app.services);
12776 numServiceProcs++;
12777 }
12778 }
12779
12780 int curMaxProcs = mProcessLimit;
12781 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12782 if (mAlwaysFinishActivities) {
12783 curMaxProcs = 1;
12784 }
12785 curMaxProcs += numServiceProcs;
12786
12787 // Quit as many processes as we can to get down to the desired
12788 // process count. First remove any processes that no longer
12789 // have activites running in them.
12790 for ( i=0;
12791 i<mLRUProcesses.size()
12792 && mLRUProcesses.size() > curMaxProcs;
12793 i++) {
12794 final ProcessRecord app = mLRUProcesses.get(i);
12795 // Quit an application only if it is not currently
12796 // running any activities.
12797 if (!app.persistent && app.activities.size() == 0
12798 && app.curReceiver == null && app.services.size() == 0) {
12799 Log.i(
12800 TAG, "Exiting empty application process "
12801 + app.processName + " ("
12802 + (app.thread != null ? app.thread.asBinder() : null)
12803 + ")\n");
12804 if (app.pid > 0 && app.pid != MY_PID) {
12805 Process.killProcess(app.pid);
12806 } else {
12807 try {
12808 app.thread.scheduleExit();
12809 } catch (Exception e) {
12810 // Ignore exceptions.
12811 }
12812 }
12813 // todo: For now we assume the application is not buggy
12814 // or evil, and will quit as a result of our request.
12815 // Eventually we need to drive this off of the death
12816 // notification, and kill the process if it takes too long.
12817 cleanUpApplicationRecordLocked(app, false, i);
12818 i--;
12819 }
12820 }
12821
12822 // If we still have too many processes, now from the least
12823 // recently used process we start finishing activities.
12824 if (Config.LOGV) Log.v(
12825 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12826 " of " + curMaxProcs + " processes");
12827 for ( i=0;
12828 i<mLRUProcesses.size()
12829 && mLRUProcesses.size() > curMaxProcs;
12830 i++) {
12831 final ProcessRecord app = mLRUProcesses.get(i);
12832 // Quit the application only if we have a state saved for
12833 // all of its activities.
12834 boolean canQuit = !app.persistent && app.curReceiver == null
12835 && app.services.size() == 0
12836 && app.persistentActivities == 0;
12837 int NUMA = app.activities.size();
12838 int j;
12839 if (Config.LOGV) Log.v(
12840 TAG, "Looking to quit " + app.processName);
12841 for (j=0; j<NUMA && canQuit; j++) {
12842 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12843 if (Config.LOGV) Log.v(
12844 TAG, " " + r.intent.getComponent().flattenToShortString()
12845 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12846 canQuit = (r.haveState || !r.stateNotNeeded)
12847 && !r.visible && r.stopped;
12848 }
12849 if (canQuit) {
12850 // Finish all of the activities, and then the app itself.
12851 for (j=0; j<NUMA; j++) {
12852 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12853 if (!r.finishing) {
12854 destroyActivityLocked(r, false);
12855 }
12856 r.resultTo = null;
12857 }
12858 Log.i(TAG, "Exiting application process "
12859 + app.processName + " ("
12860 + (app.thread != null ? app.thread.asBinder() : null)
12861 + ")\n");
12862 if (app.pid > 0 && app.pid != MY_PID) {
12863 Process.killProcess(app.pid);
12864 } else {
12865 try {
12866 app.thread.scheduleExit();
12867 } catch (Exception e) {
12868 // Ignore exceptions.
12869 }
12870 }
12871 // todo: For now we assume the application is not buggy
12872 // or evil, and will quit as a result of our request.
12873 // Eventually we need to drive this off of the death
12874 // notification, and kill the process if it takes too long.
12875 cleanUpApplicationRecordLocked(app, false, i);
12876 i--;
12877 //dump();
12878 }
12879 }
12880
12881 }
12882
12883 int curMaxActivities = MAX_ACTIVITIES;
12884 if (mAlwaysFinishActivities) {
12885 curMaxActivities = 1;
12886 }
12887
12888 // Finally, if there are too many activities now running, try to
12889 // finish as many as we can to get back down to the limit.
12890 for ( i=0;
12891 i<mLRUActivities.size()
12892 && mLRUActivities.size() > curMaxActivities;
12893 i++) {
12894 final HistoryRecord r
12895 = (HistoryRecord)mLRUActivities.get(i);
12896
12897 // We can finish this one if we have its icicle saved and
12898 // it is not persistent.
12899 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12900 && r.stopped && !r.persistent && !r.finishing) {
12901 final int origSize = mLRUActivities.size();
12902 destroyActivityLocked(r, true);
12903
12904 // This will remove it from the LRU list, so keep
12905 // our index at the same value. Note that this check to
12906 // see if the size changes is just paranoia -- if
12907 // something unexpected happens, we don't want to end up
12908 // in an infinite loop.
12909 if (origSize > mLRUActivities.size()) {
12910 i--;
12911 }
12912 }
12913 }
12914 }
12915 }
12916
12917 /** This method sends the specified signal to each of the persistent apps */
12918 public void signalPersistentProcesses(int sig) throws RemoteException {
12919 if (sig != Process.SIGNAL_USR1) {
12920 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12921 }
12922
12923 synchronized (this) {
12924 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12925 != PackageManager.PERMISSION_GRANTED) {
12926 throw new SecurityException("Requires permission "
12927 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12928 }
12929
12930 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12931 ProcessRecord r = mLRUProcesses.get(i);
12932 if (r.thread != null && r.persistent) {
12933 Process.sendSignal(r.pid, sig);
12934 }
12935 }
12936 }
12937 }
12938
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012939 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012940 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012941
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012942 try {
12943 synchronized (this) {
12944 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12945 // its own permission.
12946 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12947 != PackageManager.PERMISSION_GRANTED) {
12948 throw new SecurityException("Requires permission "
12949 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012950 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012951
12952 if (start && fd == null) {
12953 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012954 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012955
12956 ProcessRecord proc = null;
12957 try {
12958 int pid = Integer.parseInt(process);
12959 synchronized (mPidsSelfLocked) {
12960 proc = mPidsSelfLocked.get(pid);
12961 }
12962 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012963 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012964
12965 if (proc == null) {
12966 HashMap<String, SparseArray<ProcessRecord>> all
12967 = mProcessNames.getMap();
12968 SparseArray<ProcessRecord> procs = all.get(process);
12969 if (procs != null && procs.size() > 0) {
12970 proc = procs.valueAt(0);
12971 }
12972 }
12973
12974 if (proc == null || proc.thread == null) {
12975 throw new IllegalArgumentException("Unknown process: " + process);
12976 }
12977
12978 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12979 if (isSecure) {
12980 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12981 throw new SecurityException("Process not debuggable: " + proc);
12982 }
12983 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012984
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012985 proc.thread.profilerControl(start, path, fd);
12986 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012987 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012988 }
12989 } catch (RemoteException e) {
12990 throw new IllegalStateException("Process disappeared");
12991 } finally {
12992 if (fd != null) {
12993 try {
12994 fd.close();
12995 } catch (IOException e) {
12996 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012997 }
12998 }
12999 }
13000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013001 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13002 public void monitor() {
13003 synchronized (this) { }
13004 }
13005}