blob: 14c10b94dcf74d50c2b2cca64cca23b7cf414ec8 [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;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700927 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928
929 AlertDialog mUidAlert;
930
931 final Handler mHandler = new Handler() {
932 //public Handler() {
933 // if (localLOGV) Log.v(TAG, "Handler started!");
934 //}
935
936 public void handleMessage(Message msg) {
937 switch (msg.what) {
938 case SHOW_ERROR_MSG: {
939 HashMap data = (HashMap) msg.obj;
940 byte[] crashData = (byte[])data.get("crashData");
941 if (crashData != null) {
942 // This needs to be *un*synchronized to avoid deadlock.
943 ContentResolver resolver = mContext.getContentResolver();
944 Checkin.reportCrash(resolver, crashData);
945 }
946 synchronized (ActivityManagerService.this) {
947 ProcessRecord proc = (ProcessRecord)data.get("app");
948 if (proc != null && proc.crashDialog != null) {
949 Log.e(TAG, "App already has crash dialog: " + proc);
950 return;
951 }
952 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700953 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 Dialog d = new AppErrorDialog(
955 mContext, res, proc,
956 (Integer)data.get("flags"),
957 (String)data.get("shortMsg"),
958 (String)data.get("longMsg"));
959 d.show();
960 proc.crashDialog = d;
961 } else {
962 // The device is asleep, so just pretend that the user
963 // saw a crash dialog and hit "force quit".
964 res.set(0);
965 }
966 }
967 } break;
968 case SHOW_NOT_RESPONDING_MSG: {
969 synchronized (ActivityManagerService.this) {
970 HashMap data = (HashMap) msg.obj;
971 ProcessRecord proc = (ProcessRecord)data.get("app");
972 if (proc != null && proc.anrDialog != null) {
973 Log.e(TAG, "App already has anr dialog: " + proc);
974 return;
975 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800976
977 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
978 null, null, 0, null, null, null,
979 false, false, MY_PID, Process.SYSTEM_UID);
980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
982 mContext, proc, (HistoryRecord)data.get("activity"));
983 d.show();
984 proc.anrDialog = d;
985 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700986
987 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 } break;
989 case SHOW_FACTORY_ERROR_MSG: {
990 Dialog d = new FactoryErrorDialog(
991 mContext, msg.getData().getCharSequence("msg"));
992 d.show();
993 enableScreenAfterBoot();
994 } break;
995 case UPDATE_CONFIGURATION_MSG: {
996 final ContentResolver resolver = mContext.getContentResolver();
997 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
998 } break;
999 case GC_BACKGROUND_PROCESSES_MSG: {
1000 synchronized (ActivityManagerService.this) {
1001 performAppGcsIfAppropriateLocked();
1002 }
1003 } break;
1004 case WAIT_FOR_DEBUGGER_MSG: {
1005 synchronized (ActivityManagerService.this) {
1006 ProcessRecord app = (ProcessRecord)msg.obj;
1007 if (msg.arg1 != 0) {
1008 if (!app.waitedForDebugger) {
1009 Dialog d = new AppWaitingForDebuggerDialog(
1010 ActivityManagerService.this,
1011 mContext, app);
1012 app.waitDialog = d;
1013 app.waitedForDebugger = true;
1014 d.show();
1015 }
1016 } else {
1017 if (app.waitDialog != null) {
1018 app.waitDialog.dismiss();
1019 app.waitDialog = null;
1020 }
1021 }
1022 }
1023 } break;
1024 case BROADCAST_INTENT_MSG: {
1025 if (DEBUG_BROADCAST) Log.v(
1026 TAG, "Received BROADCAST_INTENT_MSG");
1027 processNextBroadcast(true);
1028 } break;
1029 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001030 if (mDidDexOpt) {
1031 mDidDexOpt = false;
1032 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1033 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1034 return;
1035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 broadcastTimeout();
1037 } break;
1038 case PAUSE_TIMEOUT_MSG: {
1039 IBinder token = (IBinder)msg.obj;
1040 // We don't at this point know if the activity is fullscreen,
1041 // so we need to be conservative and assume it isn't.
1042 Log.w(TAG, "Activity pause timeout for " + token);
1043 activityPaused(token, null, true);
1044 } break;
1045 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001046 if (mDidDexOpt) {
1047 mDidDexOpt = false;
1048 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1049 nmsg.obj = msg.obj;
1050 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1051 return;
1052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 // We don't at this point know if the activity is fullscreen,
1054 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001055 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 Log.w(TAG, "Activity idle timeout for " + token);
1057 activityIdleInternal(token, true);
1058 } break;
1059 case DESTROY_TIMEOUT_MSG: {
1060 IBinder token = (IBinder)msg.obj;
1061 // We don't at this point know if the activity is fullscreen,
1062 // so we need to be conservative and assume it isn't.
1063 Log.w(TAG, "Activity destroy timeout for " + token);
1064 activityDestroyed(token);
1065 } break;
1066 case IDLE_NOW_MSG: {
1067 IBinder token = (IBinder)msg.obj;
1068 activityIdle(token);
1069 } break;
1070 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001071 if (mDidDexOpt) {
1072 mDidDexOpt = false;
1073 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1074 nmsg.obj = msg.obj;
1075 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1076 return;
1077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 serviceTimeout((ProcessRecord)msg.obj);
1079 } break;
1080 case UPDATE_TIME_ZONE: {
1081 synchronized (ActivityManagerService.this) {
1082 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1083 ProcessRecord r = mLRUProcesses.get(i);
1084 if (r.thread != null) {
1085 try {
1086 r.thread.updateTimeZone();
1087 } catch (RemoteException ex) {
1088 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1089 }
1090 }
1091 }
1092 }
1093 break;
1094 }
1095 case SHOW_UID_ERROR_MSG: {
1096 // XXX This is a temporary dialog, no need to localize.
1097 AlertDialog d = new BaseErrorDialog(mContext);
1098 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1099 d.setCancelable(false);
1100 d.setTitle("System UIDs Inconsistent");
1101 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1102 d.setButton("I'm Feeling Lucky",
1103 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1104 mUidAlert = d;
1105 d.show();
1106 } break;
1107 case IM_FEELING_LUCKY_MSG: {
1108 if (mUidAlert != null) {
1109 mUidAlert.dismiss();
1110 mUidAlert = null;
1111 }
1112 } break;
1113 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001114 if (mDidDexOpt) {
1115 mDidDexOpt = false;
1116 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1117 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1118 return;
1119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 synchronized (ActivityManagerService.this) {
1121 if (mLaunchingActivity.isHeld()) {
1122 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1123 mLaunchingActivity.release();
1124 }
1125 }
1126 } break;
1127 case SERVICE_ERROR_MSG: {
1128 ServiceRecord srv = (ServiceRecord)msg.obj;
1129 // This needs to be *un*synchronized to avoid deadlock.
1130 Checkin.logEvent(mContext.getContentResolver(),
1131 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1132 srv.name.toShortString());
1133 } break;
1134 case RESUME_TOP_ACTIVITY_MSG: {
1135 synchronized (ActivityManagerService.this) {
1136 resumeTopActivityLocked(null);
1137 }
1138 }
1139 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001140 if (mDidDexOpt) {
1141 mDidDexOpt = false;
1142 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1143 nmsg.obj = msg.obj;
1144 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1145 return;
1146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 ProcessRecord app = (ProcessRecord)msg.obj;
1148 synchronized (ActivityManagerService.this) {
1149 processStartTimedOutLocked(app);
1150 }
1151 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001152 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1153 synchronized (ActivityManagerService.this) {
1154 doPendingActivityLaunchesLocked(true);
1155 }
1156 }
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001157 case KILL_APPLICATION_MSG: {
1158 synchronized (ActivityManagerService.this) {
1159 int uid = msg.arg1;
1160 boolean restart = (msg.arg2 == 1);
1161 String pkg = (String) msg.obj;
1162 uninstallPackageLocked(pkg, uid, restart);
1163 }
1164 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 }
1166 }
1167 };
1168
1169 public static void setSystemProcess() {
1170 try {
1171 ActivityManagerService m = mSelf;
1172
1173 ServiceManager.addService("activity", m);
1174 ServiceManager.addService("meminfo", new MemBinder(m));
1175 if (MONITOR_CPU_USAGE) {
1176 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1177 }
1178 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1179 ServiceManager.addService("activity.services", new ServicesBinder(m));
1180 ServiceManager.addService("activity.senders", new SendersBinder(m));
1181 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1182 ServiceManager.addService("permission", new PermissionController(m));
1183
1184 ApplicationInfo info =
1185 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001186 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001187 synchronized (mSelf) {
1188 ProcessRecord app = mSelf.newProcessRecordLocked(
1189 mSystemThread.getApplicationThread(), info,
1190 info.processName);
1191 app.persistent = true;
1192 app.pid = Process.myPid();
1193 app.maxAdj = SYSTEM_ADJ;
1194 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1195 synchronized (mSelf.mPidsSelfLocked) {
1196 mSelf.mPidsSelfLocked.put(app.pid, app);
1197 }
1198 mSelf.updateLRUListLocked(app, true);
1199 }
1200 } catch (PackageManager.NameNotFoundException e) {
1201 throw new RuntimeException(
1202 "Unable to find android system package", e);
1203 }
1204 }
1205
1206 public void setWindowManager(WindowManagerService wm) {
1207 mWindowManager = wm;
1208 }
1209
1210 public static final Context main(int factoryTest) {
1211 AThread thr = new AThread();
1212 thr.start();
1213
1214 synchronized (thr) {
1215 while (thr.mService == null) {
1216 try {
1217 thr.wait();
1218 } catch (InterruptedException e) {
1219 }
1220 }
1221 }
1222
1223 ActivityManagerService m = thr.mService;
1224 mSelf = m;
1225 ActivityThread at = ActivityThread.systemMain();
1226 mSystemThread = at;
1227 Context context = at.getSystemContext();
1228 m.mContext = context;
1229 m.mFactoryTest = factoryTest;
1230 PowerManager pm =
1231 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1232 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1233 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1234 m.mLaunchingActivity.setReferenceCounted(false);
1235
1236 m.mBatteryStatsService.publish(context);
1237 m.mUsageStatsService.publish(context);
1238
1239 synchronized (thr) {
1240 thr.mReady = true;
1241 thr.notifyAll();
1242 }
1243
1244 m.startRunning(null, null, null, null);
1245
1246 return context;
1247 }
1248
1249 public static ActivityManagerService self() {
1250 return mSelf;
1251 }
1252
1253 static class AThread extends Thread {
1254 ActivityManagerService mService;
1255 boolean mReady = false;
1256
1257 public AThread() {
1258 super("ActivityManager");
1259 }
1260
1261 public void run() {
1262 Looper.prepare();
1263
1264 android.os.Process.setThreadPriority(
1265 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1266
1267 ActivityManagerService m = new ActivityManagerService();
1268
1269 synchronized (this) {
1270 mService = m;
1271 notifyAll();
1272 }
1273
1274 synchronized (this) {
1275 while (!mReady) {
1276 try {
1277 wait();
1278 } catch (InterruptedException e) {
1279 }
1280 }
1281 }
1282
1283 Looper.loop();
1284 }
1285 }
1286
1287 static class BroadcastsBinder extends Binder {
1288 ActivityManagerService mActivityManagerService;
1289 BroadcastsBinder(ActivityManagerService activityManagerService) {
1290 mActivityManagerService = activityManagerService;
1291 }
1292
1293 @Override
1294 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1295 mActivityManagerService.dumpBroadcasts(pw);
1296 }
1297 }
1298
1299 static class ServicesBinder extends Binder {
1300 ActivityManagerService mActivityManagerService;
1301 ServicesBinder(ActivityManagerService activityManagerService) {
1302 mActivityManagerService = activityManagerService;
1303 }
1304
1305 @Override
1306 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1307 mActivityManagerService.dumpServices(pw);
1308 }
1309 }
1310
1311 static class SendersBinder extends Binder {
1312 ActivityManagerService mActivityManagerService;
1313 SendersBinder(ActivityManagerService activityManagerService) {
1314 mActivityManagerService = activityManagerService;
1315 }
1316
1317 @Override
1318 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1319 mActivityManagerService.dumpSenders(pw);
1320 }
1321 }
1322
1323 static class ProvidersBinder extends Binder {
1324 ActivityManagerService mActivityManagerService;
1325 ProvidersBinder(ActivityManagerService activityManagerService) {
1326 mActivityManagerService = activityManagerService;
1327 }
1328
1329 @Override
1330 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1331 mActivityManagerService.dumpProviders(pw);
1332 }
1333 }
1334
1335 static class MemBinder extends Binder {
1336 ActivityManagerService mActivityManagerService;
1337 MemBinder(ActivityManagerService activityManagerService) {
1338 mActivityManagerService = activityManagerService;
1339 }
1340
1341 @Override
1342 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1343 ActivityManagerService service = mActivityManagerService;
1344 ArrayList<ProcessRecord> procs;
1345 synchronized (mActivityManagerService) {
1346 if (args != null && args.length > 0
1347 && args[0].charAt(0) != '-') {
1348 procs = new ArrayList<ProcessRecord>();
1349 int pid = -1;
1350 try {
1351 pid = Integer.parseInt(args[0]);
1352 } catch (NumberFormatException e) {
1353
1354 }
1355 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1356 ProcessRecord proc = service.mLRUProcesses.get(i);
1357 if (proc.pid == pid) {
1358 procs.add(proc);
1359 } else if (proc.processName.equals(args[0])) {
1360 procs.add(proc);
1361 }
1362 }
1363 if (procs.size() <= 0) {
1364 pw.println("No process found for: " + args[0]);
1365 return;
1366 }
1367 } else {
1368 procs = service.mLRUProcesses;
1369 }
1370 }
1371 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1372 }
1373 }
1374
1375 static class CpuBinder extends Binder {
1376 ActivityManagerService mActivityManagerService;
1377 CpuBinder(ActivityManagerService activityManagerService) {
1378 mActivityManagerService = activityManagerService;
1379 }
1380
1381 @Override
1382 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1383 synchronized (mActivityManagerService.mProcessStatsThread) {
1384 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1385 }
1386 }
1387 }
1388
1389 private ActivityManagerService() {
1390 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1391 if (v != null && Integer.getInteger(v) != 0) {
1392 mSimpleProcessManagement = true;
1393 }
1394 v = System.getenv("ANDROID_DEBUG_APP");
1395 if (v != null) {
1396 mSimpleProcessManagement = true;
1397 }
1398
1399 MY_PID = Process.myPid();
1400
1401 File dataDir = Environment.getDataDirectory();
1402 File systemDir = new File(dataDir, "system");
1403 systemDir.mkdirs();
1404 mBatteryStatsService = new BatteryStatsService(new File(
1405 systemDir, "batterystats.bin").toString());
1406 mBatteryStatsService.getActiveStatistics().readLocked();
1407 mBatteryStatsService.getActiveStatistics().writeLocked();
1408
1409 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001410 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411
Jack Palevichb90d28c2009-07-22 15:35:24 -07001412 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1413 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001415 mConfiguration.makeDefault();
1416 mProcessStats.init();
1417
1418 // Add ourself to the Watchdog monitors.
1419 Watchdog.getInstance().addMonitor(this);
1420
1421 // These values are set in system/rootdir/init.rc on startup.
1422 FOREGROUND_APP_ADJ =
1423 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1424 VISIBLE_APP_ADJ =
1425 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1426 SECONDARY_SERVER_ADJ =
1427 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001428 BACKUP_APP_ADJ =
1429 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001430 HOME_APP_ADJ =
1431 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 HIDDEN_APP_MIN_ADJ =
1433 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1434 CONTENT_PROVIDER_ADJ =
1435 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1436 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1437 EMPTY_APP_ADJ =
1438 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1439 FOREGROUND_APP_MEM =
1440 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1441 VISIBLE_APP_MEM =
1442 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1443 SECONDARY_SERVER_MEM =
1444 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001445 BACKUP_APP_MEM =
1446 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001447 HOME_APP_MEM =
1448 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 HIDDEN_APP_MEM =
1450 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1451 EMPTY_APP_MEM =
1452 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1453
1454 mProcessStatsThread = new Thread("ProcessStats") {
1455 public void run() {
1456 while (true) {
1457 try {
1458 try {
1459 synchronized(this) {
1460 final long now = SystemClock.uptimeMillis();
1461 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1462 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1463 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1464 // + ", write delay=" + nextWriteDelay);
1465 if (nextWriteDelay < nextCpuDelay) {
1466 nextCpuDelay = nextWriteDelay;
1467 }
1468 if (nextCpuDelay > 0) {
1469 this.wait(nextCpuDelay);
1470 }
1471 }
1472 } catch (InterruptedException e) {
1473 }
1474
1475 updateCpuStatsNow();
1476 } catch (Exception e) {
1477 Log.e(TAG, "Unexpected exception collecting process stats", e);
1478 }
1479 }
1480 }
1481 };
1482 mProcessStatsThread.start();
1483 }
1484
1485 @Override
1486 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1487 throws RemoteException {
1488 try {
1489 return super.onTransact(code, data, reply, flags);
1490 } catch (RuntimeException e) {
1491 // The activity manager only throws security exceptions, so let's
1492 // log all others.
1493 if (!(e instanceof SecurityException)) {
1494 Log.e(TAG, "Activity Manager Crash", e);
1495 }
1496 throw e;
1497 }
1498 }
1499
1500 void updateCpuStats() {
1501 synchronized (mProcessStatsThread) {
1502 final long now = SystemClock.uptimeMillis();
1503 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1504 mProcessStatsThread.notify();
1505 }
1506 }
1507 }
1508
1509 void updateCpuStatsNow() {
1510 synchronized (mProcessStatsThread) {
1511 final long now = SystemClock.uptimeMillis();
1512 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 if (MONITOR_CPU_USAGE &&
1515 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1516 mLastCpuTime = now;
1517 haveNewCpuStats = true;
1518 mProcessStats.update();
1519 //Log.i(TAG, mProcessStats.printCurrentState());
1520 //Log.i(TAG, "Total CPU usage: "
1521 // + mProcessStats.getTotalCpuPercent() + "%");
1522
1523 // Log the cpu usage if the property is set.
1524 if ("true".equals(SystemProperties.get("events.cpu"))) {
1525 int user = mProcessStats.getLastUserTime();
1526 int system = mProcessStats.getLastSystemTime();
1527 int iowait = mProcessStats.getLastIoWaitTime();
1528 int irq = mProcessStats.getLastIrqTime();
1529 int softIrq = mProcessStats.getLastSoftIrqTime();
1530 int idle = mProcessStats.getLastIdleTime();
1531
1532 int total = user + system + iowait + irq + softIrq + idle;
1533 if (total == 0) total = 1;
1534
1535 EventLog.writeEvent(LOG_CPU,
1536 ((user+system+iowait+irq+softIrq) * 100) / total,
1537 (user * 100) / total,
1538 (system * 100) / total,
1539 (iowait * 100) / total,
1540 (irq * 100) / total,
1541 (softIrq * 100) / total);
1542 }
1543 }
1544
Amith Yamasani819f9282009-06-24 23:18:15 -07001545 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001546 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 synchronized(mPidsSelfLocked) {
1548 if (haveNewCpuStats) {
1549 if (mBatteryStatsService.isOnBattery()) {
1550 final int N = mProcessStats.countWorkingStats();
1551 for (int i=0; i<N; i++) {
1552 ProcessStats.Stats st
1553 = mProcessStats.getWorkingStats(i);
1554 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1555 if (pr != null) {
1556 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1557 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001558 } else {
1559 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001560 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001561 if (ps != null) {
1562 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 }
1565 }
1566 }
1567 }
1568 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1571 mLastWriteTime = now;
1572 mBatteryStatsService.getActiveStatistics().writeLocked();
1573 }
1574 }
1575 }
1576 }
1577
1578 /**
1579 * Initialize the application bind args. These are passed to each
1580 * process when the bindApplication() IPC is sent to the process. They're
1581 * lazily setup to make sure the services are running when they're asked for.
1582 */
1583 private HashMap<String, IBinder> getCommonServicesLocked() {
1584 if (mAppBindArgs == null) {
1585 mAppBindArgs = new HashMap<String, IBinder>();
1586
1587 // Setup the application init args
1588 mAppBindArgs.put("package", ServiceManager.getService("package"));
1589 mAppBindArgs.put("window", ServiceManager.getService("window"));
1590 mAppBindArgs.put(Context.ALARM_SERVICE,
1591 ServiceManager.getService(Context.ALARM_SERVICE));
1592 }
1593 return mAppBindArgs;
1594 }
1595
1596 private final void setFocusedActivityLocked(HistoryRecord r) {
1597 if (mFocusedActivity != r) {
1598 mFocusedActivity = r;
1599 mWindowManager.setFocusedApp(r, true);
1600 }
1601 }
1602
1603 private final void updateLRUListLocked(ProcessRecord app,
1604 boolean oomAdj) {
1605 // put it on the LRU to keep track of when it should be exited.
1606 int lrui = mLRUProcesses.indexOf(app);
1607 if (lrui >= 0) mLRUProcesses.remove(lrui);
1608 mLRUProcesses.add(app);
1609 //Log.i(TAG, "Putting proc to front: " + app.processName);
1610 if (oomAdj) {
1611 updateOomAdjLocked();
1612 }
1613 }
1614
1615 private final boolean updateLRUListLocked(HistoryRecord r) {
1616 final boolean hadit = mLRUActivities.remove(r);
1617 mLRUActivities.add(r);
1618 return hadit;
1619 }
1620
1621 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1622 int i = mHistory.size()-1;
1623 while (i >= 0) {
1624 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1625 if (!r.finishing && r != notTop) {
1626 return r;
1627 }
1628 i--;
1629 }
1630 return null;
1631 }
1632
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001633 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1634 int i = mHistory.size()-1;
1635 while (i >= 0) {
1636 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1637 if (!r.finishing && !r.delayedResume && r != notTop) {
1638 return r;
1639 }
1640 i--;
1641 }
1642 return null;
1643 }
1644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 /**
1646 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001647 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 *
1649 * @param token If non-null, any history records matching this token will be skipped.
1650 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1651 *
1652 * @return Returns the HistoryRecord of the next activity on the stack.
1653 */
1654 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1655 int i = mHistory.size()-1;
1656 while (i >= 0) {
1657 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1658 // Note: the taskId check depends on real taskId fields being non-zero
1659 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1660 return r;
1661 }
1662 i--;
1663 }
1664 return null;
1665 }
1666
1667 private final ProcessRecord getProcessRecordLocked(
1668 String processName, int uid) {
1669 if (uid == Process.SYSTEM_UID) {
1670 // The system gets to run in any process. If there are multiple
1671 // processes with the same uid, just pick the first (this
1672 // should never happen).
1673 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1674 processName);
1675 return procs != null ? procs.valueAt(0) : null;
1676 }
1677 ProcessRecord proc = mProcessNames.get(processName, uid);
1678 return proc;
1679 }
1680
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001681 private void ensurePackageDexOpt(String packageName) {
1682 IPackageManager pm = ActivityThread.getPackageManager();
1683 try {
1684 if (pm.performDexOpt(packageName)) {
1685 mDidDexOpt = true;
1686 }
1687 } catch (RemoteException e) {
1688 }
1689 }
1690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 private boolean isNextTransitionForward() {
1692 int transit = mWindowManager.getPendingAppTransition();
1693 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1694 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1695 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1696 }
1697
1698 private final boolean realStartActivityLocked(HistoryRecord r,
1699 ProcessRecord app, boolean andResume, boolean checkConfig)
1700 throws RemoteException {
1701
1702 r.startFreezingScreenLocked(app, 0);
1703 mWindowManager.setAppVisibility(r, true);
1704
1705 // Have the window manager re-evaluate the orientation of
1706 // the screen based on the new activity order. Note that
1707 // as a result of this, it can call back into the activity
1708 // manager with a new orientation. We don't care about that,
1709 // because the activity is not currently running so we are
1710 // just restarting it anyway.
1711 if (checkConfig) {
1712 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001713 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 r.mayFreezeScreenLocked(app) ? r : null);
1715 updateConfigurationLocked(config, r);
1716 }
1717
1718 r.app = app;
1719
1720 if (localLOGV) Log.v(TAG, "Launching: " + r);
1721
1722 int idx = app.activities.indexOf(r);
1723 if (idx < 0) {
1724 app.activities.add(r);
1725 }
1726 updateLRUListLocked(app, true);
1727
1728 try {
1729 if (app.thread == null) {
1730 throw new RemoteException();
1731 }
1732 List<ResultInfo> results = null;
1733 List<Intent> newIntents = null;
1734 if (andResume) {
1735 results = r.results;
1736 newIntents = r.newIntents;
1737 }
1738 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1739 + " icicle=" + r.icicle
1740 + " with results=" + results + " newIntents=" + newIntents
1741 + " andResume=" + andResume);
1742 if (andResume) {
1743 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1744 System.identityHashCode(r),
1745 r.task.taskId, r.shortComponentName);
1746 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001747 if (r.isHomeActivity) {
1748 mHomeProcess = app;
1749 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001750 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001752 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 r.info, r.icicle, results, newIntents, !andResume,
1754 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 } catch (RemoteException e) {
1756 if (r.launchFailed) {
1757 // This is the second time we failed -- finish activity
1758 // and give up.
1759 Log.e(TAG, "Second failure launching "
1760 + r.intent.getComponent().flattenToShortString()
1761 + ", giving up", e);
1762 appDiedLocked(app, app.pid, app.thread);
1763 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1764 "2nd-crash");
1765 return false;
1766 }
1767
1768 // This is the first time we failed -- restart process and
1769 // retry.
1770 app.activities.remove(r);
1771 throw e;
1772 }
1773
1774 r.launchFailed = false;
1775 if (updateLRUListLocked(r)) {
1776 Log.w(TAG, "Activity " + r
1777 + " being launched, but already in LRU list");
1778 }
1779
1780 if (andResume) {
1781 // As part of the process of launching, ActivityThread also performs
1782 // a resume.
1783 r.state = ActivityState.RESUMED;
1784 r.icicle = null;
1785 r.haveState = false;
1786 r.stopped = false;
1787 mResumedActivity = r;
1788 r.task.touchActiveTime();
1789 completeResumeLocked(r);
1790 pauseIfSleepingLocked();
1791 } else {
1792 // This activity is not starting in the resumed state... which
1793 // should look like we asked it to pause+stop (but remain visible),
1794 // and it has done so and reported back the current icicle and
1795 // other state.
1796 r.state = ActivityState.STOPPED;
1797 r.stopped = true;
1798 }
1799
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001800 // Launch the new version setup screen if needed. We do this -after-
1801 // launching the initial activity (that is, home), so that it can have
1802 // a chance to initialize itself while in the background, making the
1803 // switch back to it faster and look better.
1804 startSetupActivityLocked();
1805
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 return true;
1807 }
1808
1809 private final void startSpecificActivityLocked(HistoryRecord r,
1810 boolean andResume, boolean checkConfig) {
1811 // Is this activity's application already running?
1812 ProcessRecord app = getProcessRecordLocked(r.processName,
1813 r.info.applicationInfo.uid);
1814
1815 if (r.startTime == 0) {
1816 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001817 if (mInitialStartTime == 0) {
1818 mInitialStartTime = r.startTime;
1819 }
1820 } else if (mInitialStartTime == 0) {
1821 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 }
1823
1824 if (app != null && app.thread != null) {
1825 try {
1826 realStartActivityLocked(r, app, andResume, checkConfig);
1827 return;
1828 } catch (RemoteException e) {
1829 Log.w(TAG, "Exception when starting activity "
1830 + r.intent.getComponent().flattenToShortString(), e);
1831 }
1832
1833 // If a dead object exception was thrown -- fall through to
1834 // restart the application.
1835 }
1836
1837 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1838 "activity", r.intent.getComponent());
1839 }
1840
1841 private final ProcessRecord startProcessLocked(String processName,
1842 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1843 String hostingType, ComponentName hostingName) {
1844 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1845 // We don't have to do anything more if:
1846 // (1) There is an existing application record; and
1847 // (2) The caller doesn't think it is dead, OR there is no thread
1848 // object attached to it so we know it couldn't have crashed; and
1849 // (3) There is a pid assigned to it, so it is either starting or
1850 // already running.
1851 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1852 + " app=" + app + " knownToBeDead=" + knownToBeDead
1853 + " thread=" + (app != null ? app.thread : null)
1854 + " pid=" + (app != null ? app.pid : -1));
1855 if (app != null &&
1856 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1857 return app;
1858 }
1859
1860 String hostingNameStr = hostingName != null
1861 ? hostingName.flattenToShortString() : null;
1862
1863 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1864 // If we are in the background, then check to see if this process
1865 // is bad. If so, we will just silently fail.
1866 if (mBadProcesses.get(info.processName, info.uid) != null) {
1867 return null;
1868 }
1869 } else {
1870 // When the user is explicitly starting a process, then clear its
1871 // crash count so that we won't make it bad until they see at
1872 // least one crash dialog again, and make the process good again
1873 // if it had been bad.
1874 mProcessCrashTimes.remove(info.processName, info.uid);
1875 if (mBadProcesses.get(info.processName, info.uid) != null) {
1876 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1877 info.processName);
1878 mBadProcesses.remove(info.processName, info.uid);
1879 if (app != null) {
1880 app.bad = false;
1881 }
1882 }
1883 }
1884
1885 if (app == null) {
1886 app = newProcessRecordLocked(null, info, processName);
1887 mProcessNames.put(processName, info.uid, app);
1888 } else {
1889 // If this is a new package in the process, add the package to the list
1890 app.addPackage(info.packageName);
1891 }
1892
1893 // If the system is not ready yet, then hold off on starting this
1894 // process until it is.
1895 if (!mSystemReady
1896 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1897 if (!mProcessesOnHold.contains(app)) {
1898 mProcessesOnHold.add(app);
1899 }
1900 return app;
1901 }
1902
1903 startProcessLocked(app, hostingType, hostingNameStr);
1904 return (app.pid != 0) ? app : null;
1905 }
1906
1907 private final void startProcessLocked(ProcessRecord app,
1908 String hostingType, String hostingNameStr) {
1909 if (app.pid > 0 && app.pid != MY_PID) {
1910 synchronized (mPidsSelfLocked) {
1911 mPidsSelfLocked.remove(app.pid);
1912 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1913 }
1914 app.pid = 0;
1915 }
1916
1917 mProcessesOnHold.remove(app);
1918
1919 updateCpuStats();
1920
1921 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1922 mProcDeaths[0] = 0;
1923
1924 try {
1925 int uid = app.info.uid;
1926 int[] gids = null;
1927 try {
1928 gids = mContext.getPackageManager().getPackageGids(
1929 app.info.packageName);
1930 } catch (PackageManager.NameNotFoundException e) {
1931 Log.w(TAG, "Unable to retrieve gids", e);
1932 }
1933 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1934 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1935 && mTopComponent != null
1936 && app.processName.equals(mTopComponent.getPackageName())) {
1937 uid = 0;
1938 }
1939 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1940 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1941 uid = 0;
1942 }
1943 }
1944 int debugFlags = 0;
1945 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1946 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1947 }
1948 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1949 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1950 }
1951 if ("1".equals(SystemProperties.get("debug.assert"))) {
1952 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1953 }
1954 int pid = Process.start("android.app.ActivityThread",
1955 mSimpleProcessManagement ? app.processName : null, uid, uid,
1956 gids, debugFlags, null);
1957 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1958 synchronized (bs) {
1959 if (bs.isOnBattery()) {
1960 app.batteryStats.incStartsLocked();
1961 }
1962 }
1963
1964 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1965 app.processName, hostingType,
1966 hostingNameStr != null ? hostingNameStr : "");
1967
1968 if (app.persistent) {
1969 Watchdog.getInstance().processStarted(app, app.processName, pid);
1970 }
1971
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001972 StringBuilder buf = mStringBuilder;
1973 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 buf.append("Start proc ");
1975 buf.append(app.processName);
1976 buf.append(" for ");
1977 buf.append(hostingType);
1978 if (hostingNameStr != null) {
1979 buf.append(" ");
1980 buf.append(hostingNameStr);
1981 }
1982 buf.append(": pid=");
1983 buf.append(pid);
1984 buf.append(" uid=");
1985 buf.append(uid);
1986 buf.append(" gids={");
1987 if (gids != null) {
1988 for (int gi=0; gi<gids.length; gi++) {
1989 if (gi != 0) buf.append(", ");
1990 buf.append(gids[gi]);
1991
1992 }
1993 }
1994 buf.append("}");
1995 Log.i(TAG, buf.toString());
1996 if (pid == 0 || pid == MY_PID) {
1997 // Processes are being emulated with threads.
1998 app.pid = MY_PID;
1999 app.removed = false;
2000 mStartingProcesses.add(app);
2001 } else if (pid > 0) {
2002 app.pid = pid;
2003 app.removed = false;
2004 synchronized (mPidsSelfLocked) {
2005 this.mPidsSelfLocked.put(pid, app);
2006 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2007 msg.obj = app;
2008 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2009 }
2010 } else {
2011 app.pid = 0;
2012 RuntimeException e = new RuntimeException(
2013 "Failure starting process " + app.processName
2014 + ": returned pid=" + pid);
2015 Log.e(TAG, e.getMessage(), e);
2016 }
2017 } catch (RuntimeException e) {
2018 // XXX do better error recovery.
2019 app.pid = 0;
2020 Log.e(TAG, "Failure starting process " + app.processName, e);
2021 }
2022 }
2023
2024 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2025 if (mPausingActivity != null) {
2026 RuntimeException e = new RuntimeException();
2027 Log.e(TAG, "Trying to pause when pause is already pending for "
2028 + mPausingActivity, e);
2029 }
2030 HistoryRecord prev = mResumedActivity;
2031 if (prev == null) {
2032 RuntimeException e = new RuntimeException();
2033 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2034 resumeTopActivityLocked(null);
2035 return;
2036 }
2037 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2038 mResumedActivity = null;
2039 mPausingActivity = prev;
2040 mLastPausedActivity = prev;
2041 prev.state = ActivityState.PAUSING;
2042 prev.task.touchActiveTime();
2043
2044 updateCpuStats();
2045
2046 if (prev.app != null && prev.app.thread != null) {
2047 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2048 try {
2049 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2050 System.identityHashCode(prev),
2051 prev.shortComponentName);
2052 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2053 prev.configChangeFlags);
2054 updateUsageStats(prev, false);
2055 } catch (Exception e) {
2056 // Ignore exception, if process died other code will cleanup.
2057 Log.w(TAG, "Exception thrown during pause", e);
2058 mPausingActivity = null;
2059 mLastPausedActivity = null;
2060 }
2061 } else {
2062 mPausingActivity = null;
2063 mLastPausedActivity = null;
2064 }
2065
2066 // If we are not going to sleep, we want to ensure the device is
2067 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002068 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 mLaunchingActivity.acquire();
2070 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2071 // To be safe, don't allow the wake lock to be held for too long.
2072 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2073 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2074 }
2075 }
2076
2077
2078 if (mPausingActivity != null) {
2079 // Have the window manager pause its key dispatching until the new
2080 // activity has started. If we're pausing the activity just because
2081 // the screen is being turned off and the UI is sleeping, don't interrupt
2082 // key dispatch; the same activity will pick it up again on wakeup.
2083 if (!uiSleeping) {
2084 prev.pauseKeyDispatchingLocked();
2085 } else {
2086 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2087 }
2088
2089 // Schedule a pause timeout in case the app doesn't respond.
2090 // We don't give it much time because this directly impacts the
2091 // responsiveness seen by the user.
2092 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2093 msg.obj = prev;
2094 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2095 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2096 } else {
2097 // This activity failed to schedule the
2098 // pause, so just treat it as being paused now.
2099 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2100 resumeTopActivityLocked(null);
2101 }
2102 }
2103
2104 private final void completePauseLocked() {
2105 HistoryRecord prev = mPausingActivity;
2106 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2107
2108 if (prev != null) {
2109 if (prev.finishing) {
2110 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2111 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2112 } else if (prev.app != null) {
2113 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2114 if (prev.waitingVisible) {
2115 prev.waitingVisible = false;
2116 mWaitingVisibleActivities.remove(prev);
2117 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2118 TAG, "Complete pause, no longer waiting: " + prev);
2119 }
2120 if (prev.configDestroy) {
2121 // The previous is being paused because the configuration
2122 // is changing, which means it is actually stopping...
2123 // To juggle the fact that we are also starting a new
2124 // instance right now, we need to first completely stop
2125 // the current instance before starting the new one.
2126 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2127 destroyActivityLocked(prev, true);
2128 } else {
2129 mStoppingActivities.add(prev);
2130 if (mStoppingActivities.size() > 3) {
2131 // If we already have a few activities waiting to stop,
2132 // then give up on things going idle and start clearing
2133 // them out.
2134 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2135 Message msg = Message.obtain();
2136 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2137 mHandler.sendMessage(msg);
2138 }
2139 }
2140 } else {
2141 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2142 prev = null;
2143 }
2144 mPausingActivity = null;
2145 }
2146
Dianne Hackborn55280a92009-05-07 15:53:46 -07002147 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148 resumeTopActivityLocked(prev);
2149 } else {
2150 if (mGoingToSleep.isHeld()) {
2151 mGoingToSleep.release();
2152 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002153 if (mShuttingDown) {
2154 notifyAll();
2155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 }
2157
2158 if (prev != null) {
2159 prev.resumeKeyDispatchingLocked();
2160 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002161
2162 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2163 long diff = 0;
2164 synchronized (mProcessStatsThread) {
2165 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2166 }
2167 if (diff > 0) {
2168 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2169 synchronized (bsi) {
2170 BatteryStatsImpl.Uid.Proc ps =
2171 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2172 prev.info.packageName);
2173 if (ps != null) {
2174 ps.addForegroundTimeLocked(diff);
2175 }
2176 }
2177 }
2178 }
2179 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002180 }
2181
2182 /**
2183 * Once we know that we have asked an application to put an activity in
2184 * the resumed state (either by launching it or explicitly telling it),
2185 * this function updates the rest of our state to match that fact.
2186 */
2187 private final void completeResumeLocked(HistoryRecord next) {
2188 next.idle = false;
2189 next.results = null;
2190 next.newIntents = null;
2191
2192 // schedule an idle timeout in case the app doesn't do it for us.
2193 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2194 msg.obj = next;
2195 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2196
2197 if (false) {
2198 // The activity was never told to pause, so just keep
2199 // things going as-is. To maintain our own state,
2200 // we need to emulate it coming back and saying it is
2201 // idle.
2202 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2203 msg.obj = next;
2204 mHandler.sendMessage(msg);
2205 }
2206
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002207 reportResumedActivity(next);
2208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 next.thumbnail = null;
2210 setFocusedActivityLocked(next);
2211 next.resumeKeyDispatchingLocked();
2212 ensureActivitiesVisibleLocked(null, 0);
2213 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002214
2215 // Mark the point when the activity is resuming
2216 // TODO: To be more accurate, the mark should be before the onCreate,
2217 // not after the onResume. But for subsequent starts, onResume is fine.
2218 if (next.app != null) {
2219 synchronized (mProcessStatsThread) {
2220 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2221 }
2222 } else {
2223 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002225 }
2226
2227 /**
2228 * Make sure that all activities that need to be visible (that is, they
2229 * currently can be seen by the user) actually are.
2230 */
2231 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2232 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2233 if (DEBUG_VISBILITY) Log.v(
2234 TAG, "ensureActivitiesVisible behind " + top
2235 + " configChanges=0x" + Integer.toHexString(configChanges));
2236
2237 // If the top activity is not fullscreen, then we need to
2238 // make sure any activities under it are now visible.
2239 final int count = mHistory.size();
2240 int i = count-1;
2241 while (mHistory.get(i) != top) {
2242 i--;
2243 }
2244 HistoryRecord r;
2245 boolean behindFullscreen = false;
2246 for (; i>=0; i--) {
2247 r = (HistoryRecord)mHistory.get(i);
2248 if (DEBUG_VISBILITY) Log.v(
2249 TAG, "Make visible? " + r + " finishing=" + r.finishing
2250 + " state=" + r.state);
2251 if (r.finishing) {
2252 continue;
2253 }
2254
2255 final boolean doThisProcess = onlyThisProcess == null
2256 || onlyThisProcess.equals(r.processName);
2257
2258 // First: if this is not the current activity being started, make
2259 // sure it matches the current configuration.
2260 if (r != starting && doThisProcess) {
2261 ensureActivityConfigurationLocked(r, 0);
2262 }
2263
2264 if (r.app == null || r.app.thread == null) {
2265 if (onlyThisProcess == null
2266 || onlyThisProcess.equals(r.processName)) {
2267 // This activity needs to be visible, but isn't even
2268 // running... get it started, but don't resume it
2269 // at this point.
2270 if (DEBUG_VISBILITY) Log.v(
2271 TAG, "Start and freeze screen for " + r);
2272 if (r != starting) {
2273 r.startFreezingScreenLocked(r.app, configChanges);
2274 }
2275 if (!r.visible) {
2276 if (DEBUG_VISBILITY) Log.v(
2277 TAG, "Starting and making visible: " + r);
2278 mWindowManager.setAppVisibility(r, true);
2279 }
2280 if (r != starting) {
2281 startSpecificActivityLocked(r, false, false);
2282 }
2283 }
2284
2285 } else if (r.visible) {
2286 // If this activity is already visible, then there is nothing
2287 // else to do here.
2288 if (DEBUG_VISBILITY) Log.v(
2289 TAG, "Skipping: already visible at " + r);
2290 r.stopFreezingScreenLocked(false);
2291
2292 } else if (onlyThisProcess == null) {
2293 // This activity is not currently visible, but is running.
2294 // Tell it to become visible.
2295 r.visible = true;
2296 if (r.state != ActivityState.RESUMED && r != starting) {
2297 // If this activity is paused, tell it
2298 // to now show its window.
2299 if (DEBUG_VISBILITY) Log.v(
2300 TAG, "Making visible and scheduling visibility: " + r);
2301 try {
2302 mWindowManager.setAppVisibility(r, true);
2303 r.app.thread.scheduleWindowVisibility(r, true);
2304 r.stopFreezingScreenLocked(false);
2305 } catch (Exception e) {
2306 // Just skip on any failure; we'll make it
2307 // visible when it next restarts.
2308 Log.w(TAG, "Exception thrown making visibile: "
2309 + r.intent.getComponent(), e);
2310 }
2311 }
2312 }
2313
2314 // Aggregate current change flags.
2315 configChanges |= r.configChangeFlags;
2316
2317 if (r.fullscreen) {
2318 // At this point, nothing else needs to be shown
2319 if (DEBUG_VISBILITY) Log.v(
2320 TAG, "Stopping: fullscreen at " + r);
2321 behindFullscreen = true;
2322 i--;
2323 break;
2324 }
2325 }
2326
2327 // Now for any activities that aren't visible to the user, make
2328 // sure they no longer are keeping the screen frozen.
2329 while (i >= 0) {
2330 r = (HistoryRecord)mHistory.get(i);
2331 if (DEBUG_VISBILITY) Log.v(
2332 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2333 + " state=" + r.state
2334 + " behindFullscreen=" + behindFullscreen);
2335 if (!r.finishing) {
2336 if (behindFullscreen) {
2337 if (r.visible) {
2338 if (DEBUG_VISBILITY) Log.v(
2339 TAG, "Making invisible: " + r);
2340 r.visible = false;
2341 try {
2342 mWindowManager.setAppVisibility(r, false);
2343 if ((r.state == ActivityState.STOPPING
2344 || r.state == ActivityState.STOPPED)
2345 && r.app != null && r.app.thread != null) {
2346 if (DEBUG_VISBILITY) Log.v(
2347 TAG, "Scheduling invisibility: " + r);
2348 r.app.thread.scheduleWindowVisibility(r, false);
2349 }
2350 } catch (Exception e) {
2351 // Just skip on any failure; we'll make it
2352 // visible when it next restarts.
2353 Log.w(TAG, "Exception thrown making hidden: "
2354 + r.intent.getComponent(), e);
2355 }
2356 } else {
2357 if (DEBUG_VISBILITY) Log.v(
2358 TAG, "Already invisible: " + r);
2359 }
2360 } else if (r.fullscreen) {
2361 if (DEBUG_VISBILITY) Log.v(
2362 TAG, "Now behindFullscreen: " + r);
2363 behindFullscreen = true;
2364 }
2365 }
2366 i--;
2367 }
2368 }
2369
2370 /**
2371 * Version of ensureActivitiesVisible that can easily be called anywhere.
2372 */
2373 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2374 int configChanges) {
2375 HistoryRecord r = topRunningActivityLocked(null);
2376 if (r != null) {
2377 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2378 }
2379 }
2380
2381 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2382 if (resumed) {
2383 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2384 } else {
2385 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2386 }
2387 }
2388
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002389 private boolean startHomeActivityLocked() {
2390 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2391 && mTopAction == null) {
2392 // We are running in factory test mode, but unable to find
2393 // the factory test app, so just sit around displaying the
2394 // error message and don't try to start anything.
2395 return false;
2396 }
2397 Intent intent = new Intent(
2398 mTopAction,
2399 mTopData != null ? Uri.parse(mTopData) : null);
2400 intent.setComponent(mTopComponent);
2401 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2402 intent.addCategory(Intent.CATEGORY_HOME);
2403 }
2404 ActivityInfo aInfo =
2405 intent.resolveActivityInfo(mContext.getPackageManager(),
2406 STOCK_PM_FLAGS);
2407 if (aInfo != null) {
2408 intent.setComponent(new ComponentName(
2409 aInfo.applicationInfo.packageName, aInfo.name));
2410 // Don't do this if the home app is currently being
2411 // instrumented.
2412 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2413 aInfo.applicationInfo.uid);
2414 if (app == null || app.instrumentationClass == null) {
2415 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2416 startActivityLocked(null, intent, null, null, 0, aInfo,
2417 null, null, 0, 0, 0, false, false);
2418 }
2419 }
2420
2421
2422 return true;
2423 }
2424
2425 /**
2426 * Starts the "new version setup screen" if appropriate.
2427 */
2428 private void startSetupActivityLocked() {
2429 // Only do this once per boot.
2430 if (mCheckedForSetup) {
2431 return;
2432 }
2433
2434 // We will show this screen if the current one is a different
2435 // version than the last one shown, and we are not running in
2436 // low-level factory test mode.
2437 final ContentResolver resolver = mContext.getContentResolver();
2438 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2439 Settings.Secure.getInt(resolver,
2440 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2441 mCheckedForSetup = true;
2442
2443 // See if we should be showing the platform update setup UI.
2444 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2445 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2446 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2447
2448 // We don't allow third party apps to replace this.
2449 ResolveInfo ri = null;
2450 for (int i=0; ris != null && i<ris.size(); i++) {
2451 if ((ris.get(i).activityInfo.applicationInfo.flags
2452 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2453 ri = ris.get(i);
2454 break;
2455 }
2456 }
2457
2458 if (ri != null) {
2459 String vers = ri.activityInfo.metaData != null
2460 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2461 : null;
2462 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2463 vers = ri.activityInfo.applicationInfo.metaData.getString(
2464 Intent.METADATA_SETUP_VERSION);
2465 }
2466 String lastVers = Settings.Secure.getString(
2467 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2468 if (vers != null && !vers.equals(lastVers)) {
2469 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2470 intent.setComponent(new ComponentName(
2471 ri.activityInfo.packageName, ri.activityInfo.name));
2472 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2473 null, null, 0, 0, 0, false, false);
2474 }
2475 }
2476 }
2477 }
2478
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002479 private void reportResumedActivity(HistoryRecord r) {
2480 //Log.i(TAG, "**** REPORT RESUME: " + r);
2481
2482 final int identHash = System.identityHashCode(r);
2483 updateUsageStats(r, true);
2484
2485 int i = mWatchers.beginBroadcast();
2486 while (i > 0) {
2487 i--;
2488 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2489 if (w != null) {
2490 try {
2491 w.activityResuming(identHash);
2492 } catch (RemoteException e) {
2493 }
2494 }
2495 }
2496 mWatchers.finishBroadcast();
2497 }
2498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002499 /**
2500 * Ensure that the top activity in the stack is resumed.
2501 *
2502 * @param prev The previously resumed activity, for when in the process
2503 * of pausing; can be null to call from elsewhere.
2504 *
2505 * @return Returns true if something is being resumed, or false if
2506 * nothing happened.
2507 */
2508 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2509 // Find the first activity that is not finishing.
2510 HistoryRecord next = topRunningActivityLocked(null);
2511
2512 // Remember how we'll process this pause/resume situation, and ensure
2513 // that the state is reset however we wind up proceeding.
2514 final boolean userLeaving = mUserLeaving;
2515 mUserLeaving = false;
2516
2517 if (next == null) {
2518 // There are no more activities! Let's just start up the
2519 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002520 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 }
2522
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002523 next.delayedResume = false;
2524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002525 // If the top activity is the resumed one, nothing to do.
2526 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2527 // Make sure we have executed any pending transitions, since there
2528 // should be nothing left to do at this point.
2529 mWindowManager.executeAppTransition();
2530 return false;
2531 }
2532
2533 // If we are sleeping, and there is no resumed activity, and the top
2534 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002535 if ((mSleeping || mShuttingDown)
2536 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002537 // Make sure we have executed any pending transitions, since there
2538 // should be nothing left to do at this point.
2539 mWindowManager.executeAppTransition();
2540 return false;
2541 }
2542
2543 // The activity may be waiting for stop, but that is no longer
2544 // appropriate for it.
2545 mStoppingActivities.remove(next);
2546 mWaitingVisibleActivities.remove(next);
2547
2548 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2549
2550 // If we are currently pausing an activity, then don't do anything
2551 // until that is done.
2552 if (mPausingActivity != null) {
2553 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2554 return false;
2555 }
2556
2557 // We need to start pausing the current activity so the top one
2558 // can be resumed...
2559 if (mResumedActivity != null) {
2560 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2561 startPausingLocked(userLeaving, false);
2562 return true;
2563 }
2564
2565 if (prev != null && prev != next) {
2566 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2567 prev.waitingVisible = true;
2568 mWaitingVisibleActivities.add(prev);
2569 if (DEBUG_SWITCH) Log.v(
2570 TAG, "Resuming top, waiting visible to hide: " + prev);
2571 } else {
2572 // The next activity is already visible, so hide the previous
2573 // activity's windows right now so we can show the new one ASAP.
2574 // We only do this if the previous is finishing, which should mean
2575 // it is on top of the one being resumed so hiding it quickly
2576 // is good. Otherwise, we want to do the normal route of allowing
2577 // the resumed activity to be shown so we can decide if the
2578 // previous should actually be hidden depending on whether the
2579 // new one is found to be full-screen or not.
2580 if (prev.finishing) {
2581 mWindowManager.setAppVisibility(prev, false);
2582 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2583 + prev + ", waitingVisible="
2584 + (prev != null ? prev.waitingVisible : null)
2585 + ", nowVisible=" + next.nowVisible);
2586 } else {
2587 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2588 + prev + ", waitingVisible="
2589 + (prev != null ? prev.waitingVisible : null)
2590 + ", nowVisible=" + next.nowVisible);
2591 }
2592 }
2593 }
2594
2595 // We are starting up the next activity, so tell the window manager
2596 // that the previous one will be hidden soon. This way it can know
2597 // to ignore it when computing the desired screen orientation.
2598 if (prev != null) {
2599 if (prev.finishing) {
2600 if (DEBUG_TRANSITION) Log.v(TAG,
2601 "Prepare close transition: prev=" + prev);
2602 mWindowManager.prepareAppTransition(prev.task == next.task
2603 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2604 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2605 mWindowManager.setAppWillBeHidden(prev);
2606 mWindowManager.setAppVisibility(prev, false);
2607 } else {
2608 if (DEBUG_TRANSITION) Log.v(TAG,
2609 "Prepare open transition: prev=" + prev);
2610 mWindowManager.prepareAppTransition(prev.task == next.task
2611 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2612 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2613 }
2614 if (false) {
2615 mWindowManager.setAppWillBeHidden(prev);
2616 mWindowManager.setAppVisibility(prev, false);
2617 }
2618 } else if (mHistory.size() > 1) {
2619 if (DEBUG_TRANSITION) Log.v(TAG,
2620 "Prepare open transition: no previous");
2621 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2622 }
2623
2624 if (next.app != null && next.app.thread != null) {
2625 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2626
2627 // This activity is now becoming visible.
2628 mWindowManager.setAppVisibility(next, true);
2629
2630 HistoryRecord lastResumedActivity = mResumedActivity;
2631 ActivityState lastState = next.state;
2632
2633 updateCpuStats();
2634
2635 next.state = ActivityState.RESUMED;
2636 mResumedActivity = next;
2637 next.task.touchActiveTime();
2638 updateLRUListLocked(next.app, true);
2639 updateLRUListLocked(next);
2640
2641 // Have the window manager re-evaluate the orientation of
2642 // the screen based on the new activity order.
2643 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002644 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002645 next.mayFreezeScreenLocked(next.app) ? next : null);
2646 if (config != null) {
2647 next.frozenBeforeDestroy = true;
2648 }
2649 if (!updateConfigurationLocked(config, next)) {
2650 // The configuration update wasn't able to keep the existing
2651 // instance of the activity, and instead started a new one.
2652 // We should be all done, but let's just make sure our activity
2653 // is still at the top and schedule another run if something
2654 // weird happened.
2655 HistoryRecord nextNext = topRunningActivityLocked(null);
2656 if (DEBUG_SWITCH) Log.i(TAG,
2657 "Activity config changed during resume: " + next
2658 + ", new next: " + nextNext);
2659 if (nextNext != next) {
2660 // Do over!
2661 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2662 }
2663 mWindowManager.executeAppTransition();
2664 return true;
2665 }
2666
2667 try {
2668 // Deliver all pending results.
2669 ArrayList a = next.results;
2670 if (a != null) {
2671 final int N = a.size();
2672 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002673 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 TAG, "Delivering results to " + next
2675 + ": " + a);
2676 next.app.thread.scheduleSendResult(next, a);
2677 }
2678 }
2679
2680 if (next.newIntents != null) {
2681 next.app.thread.scheduleNewIntent(next.newIntents, next);
2682 }
2683
2684 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2685 System.identityHashCode(next),
2686 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687
2688 next.app.thread.scheduleResumeActivity(next,
2689 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 pauseIfSleepingLocked();
2692
2693 } catch (Exception e) {
2694 // Whoops, need to restart this activity!
2695 next.state = lastState;
2696 mResumedActivity = lastResumedActivity;
2697 if (Config.LOGD) Log.d(TAG,
2698 "Restarting because process died: " + next);
2699 if (!next.hasBeenLaunched) {
2700 next.hasBeenLaunched = true;
2701 } else {
2702 if (SHOW_APP_STARTING_ICON) {
2703 mWindowManager.setAppStartingWindow(
2704 next, next.packageName, next.theme,
2705 next.nonLocalizedLabel,
2706 next.labelRes, next.icon, null, true);
2707 }
2708 }
2709 startSpecificActivityLocked(next, true, false);
2710 return true;
2711 }
2712
2713 // From this point on, if something goes wrong there is no way
2714 // to recover the activity.
2715 try {
2716 next.visible = true;
2717 completeResumeLocked(next);
2718 } catch (Exception e) {
2719 // If any exception gets thrown, toss away this
2720 // activity and try the next one.
2721 Log.w(TAG, "Exception thrown during resume of " + next, e);
2722 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2723 "resume-exception");
2724 return true;
2725 }
2726
2727 // Didn't need to use the icicle, and it is now out of date.
2728 next.icicle = null;
2729 next.haveState = false;
2730 next.stopped = false;
2731
2732 } else {
2733 // Whoops, need to restart this activity!
2734 if (!next.hasBeenLaunched) {
2735 next.hasBeenLaunched = true;
2736 } else {
2737 if (SHOW_APP_STARTING_ICON) {
2738 mWindowManager.setAppStartingWindow(
2739 next, next.packageName, next.theme,
2740 next.nonLocalizedLabel,
2741 next.labelRes, next.icon, null, true);
2742 }
2743 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2744 }
2745 startSpecificActivityLocked(next, true, true);
2746 }
2747
2748 return true;
2749 }
2750
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002751 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2752 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002753 final int NH = mHistory.size();
2754
2755 int addPos = -1;
2756
2757 if (!newTask) {
2758 // If starting in an existing task, find where that is...
2759 HistoryRecord next = null;
2760 boolean startIt = true;
2761 for (int i = NH-1; i >= 0; i--) {
2762 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2763 if (p.finishing) {
2764 continue;
2765 }
2766 if (p.task == r.task) {
2767 // Here it is! Now, if this is not yet visible to the
2768 // user, then just add it without starting; it will
2769 // get started when the user navigates back to it.
2770 addPos = i+1;
2771 if (!startIt) {
2772 mHistory.add(addPos, r);
2773 r.inHistory = true;
2774 r.task.numActivities++;
2775 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2776 r.info.screenOrientation, r.fullscreen);
2777 if (VALIDATE_TOKENS) {
2778 mWindowManager.validateAppTokens(mHistory);
2779 }
2780 return;
2781 }
2782 break;
2783 }
2784 if (p.fullscreen) {
2785 startIt = false;
2786 }
2787 next = p;
2788 }
2789 }
2790
2791 // Place a new activity at top of stack, so it is next to interact
2792 // with the user.
2793 if (addPos < 0) {
2794 addPos = mHistory.size();
2795 }
2796
2797 // If we are not placing the new activity frontmost, we do not want
2798 // to deliver the onUserLeaving callback to the actual frontmost
2799 // activity
2800 if (addPos < NH) {
2801 mUserLeaving = false;
2802 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2803 }
2804
2805 // Slot the activity into the history stack and proceed
2806 mHistory.add(addPos, r);
2807 r.inHistory = true;
2808 r.frontOfTask = newTask;
2809 r.task.numActivities++;
2810 if (NH > 0) {
2811 // We want to show the starting preview window if we are
2812 // switching to a new task, or the next activity's process is
2813 // not currently running.
2814 boolean showStartingIcon = newTask;
2815 ProcessRecord proc = r.app;
2816 if (proc == null) {
2817 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2818 }
2819 if (proc == null || proc.thread == null) {
2820 showStartingIcon = true;
2821 }
2822 if (DEBUG_TRANSITION) Log.v(TAG,
2823 "Prepare open transition: starting " + r);
2824 mWindowManager.prepareAppTransition(newTask
2825 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2826 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2827 mWindowManager.addAppToken(
2828 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2829 boolean doShow = true;
2830 if (newTask) {
2831 // Even though this activity is starting fresh, we still need
2832 // to reset it to make sure we apply affinities to move any
2833 // existing activities from other tasks in to it.
2834 // If the caller has requested that the target task be
2835 // reset, then do so.
2836 if ((r.intent.getFlags()
2837 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2838 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002839 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002840 }
2841 }
2842 if (SHOW_APP_STARTING_ICON && doShow) {
2843 // Figure out if we are transitioning from another activity that is
2844 // "has the same starting icon" as the next one. This allows the
2845 // window manager to keep the previous window it had previously
2846 // created, if it still had one.
2847 HistoryRecord prev = mResumedActivity;
2848 if (prev != null) {
2849 // We don't want to reuse the previous starting preview if:
2850 // (1) The current activity is in a different task.
2851 if (prev.task != r.task) prev = null;
2852 // (2) The current activity is already displayed.
2853 else if (prev.nowVisible) prev = null;
2854 }
2855 mWindowManager.setAppStartingWindow(
2856 r, r.packageName, r.theme, r.nonLocalizedLabel,
2857 r.labelRes, r.icon, prev, showStartingIcon);
2858 }
2859 } else {
2860 // If this is the first activity, don't do any fancy animations,
2861 // because there is nothing for it to animate on top of.
2862 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2863 r.info.screenOrientation, r.fullscreen);
2864 }
2865 if (VALIDATE_TOKENS) {
2866 mWindowManager.validateAppTokens(mHistory);
2867 }
2868
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002869 if (doResume) {
2870 resumeTopActivityLocked(null);
2871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002872 }
2873
2874 /**
2875 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002876 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2877 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002878 * an instance of that activity in the stack and, if found, finish all
2879 * activities on top of it and return the instance.
2880 *
2881 * @param newR Description of the new activity being started.
2882 * @return Returns the old activity that should be continue to be used,
2883 * or null if none was found.
2884 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002885 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 HistoryRecord newR, boolean doClear) {
2887 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002888
2889 // First find the requested task.
2890 while (i > 0) {
2891 i--;
2892 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2893 if (r.task.taskId == taskId) {
2894 i++;
2895 break;
2896 }
2897 }
2898
2899 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002900 while (i > 0) {
2901 i--;
2902 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2903 if (r.finishing) {
2904 continue;
2905 }
2906 if (r.task.taskId != taskId) {
2907 return null;
2908 }
2909 if (r.realActivity.equals(newR.realActivity)) {
2910 // Here it is! Now finish everything in front...
2911 HistoryRecord ret = r;
2912 if (doClear) {
2913 while (i < (mHistory.size()-1)) {
2914 i++;
2915 r = (HistoryRecord)mHistory.get(i);
2916 if (r.finishing) {
2917 continue;
2918 }
2919 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2920 null, "clear")) {
2921 i--;
2922 }
2923 }
2924 }
2925
2926 // Finally, if this is a normal launch mode (that is, not
2927 // expecting onNewIntent()), then we will finish the current
2928 // instance of the activity so a new fresh one can be started.
2929 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2930 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002931 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002932 if (index >= 0) {
2933 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2934 null, "clear");
2935 }
2936 return null;
2937 }
2938 }
2939
2940 return ret;
2941 }
2942 }
2943
2944 return null;
2945 }
2946
2947 /**
2948 * Find the activity in the history stack within the given task. Returns
2949 * the index within the history at which it's found, or < 0 if not found.
2950 */
2951 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2952 int i = mHistory.size();
2953 while (i > 0) {
2954 i--;
2955 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2956 if (candidate.task.taskId != task) {
2957 break;
2958 }
2959 if (candidate.realActivity.equals(r.realActivity)) {
2960 return i;
2961 }
2962 }
2963
2964 return -1;
2965 }
2966
2967 /**
2968 * Reorder the history stack so that the activity at the given index is
2969 * brought to the front.
2970 */
2971 private final HistoryRecord moveActivityToFrontLocked(int where) {
2972 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2973 int top = mHistory.size();
2974 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2975 mHistory.add(top, newTop);
2976 oldTop.frontOfTask = false;
2977 newTop.frontOfTask = true;
2978 return newTop;
2979 }
2980
2981 /**
2982 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2983 * method will be called at the proper time.
2984 */
2985 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2986 boolean sent = false;
2987 if (r.state == ActivityState.RESUMED
2988 && r.app != null && r.app.thread != null) {
2989 try {
2990 ArrayList<Intent> ar = new ArrayList<Intent>();
2991 ar.add(new Intent(intent));
2992 r.app.thread.scheduleNewIntent(ar, r);
2993 sent = true;
2994 } catch (Exception e) {
2995 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2996 }
2997 }
2998 if (!sent) {
2999 r.addNewIntentLocked(new Intent(intent));
3000 }
3001 }
3002
3003 private final void logStartActivity(int tag, HistoryRecord r,
3004 TaskRecord task) {
3005 EventLog.writeEvent(tag,
3006 System.identityHashCode(r), task.taskId,
3007 r.shortComponentName, r.intent.getAction(),
3008 r.intent.getType(), r.intent.getDataString(),
3009 r.intent.getFlags());
3010 }
3011
3012 private final int startActivityLocked(IApplicationThread caller,
3013 Intent intent, String resolvedType,
3014 Uri[] grantedUriPermissions,
3015 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3016 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003017 int callingPid, int callingUid, boolean onlyIfNeeded,
3018 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003019 Log.i(TAG, "Starting activity: " + intent);
3020
3021 HistoryRecord sourceRecord = null;
3022 HistoryRecord resultRecord = null;
3023 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003024 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003025 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003026 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3027 if (index >= 0) {
3028 sourceRecord = (HistoryRecord)mHistory.get(index);
3029 if (requestCode >= 0 && !sourceRecord.finishing) {
3030 resultRecord = sourceRecord;
3031 }
3032 }
3033 }
3034
3035 int launchFlags = intent.getFlags();
3036
3037 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3038 && sourceRecord != null) {
3039 // Transfer the result target from the source activity to the new
3040 // one being started, including any failures.
3041 if (requestCode >= 0) {
3042 return START_FORWARD_AND_REQUEST_CONFLICT;
3043 }
3044 resultRecord = sourceRecord.resultTo;
3045 resultWho = sourceRecord.resultWho;
3046 requestCode = sourceRecord.requestCode;
3047 sourceRecord.resultTo = null;
3048 if (resultRecord != null) {
3049 resultRecord.removeResultsLocked(
3050 sourceRecord, resultWho, requestCode);
3051 }
3052 }
3053
3054 int err = START_SUCCESS;
3055
3056 if (intent.getComponent() == null) {
3057 // We couldn't find a class that can handle the given Intent.
3058 // That's the end of that!
3059 err = START_INTENT_NOT_RESOLVED;
3060 }
3061
3062 if (err == START_SUCCESS && aInfo == null) {
3063 // We couldn't find the specific class specified in the Intent.
3064 // Also the end of the line.
3065 err = START_CLASS_NOT_FOUND;
3066 }
3067
3068 ProcessRecord callerApp = null;
3069 if (err == START_SUCCESS && caller != null) {
3070 callerApp = getRecordForAppLocked(caller);
3071 if (callerApp != null) {
3072 callingPid = callerApp.pid;
3073 callingUid = callerApp.info.uid;
3074 } else {
3075 Log.w(TAG, "Unable to find app for caller " + caller
3076 + " (pid=" + callingPid + ") when starting: "
3077 + intent.toString());
3078 err = START_PERMISSION_DENIED;
3079 }
3080 }
3081
3082 if (err != START_SUCCESS) {
3083 if (resultRecord != null) {
3084 sendActivityResultLocked(-1,
3085 resultRecord, resultWho, requestCode,
3086 Activity.RESULT_CANCELED, null);
3087 }
3088 return err;
3089 }
3090
3091 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3092 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3093 if (perm != PackageManager.PERMISSION_GRANTED) {
3094 if (resultRecord != null) {
3095 sendActivityResultLocked(-1,
3096 resultRecord, resultWho, requestCode,
3097 Activity.RESULT_CANCELED, null);
3098 }
3099 String msg = "Permission Denial: starting " + intent.toString()
3100 + " from " + callerApp + " (pid=" + callingPid
3101 + ", uid=" + callingUid + ")"
3102 + " requires " + aInfo.permission;
3103 Log.w(TAG, msg);
3104 throw new SecurityException(msg);
3105 }
3106
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003107 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003108 boolean abort = false;
3109 try {
3110 // The Intent we give to the watcher has the extra data
3111 // stripped off, since it can contain private information.
3112 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003113 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003114 aInfo.applicationInfo.packageName);
3115 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003116 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 }
3118
3119 if (abort) {
3120 if (resultRecord != null) {
3121 sendActivityResultLocked(-1,
3122 resultRecord, resultWho, requestCode,
3123 Activity.RESULT_CANCELED, null);
3124 }
3125 // We pretend to the caller that it was really started, but
3126 // they will just get a cancel result.
3127 return START_SUCCESS;
3128 }
3129 }
3130
3131 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3132 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003133 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003134
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003135 if (mResumedActivity == null
3136 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3137 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3138 PendingActivityLaunch pal = new PendingActivityLaunch();
3139 pal.r = r;
3140 pal.sourceRecord = sourceRecord;
3141 pal.grantedUriPermissions = grantedUriPermissions;
3142 pal.grantedMode = grantedMode;
3143 pal.onlyIfNeeded = onlyIfNeeded;
3144 mPendingActivityLaunches.add(pal);
3145 return START_SWITCHES_CANCELED;
3146 }
3147 }
3148
3149 if (mDidAppSwitch) {
3150 // This is the second allowed switch since we stopped switches,
3151 // so now just generally allow switches. Use case: user presses
3152 // home (switches disabled, switch to home, mDidAppSwitch now true);
3153 // user taps a home icon (coming from home so allowed, we hit here
3154 // and now allow anyone to switch again).
3155 mAppSwitchesAllowedTime = 0;
3156 } else {
3157 mDidAppSwitch = true;
3158 }
3159
3160 doPendingActivityLaunchesLocked(false);
3161
3162 return startActivityUncheckedLocked(r, sourceRecord,
3163 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3164 }
3165
3166 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3167 final int N = mPendingActivityLaunches.size();
3168 if (N <= 0) {
3169 return;
3170 }
3171 for (int i=0; i<N; i++) {
3172 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3173 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3174 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3175 doResume && i == (N-1));
3176 }
3177 mPendingActivityLaunches.clear();
3178 }
3179
3180 private final int startActivityUncheckedLocked(HistoryRecord r,
3181 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3182 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3183 final Intent intent = r.intent;
3184 final int callingUid = r.launchedFromUid;
3185
3186 int launchFlags = intent.getFlags();
3187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 // We'll invoke onUserLeaving before onPause only if the launching
3189 // activity did not explicitly state that this is an automated launch.
3190 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3191 if (DEBUG_USER_LEAVING) Log.v(TAG,
3192 "startActivity() => mUserLeaving=" + mUserLeaving);
3193
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003194 // If the caller has asked not to resume at this point, we make note
3195 // of this in the record so that we can skip it when trying to find
3196 // the top running activity.
3197 if (!doResume) {
3198 r.delayedResume = true;
3199 }
3200
3201 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3202 != 0 ? r : null;
3203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003204 // If the onlyIfNeeded flag is set, then we can do this if the activity
3205 // being launched is the same as the one making the call... or, as
3206 // a special case, if we do not know the caller then we count the
3207 // current top activity as the caller.
3208 if (onlyIfNeeded) {
3209 HistoryRecord checkedCaller = sourceRecord;
3210 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003211 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 }
3213 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3214 // Caller is not the same as launcher, so always needed.
3215 onlyIfNeeded = false;
3216 }
3217 }
3218
3219 if (grantedUriPermissions != null && callingUid > 0) {
3220 for (int i=0; i<grantedUriPermissions.length; i++) {
3221 grantUriPermissionLocked(callingUid, r.packageName,
3222 grantedUriPermissions[i], grantedMode, r);
3223 }
3224 }
3225
3226 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3227 intent, r);
3228
3229 if (sourceRecord == null) {
3230 // This activity is not being started from another... in this
3231 // case we -always- start a new task.
3232 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3233 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3234 + intent);
3235 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3236 }
3237 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3238 // The original activity who is starting us is running as a single
3239 // instance... this new activity it is starting must go on its
3240 // own task.
3241 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3242 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3243 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3244 // The activity being started is a single instance... it always
3245 // gets launched into its own task.
3246 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3247 }
3248
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003249 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003250 // For whatever reason this activity is being launched into a new
3251 // task... yet the caller has requested a result back. Well, that
3252 // is pretty messed up, so instead immediately send back a cancel
3253 // and let the new task continue launched as normal without a
3254 // dependency on its originator.
3255 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3256 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003257 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 Activity.RESULT_CANCELED, null);
3259 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260 }
3261
3262 boolean addingToTask = false;
3263 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3264 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3265 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3266 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3267 // If bring to front is requested, and no result is requested, and
3268 // we can find a task that was started with this same
3269 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003270 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271 // See if there is a task to bring to the front. If this is
3272 // a SINGLE_INSTANCE activity, there can be one and only one
3273 // instance of it in the history, and it is always in its own
3274 // unique task, so we do a special search.
3275 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3276 ? findTaskLocked(intent, r.info)
3277 : findActivityLocked(intent, r.info);
3278 if (taskTop != null) {
3279 if (taskTop.task.intent == null) {
3280 // This task was started because of movement of
3281 // the activity based on affinity... now that we
3282 // are actually launching it, we can assign the
3283 // base intent.
3284 taskTop.task.setIntent(intent, r.info);
3285 }
3286 // If the target task is not in the front, then we need
3287 // to bring it to the front... except... well, with
3288 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3289 // to have the same behavior as if a new instance was
3290 // being started, which means not bringing it to the front
3291 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003292 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 if (curTop.task != taskTop.task) {
3294 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3295 boolean callerAtFront = sourceRecord == null
3296 || curTop.task == sourceRecord.task;
3297 if (callerAtFront) {
3298 // We really do want to push this one into the
3299 // user's face, right now.
3300 moveTaskToFrontLocked(taskTop.task);
3301 }
3302 }
3303 // If the caller has requested that the target task be
3304 // reset, then do so.
3305 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3306 taskTop = resetTaskIfNeededLocked(taskTop, r);
3307 }
3308 if (onlyIfNeeded) {
3309 // We don't need to start a new activity, and
3310 // the client said not to do anything if that
3311 // is the case, so this is it! And for paranoia, make
3312 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003313 if (doResume) {
3314 resumeTopActivityLocked(null);
3315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003316 return START_RETURN_INTENT_TO_CALLER;
3317 }
3318 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3319 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3320 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3321 // In this situation we want to remove all activities
3322 // from the task up to the one being started. In most
3323 // cases this means we are resetting the task to its
3324 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003325 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 taskTop.task.taskId, r, true);
3327 if (top != null) {
3328 if (top.frontOfTask) {
3329 // Activity aliases may mean we use different
3330 // intents for the top activity, so make sure
3331 // the task now has the identity of the new
3332 // intent.
3333 top.task.setIntent(r.intent, r.info);
3334 }
3335 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3336 deliverNewIntentLocked(top, r.intent);
3337 } else {
3338 // A special case: we need to
3339 // start the activity because it is not currently
3340 // running, and the caller has asked to clear the
3341 // current task to have this activity at the top.
3342 addingToTask = true;
3343 // Now pretend like this activity is being started
3344 // by the top of its task, so it is put in the
3345 // right place.
3346 sourceRecord = taskTop;
3347 }
3348 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3349 // In this case the top activity on the task is the
3350 // same as the one being launched, so we take that
3351 // as a request to bring the task to the foreground.
3352 // If the top activity in the task is the root
3353 // activity, deliver this new intent to it if it
3354 // desires.
3355 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3356 && taskTop.realActivity.equals(r.realActivity)) {
3357 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3358 if (taskTop.frontOfTask) {
3359 taskTop.task.setIntent(r.intent, r.info);
3360 }
3361 deliverNewIntentLocked(taskTop, r.intent);
3362 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3363 // In this case we are launching the root activity
3364 // of the task, but with a different intent. We
3365 // should start a new instance on top.
3366 addingToTask = true;
3367 sourceRecord = taskTop;
3368 }
3369 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3370 // In this case an activity is being launched in to an
3371 // existing task, without resetting that task. This
3372 // is typically the situation of launching an activity
3373 // from a notification or shortcut. We want to place
3374 // the new activity on top of the current task.
3375 addingToTask = true;
3376 sourceRecord = taskTop;
3377 } else if (!taskTop.task.rootWasReset) {
3378 // In this case we are launching in to an existing task
3379 // that has not yet been started from its front door.
3380 // The current task has been brought to the front.
3381 // Ideally, we'd probably like to place this new task
3382 // at the bottom of its stack, but that's a little hard
3383 // to do with the current organization of the code so
3384 // for now we'll just drop it.
3385 taskTop.task.setIntent(r.intent, r.info);
3386 }
3387 if (!addingToTask) {
3388 // We didn't do anything... but it was needed (a.k.a., client
3389 // don't use that intent!) And for paranoia, make
3390 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003391 if (doResume) {
3392 resumeTopActivityLocked(null);
3393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 return START_TASK_TO_FRONT;
3395 }
3396 }
3397 }
3398 }
3399
3400 //String uri = r.intent.toURI();
3401 //Intent intent2 = new Intent(uri);
3402 //Log.i(TAG, "Given intent: " + r.intent);
3403 //Log.i(TAG, "URI is: " + uri);
3404 //Log.i(TAG, "To intent: " + intent2);
3405
3406 if (r.packageName != null) {
3407 // If the activity being launched is the same as the one currently
3408 // at the top, then we need to check if it should only be launched
3409 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003410 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3411 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412 if (top.realActivity.equals(r.realActivity)) {
3413 if (top.app != null && top.app.thread != null) {
3414 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3415 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3416 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3417 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3418 // For paranoia, make sure we have correctly
3419 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003420 if (doResume) {
3421 resumeTopActivityLocked(null);
3422 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 if (onlyIfNeeded) {
3424 // We don't need to start a new activity, and
3425 // the client said not to do anything if that
3426 // is the case, so this is it!
3427 return START_RETURN_INTENT_TO_CALLER;
3428 }
3429 deliverNewIntentLocked(top, r.intent);
3430 return START_DELIVERED_TO_TOP;
3431 }
3432 }
3433 }
3434 }
3435
3436 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003437 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003439 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 Activity.RESULT_CANCELED, null);
3441 }
3442 return START_CLASS_NOT_FOUND;
3443 }
3444
3445 boolean newTask = false;
3446
3447 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003448 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003449 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3450 // todo: should do better management of integers.
3451 mCurTask++;
3452 if (mCurTask <= 0) {
3453 mCurTask = 1;
3454 }
3455 r.task = new TaskRecord(mCurTask, r.info, intent,
3456 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3457 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3458 + " in new task " + r.task);
3459 newTask = true;
3460 addRecentTask(r.task);
3461
3462 } else if (sourceRecord != null) {
3463 if (!addingToTask &&
3464 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3465 // In this case, we are adding the activity to an existing
3466 // task, but the caller has asked to clear that task if the
3467 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003468 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 sourceRecord.task.taskId, r, true);
3470 if (top != null) {
3471 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3472 deliverNewIntentLocked(top, r.intent);
3473 // For paranoia, make sure we have correctly
3474 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003475 if (doResume) {
3476 resumeTopActivityLocked(null);
3477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 return START_DELIVERED_TO_TOP;
3479 }
3480 } else if (!addingToTask &&
3481 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3482 // In this case, we are launching an activity in our own task
3483 // that may already be running somewhere in the history, and
3484 // we want to shuffle it to the front of the stack if so.
3485 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3486 if (where >= 0) {
3487 HistoryRecord top = moveActivityToFrontLocked(where);
3488 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3489 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003490 if (doResume) {
3491 resumeTopActivityLocked(null);
3492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 return START_DELIVERED_TO_TOP;
3494 }
3495 }
3496 // An existing activity is starting this new activity, so we want
3497 // to keep the new one in the same task as the one that is starting
3498 // it.
3499 r.task = sourceRecord.task;
3500 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3501 + " in existing task " + r.task);
3502
3503 } else {
3504 // This not being started from an existing activity, and not part
3505 // of a new task... just put it in the top task, though these days
3506 // this case should never happen.
3507 final int N = mHistory.size();
3508 HistoryRecord prev =
3509 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3510 r.task = prev != null
3511 ? prev.task
3512 : new TaskRecord(mCurTask, r.info, intent,
3513 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3514 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3515 + " in new guessed " + r.task);
3516 }
3517 if (newTask) {
3518 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3519 }
3520 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003521 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003522 return START_SUCCESS;
3523 }
3524
3525 public final int startActivity(IApplicationThread caller,
3526 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3527 int grantedMode, IBinder resultTo,
3528 String resultWho, int requestCode, boolean onlyIfNeeded,
3529 boolean debug) {
3530 // Refuse possible leaked file descriptors
3531 if (intent != null && intent.hasFileDescriptors()) {
3532 throw new IllegalArgumentException("File descriptors passed in Intent");
3533 }
3534
The Android Open Source Project4df24232009-03-05 14:34:35 -08003535 final boolean componentSpecified = intent.getComponent() != null;
3536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 // Don't modify the client's object!
3538 intent = new Intent(intent);
3539
3540 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 ActivityInfo aInfo;
3542 try {
3543 ResolveInfo rInfo =
3544 ActivityThread.getPackageManager().resolveIntent(
3545 intent, resolvedType,
3546 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003547 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003548 aInfo = rInfo != null ? rInfo.activityInfo : null;
3549 } catch (RemoteException e) {
3550 aInfo = null;
3551 }
3552
3553 if (aInfo != null) {
3554 // Store the found target back into the intent, because now that
3555 // we have it we never want to do this again. For example, if the
3556 // user navigates back to this point in the history, we should
3557 // always restart the exact same activity.
3558 intent.setComponent(new ComponentName(
3559 aInfo.applicationInfo.packageName, aInfo.name));
3560
3561 // Don't debug things in the system process
3562 if (debug) {
3563 if (!aInfo.processName.equals("system")) {
3564 setDebugApp(aInfo.processName, true, false);
3565 }
3566 }
3567 }
3568
3569 synchronized(this) {
3570 final long origId = Binder.clearCallingIdentity();
3571 int res = startActivityLocked(caller, intent, resolvedType,
3572 grantedUriPermissions, grantedMode, aInfo,
3573 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003574 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003575 Binder.restoreCallingIdentity(origId);
3576 return res;
3577 }
3578 }
3579
3580 public boolean startNextMatchingActivity(IBinder callingActivity,
3581 Intent intent) {
3582 // Refuse possible leaked file descriptors
3583 if (intent != null && intent.hasFileDescriptors() == true) {
3584 throw new IllegalArgumentException("File descriptors passed in Intent");
3585 }
3586
3587 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003588 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 if (index < 0) {
3590 return false;
3591 }
3592 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3593 if (r.app == null || r.app.thread == null) {
3594 // The caller is not running... d'oh!
3595 return false;
3596 }
3597 intent = new Intent(intent);
3598 // The caller is not allowed to change the data.
3599 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3600 // And we are resetting to find the next component...
3601 intent.setComponent(null);
3602
3603 ActivityInfo aInfo = null;
3604 try {
3605 List<ResolveInfo> resolves =
3606 ActivityThread.getPackageManager().queryIntentActivities(
3607 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003608 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003609
3610 // Look for the original activity in the list...
3611 final int N = resolves != null ? resolves.size() : 0;
3612 for (int i=0; i<N; i++) {
3613 ResolveInfo rInfo = resolves.get(i);
3614 if (rInfo.activityInfo.packageName.equals(r.packageName)
3615 && rInfo.activityInfo.name.equals(r.info.name)) {
3616 // We found the current one... the next matching is
3617 // after it.
3618 i++;
3619 if (i<N) {
3620 aInfo = resolves.get(i).activityInfo;
3621 }
3622 break;
3623 }
3624 }
3625 } catch (RemoteException e) {
3626 }
3627
3628 if (aInfo == null) {
3629 // Nobody who is next!
3630 return false;
3631 }
3632
3633 intent.setComponent(new ComponentName(
3634 aInfo.applicationInfo.packageName, aInfo.name));
3635 intent.setFlags(intent.getFlags()&~(
3636 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3637 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3638 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3639 Intent.FLAG_ACTIVITY_NEW_TASK));
3640
3641 // Okay now we need to start the new activity, replacing the
3642 // currently running activity. This is a little tricky because
3643 // we want to start the new one as if the current one is finished,
3644 // but not finish the current one first so that there is no flicker.
3645 // And thus...
3646 final boolean wasFinishing = r.finishing;
3647 r.finishing = true;
3648
3649 // Propagate reply information over to the new activity.
3650 final HistoryRecord resultTo = r.resultTo;
3651 final String resultWho = r.resultWho;
3652 final int requestCode = r.requestCode;
3653 r.resultTo = null;
3654 if (resultTo != null) {
3655 resultTo.removeResultsLocked(r, resultWho, requestCode);
3656 }
3657
3658 final long origId = Binder.clearCallingIdentity();
3659 // XXX we are not dealing with propagating grantedUriPermissions...
3660 // those are not yet exposed to user code, so there is no need.
3661 int res = startActivityLocked(r.app.thread, intent,
3662 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003663 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003664 Binder.restoreCallingIdentity(origId);
3665
3666 r.finishing = wasFinishing;
3667 if (res != START_SUCCESS) {
3668 return false;
3669 }
3670 return true;
3671 }
3672 }
3673
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003674 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003675 Intent intent, String resolvedType, IBinder resultTo,
3676 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003677
3678 // This is so super not safe, that only the system (or okay root)
3679 // can do it.
3680 final int callingUid = Binder.getCallingUid();
3681 if (callingUid != 0 && callingUid != Process.myUid()) {
3682 throw new SecurityException(
3683 "startActivityInPackage only available to the system");
3684 }
3685
The Android Open Source Project4df24232009-03-05 14:34:35 -08003686 final boolean componentSpecified = intent.getComponent() != null;
3687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688 // Don't modify the client's object!
3689 intent = new Intent(intent);
3690
3691 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 ActivityInfo aInfo;
3693 try {
3694 ResolveInfo rInfo =
3695 ActivityThread.getPackageManager().resolveIntent(
3696 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003697 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003698 aInfo = rInfo != null ? rInfo.activityInfo : null;
3699 } catch (RemoteException e) {
3700 aInfo = null;
3701 }
3702
3703 if (aInfo != null) {
3704 // Store the found target back into the intent, because now that
3705 // we have it we never want to do this again. For example, if the
3706 // user navigates back to this point in the history, we should
3707 // always restart the exact same activity.
3708 intent.setComponent(new ComponentName(
3709 aInfo.applicationInfo.packageName, aInfo.name));
3710 }
3711
3712 synchronized(this) {
3713 return startActivityLocked(null, intent, resolvedType,
3714 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003715 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003716 }
3717 }
3718
3719 private final void addRecentTask(TaskRecord task) {
3720 // Remove any existing entries that are the same kind of task.
3721 int N = mRecentTasks.size();
3722 for (int i=0; i<N; i++) {
3723 TaskRecord tr = mRecentTasks.get(i);
3724 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3725 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3726 mRecentTasks.remove(i);
3727 i--;
3728 N--;
3729 if (task.intent == null) {
3730 // If the new recent task we are adding is not fully
3731 // specified, then replace it with the existing recent task.
3732 task = tr;
3733 }
3734 }
3735 }
3736 if (N >= MAX_RECENT_TASKS) {
3737 mRecentTasks.remove(N-1);
3738 }
3739 mRecentTasks.add(0, task);
3740 }
3741
3742 public void setRequestedOrientation(IBinder token,
3743 int requestedOrientation) {
3744 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003745 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 if (index < 0) {
3747 return;
3748 }
3749 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3750 final long origId = Binder.clearCallingIdentity();
3751 mWindowManager.setAppOrientation(r, requestedOrientation);
3752 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003753 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 r.mayFreezeScreenLocked(r.app) ? r : null);
3755 if (config != null) {
3756 r.frozenBeforeDestroy = true;
3757 if (!updateConfigurationLocked(config, r)) {
3758 resumeTopActivityLocked(null);
3759 }
3760 }
3761 Binder.restoreCallingIdentity(origId);
3762 }
3763 }
3764
3765 public int getRequestedOrientation(IBinder token) {
3766 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003767 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003768 if (index < 0) {
3769 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3770 }
3771 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3772 return mWindowManager.getAppOrientation(r);
3773 }
3774 }
3775
3776 private final void stopActivityLocked(HistoryRecord r) {
3777 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3778 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3779 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3780 if (!r.finishing) {
3781 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3782 "no-history");
3783 }
3784 } else if (r.app != null && r.app.thread != null) {
3785 if (mFocusedActivity == r) {
3786 setFocusedActivityLocked(topRunningActivityLocked(null));
3787 }
3788 r.resumeKeyDispatchingLocked();
3789 try {
3790 r.stopped = false;
3791 r.state = ActivityState.STOPPING;
3792 if (DEBUG_VISBILITY) Log.v(
3793 TAG, "Stopping visible=" + r.visible + " for " + r);
3794 if (!r.visible) {
3795 mWindowManager.setAppVisibility(r, false);
3796 }
3797 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3798 } catch (Exception e) {
3799 // Maybe just ignore exceptions here... if the process
3800 // has crashed, our death notification will clean things
3801 // up.
3802 Log.w(TAG, "Exception thrown during pause", e);
3803 // Just in case, assume it to be stopped.
3804 r.stopped = true;
3805 r.state = ActivityState.STOPPED;
3806 if (r.configDestroy) {
3807 destroyActivityLocked(r, true);
3808 }
3809 }
3810 }
3811 }
3812
3813 /**
3814 * @return Returns true if the activity is being finished, false if for
3815 * some reason it is being left as-is.
3816 */
3817 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3818 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003819 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 TAG, "Finishing activity: token=" + token
3821 + ", result=" + resultCode + ", data=" + resultData);
3822
Dianne Hackborn75b03852009-06-12 15:43:26 -07003823 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003824 if (index < 0) {
3825 return false;
3826 }
3827 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3828
3829 // Is this the last activity left?
3830 boolean lastActivity = true;
3831 for (int i=mHistory.size()-1; i>=0; i--) {
3832 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3833 if (!p.finishing && p != r) {
3834 lastActivity = false;
3835 break;
3836 }
3837 }
3838
3839 // If this is the last activity, but it is the home activity, then
3840 // just don't finish it.
3841 if (lastActivity) {
3842 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3843 return false;
3844 }
3845 }
3846
3847 finishActivityLocked(r, index, resultCode, resultData, reason);
3848 return true;
3849 }
3850
3851 /**
3852 * @return Returns true if this activity has been removed from the history
3853 * list, or false if it is still in the list and will be removed later.
3854 */
3855 private final boolean finishActivityLocked(HistoryRecord r, int index,
3856 int resultCode, Intent resultData, String reason) {
3857 if (r.finishing) {
3858 Log.w(TAG, "Duplicate finish request for " + r);
3859 return false;
3860 }
3861
3862 r.finishing = true;
3863 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3864 System.identityHashCode(r),
3865 r.task.taskId, r.shortComponentName, reason);
3866 r.task.numActivities--;
3867 if (r.frontOfTask && index < (mHistory.size()-1)) {
3868 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3869 if (next.task == r.task) {
3870 next.frontOfTask = true;
3871 }
3872 }
3873
3874 r.pauseKeyDispatchingLocked();
3875 if (mFocusedActivity == r) {
3876 setFocusedActivityLocked(topRunningActivityLocked(null));
3877 }
3878
3879 // send the result
3880 HistoryRecord resultTo = r.resultTo;
3881 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003882 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3883 + " who=" + r.resultWho + " req=" + r.requestCode
3884 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885 if (r.info.applicationInfo.uid > 0) {
3886 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3887 r.packageName, resultData, r);
3888 }
3889 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3890 resultData);
3891 r.resultTo = null;
3892 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003893 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003894
3895 // Make sure this HistoryRecord is not holding on to other resources,
3896 // because clients have remote IPC references to this object so we
3897 // can't assume that will go away and want to avoid circular IPC refs.
3898 r.results = null;
3899 r.pendingResults = null;
3900 r.newIntents = null;
3901 r.icicle = null;
3902
3903 if (mPendingThumbnails.size() > 0) {
3904 // There are clients waiting to receive thumbnails so, in case
3905 // this is an activity that someone is waiting for, add it
3906 // to the pending list so we can correctly update the clients.
3907 mCancelledThumbnails.add(r);
3908 }
3909
3910 if (mResumedActivity == r) {
3911 boolean endTask = index <= 0
3912 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3913 if (DEBUG_TRANSITION) Log.v(TAG,
3914 "Prepare close transition: finishing " + r);
3915 mWindowManager.prepareAppTransition(endTask
3916 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3917 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3918
3919 // Tell window manager to prepare for this one to be removed.
3920 mWindowManager.setAppVisibility(r, false);
3921
3922 if (mPausingActivity == null) {
3923 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3924 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3925 startPausingLocked(false, false);
3926 }
3927
3928 } else if (r.state != ActivityState.PAUSING) {
3929 // If the activity is PAUSING, we will complete the finish once
3930 // it is done pausing; else we can just directly finish it here.
3931 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3932 return finishCurrentActivityLocked(r, index,
3933 FINISH_AFTER_PAUSE) == null;
3934 } else {
3935 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3936 }
3937
3938 return false;
3939 }
3940
3941 private static final int FINISH_IMMEDIATELY = 0;
3942 private static final int FINISH_AFTER_PAUSE = 1;
3943 private static final int FINISH_AFTER_VISIBLE = 2;
3944
3945 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3946 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003947 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003948 if (index < 0) {
3949 return null;
3950 }
3951
3952 return finishCurrentActivityLocked(r, index, mode);
3953 }
3954
3955 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3956 int index, int mode) {
3957 // First things first: if this activity is currently visible,
3958 // and the resumed activity is not yet visible, then hold off on
3959 // finishing until the resumed one becomes visible.
3960 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3961 if (!mStoppingActivities.contains(r)) {
3962 mStoppingActivities.add(r);
3963 if (mStoppingActivities.size() > 3) {
3964 // If we already have a few activities waiting to stop,
3965 // then give up on things going idle and start clearing
3966 // them out.
3967 Message msg = Message.obtain();
3968 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3969 mHandler.sendMessage(msg);
3970 }
3971 }
3972 r.state = ActivityState.STOPPING;
3973 updateOomAdjLocked();
3974 return r;
3975 }
3976
3977 // make sure the record is cleaned out of other places.
3978 mStoppingActivities.remove(r);
3979 mWaitingVisibleActivities.remove(r);
3980 if (mResumedActivity == r) {
3981 mResumedActivity = null;
3982 }
3983 final ActivityState prevState = r.state;
3984 r.state = ActivityState.FINISHING;
3985
3986 if (mode == FINISH_IMMEDIATELY
3987 || prevState == ActivityState.STOPPED
3988 || prevState == ActivityState.INITIALIZING) {
3989 // If this activity is already stopped, we can just finish
3990 // it right now.
3991 return destroyActivityLocked(r, true) ? null : r;
3992 } else {
3993 // Need to go through the full pause cycle to get this
3994 // activity into the stopped state and then finish it.
3995 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3996 mFinishingActivities.add(r);
3997 resumeTopActivityLocked(null);
3998 }
3999 return r;
4000 }
4001
4002 /**
4003 * This is the internal entry point for handling Activity.finish().
4004 *
4005 * @param token The Binder token referencing the Activity we want to finish.
4006 * @param resultCode Result code, if any, from this Activity.
4007 * @param resultData Result data (Intent), if any, from this Activity.
4008 *
4009 * @result Returns true if the activity successfully finished, or false if it is still running.
4010 */
4011 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4012 // Refuse possible leaked file descriptors
4013 if (resultData != null && resultData.hasFileDescriptors() == true) {
4014 throw new IllegalArgumentException("File descriptors passed in Intent");
4015 }
4016
4017 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004018 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004019 // Find the first activity that is not finishing.
4020 HistoryRecord next = topRunningActivityLocked(token, 0);
4021 if (next != null) {
4022 // ask watcher if this is allowed
4023 boolean resumeOK = true;
4024 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004025 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004027 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004028 }
4029
4030 if (!resumeOK) {
4031 return false;
4032 }
4033 }
4034 }
4035 final long origId = Binder.clearCallingIdentity();
4036 boolean res = requestFinishActivityLocked(token, resultCode,
4037 resultData, "app-request");
4038 Binder.restoreCallingIdentity(origId);
4039 return res;
4040 }
4041 }
4042
4043 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4044 String resultWho, int requestCode, int resultCode, Intent data) {
4045
4046 if (callingUid > 0) {
4047 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4048 data, r);
4049 }
4050
The Android Open Source Project10592532009-03-18 17:39:46 -07004051 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4052 + " : who=" + resultWho + " req=" + requestCode
4053 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4055 try {
4056 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4057 list.add(new ResultInfo(resultWho, requestCode,
4058 resultCode, data));
4059 r.app.thread.scheduleSendResult(r, list);
4060 return;
4061 } catch (Exception e) {
4062 Log.w(TAG, "Exception thrown sending result to " + r, e);
4063 }
4064 }
4065
4066 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4067 }
4068
4069 public final void finishSubActivity(IBinder token, String resultWho,
4070 int requestCode) {
4071 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004072 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004073 if (index < 0) {
4074 return;
4075 }
4076 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4077
4078 final long origId = Binder.clearCallingIdentity();
4079
4080 int i;
4081 for (i=mHistory.size()-1; i>=0; i--) {
4082 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4083 if (r.resultTo == self && r.requestCode == requestCode) {
4084 if ((r.resultWho == null && resultWho == null) ||
4085 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4086 finishActivityLocked(r, i,
4087 Activity.RESULT_CANCELED, null, "request-sub");
4088 }
4089 }
4090 }
4091
4092 Binder.restoreCallingIdentity(origId);
4093 }
4094 }
4095
4096 /**
4097 * Perform clean-up of service connections in an activity record.
4098 */
4099 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4100 // Throw away any services that have been bound by this activity.
4101 if (r.connections != null) {
4102 Iterator<ConnectionRecord> it = r.connections.iterator();
4103 while (it.hasNext()) {
4104 ConnectionRecord c = it.next();
4105 removeConnectionLocked(c, null, r);
4106 }
4107 r.connections = null;
4108 }
4109 }
4110
4111 /**
4112 * Perform the common clean-up of an activity record. This is called both
4113 * as part of destroyActivityLocked() (when destroying the client-side
4114 * representation) and cleaning things up as a result of its hosting
4115 * processing going away, in which case there is no remaining client-side
4116 * state to destroy so only the cleanup here is needed.
4117 */
4118 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4119 if (mResumedActivity == r) {
4120 mResumedActivity = null;
4121 }
4122 if (mFocusedActivity == r) {
4123 mFocusedActivity = null;
4124 }
4125
4126 r.configDestroy = false;
4127 r.frozenBeforeDestroy = false;
4128
4129 // Make sure this record is no longer in the pending finishes list.
4130 // This could happen, for example, if we are trimming activities
4131 // down to the max limit while they are still waiting to finish.
4132 mFinishingActivities.remove(r);
4133 mWaitingVisibleActivities.remove(r);
4134
4135 // Remove any pending results.
4136 if (r.finishing && r.pendingResults != null) {
4137 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4138 PendingIntentRecord rec = apr.get();
4139 if (rec != null) {
4140 cancelIntentSenderLocked(rec, false);
4141 }
4142 }
4143 r.pendingResults = null;
4144 }
4145
4146 if (cleanServices) {
4147 cleanUpActivityServicesLocked(r);
4148 }
4149
4150 if (mPendingThumbnails.size() > 0) {
4151 // There are clients waiting to receive thumbnails so, in case
4152 // this is an activity that someone is waiting for, add it
4153 // to the pending list so we can correctly update the clients.
4154 mCancelledThumbnails.add(r);
4155 }
4156
4157 // Get rid of any pending idle timeouts.
4158 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4159 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4160 }
4161
4162 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4163 if (r.state != ActivityState.DESTROYED) {
4164 mHistory.remove(r);
4165 r.inHistory = false;
4166 r.state = ActivityState.DESTROYED;
4167 mWindowManager.removeAppToken(r);
4168 if (VALIDATE_TOKENS) {
4169 mWindowManager.validateAppTokens(mHistory);
4170 }
4171 cleanUpActivityServicesLocked(r);
4172 removeActivityUriPermissionsLocked(r);
4173 }
4174 }
4175
4176 /**
4177 * Destroy the current CLIENT SIDE instance of an activity. This may be
4178 * called both when actually finishing an activity, or when performing
4179 * a configuration switch where we destroy the current client-side object
4180 * but then create a new client-side object for this same HistoryRecord.
4181 */
4182 private final boolean destroyActivityLocked(HistoryRecord r,
4183 boolean removeFromApp) {
4184 if (DEBUG_SWITCH) Log.v(
4185 TAG, "Removing activity: token=" + r
4186 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4187 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4188 System.identityHashCode(r),
4189 r.task.taskId, r.shortComponentName);
4190
4191 boolean removedFromHistory = false;
4192
4193 cleanUpActivityLocked(r, false);
4194
4195 if (r.app != null) {
4196 if (removeFromApp) {
4197 int idx = r.app.activities.indexOf(r);
4198 if (idx >= 0) {
4199 r.app.activities.remove(idx);
4200 }
4201 if (r.persistent) {
4202 decPersistentCountLocked(r.app);
4203 }
4204 }
4205
4206 boolean skipDestroy = false;
4207
4208 try {
4209 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4210 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4211 r.configChangeFlags);
4212 } catch (Exception e) {
4213 // We can just ignore exceptions here... if the process
4214 // has crashed, our death notification will clean things
4215 // up.
4216 //Log.w(TAG, "Exception thrown during finish", e);
4217 if (r.finishing) {
4218 removeActivityFromHistoryLocked(r);
4219 removedFromHistory = true;
4220 skipDestroy = true;
4221 }
4222 }
4223
4224 r.app = null;
4225 r.nowVisible = false;
4226
4227 if (r.finishing && !skipDestroy) {
4228 r.state = ActivityState.DESTROYING;
4229 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4230 msg.obj = r;
4231 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4232 } else {
4233 r.state = ActivityState.DESTROYED;
4234 }
4235 } else {
4236 // remove this record from the history.
4237 if (r.finishing) {
4238 removeActivityFromHistoryLocked(r);
4239 removedFromHistory = true;
4240 } else {
4241 r.state = ActivityState.DESTROYED;
4242 }
4243 }
4244
4245 r.configChangeFlags = 0;
4246
4247 if (!mLRUActivities.remove(r)) {
4248 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4249 }
4250
4251 return removedFromHistory;
4252 }
4253
4254 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4255 ProcessRecord app)
4256 {
4257 int i = list.size();
4258 if (localLOGV) Log.v(
4259 TAG, "Removing app " + app + " from list " + list
4260 + " with " + i + " entries");
4261 while (i > 0) {
4262 i--;
4263 HistoryRecord r = (HistoryRecord)list.get(i);
4264 if (localLOGV) Log.v(
4265 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4266 if (r.app == app) {
4267 if (localLOGV) Log.v(TAG, "Removing this entry!");
4268 list.remove(i);
4269 }
4270 }
4271 }
4272
4273 /**
4274 * Main function for removing an existing process from the activity manager
4275 * as a result of that process going away. Clears out all connections
4276 * to the process.
4277 */
4278 private final void handleAppDiedLocked(ProcessRecord app,
4279 boolean restarting) {
4280 cleanUpApplicationRecordLocked(app, restarting, -1);
4281 if (!restarting) {
4282 mLRUProcesses.remove(app);
4283 }
4284
4285 // Just in case...
4286 if (mPausingActivity != null && mPausingActivity.app == app) {
4287 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4288 mPausingActivity = null;
4289 }
4290 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4291 mLastPausedActivity = null;
4292 }
4293
4294 // Remove this application's activities from active lists.
4295 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4296 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4297 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4298 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4299
4300 boolean atTop = true;
4301 boolean hasVisibleActivities = false;
4302
4303 // Clean out the history list.
4304 int i = mHistory.size();
4305 if (localLOGV) Log.v(
4306 TAG, "Removing app " + app + " from history with " + i + " entries");
4307 while (i > 0) {
4308 i--;
4309 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4310 if (localLOGV) Log.v(
4311 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4312 if (r.app == app) {
4313 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4314 if (localLOGV) Log.v(
4315 TAG, "Removing this entry! frozen=" + r.haveState
4316 + " finishing=" + r.finishing);
4317 mHistory.remove(i);
4318
4319 r.inHistory = false;
4320 mWindowManager.removeAppToken(r);
4321 if (VALIDATE_TOKENS) {
4322 mWindowManager.validateAppTokens(mHistory);
4323 }
4324 removeActivityUriPermissionsLocked(r);
4325
4326 } else {
4327 // We have the current state for this activity, so
4328 // it can be restarted later when needed.
4329 if (localLOGV) Log.v(
4330 TAG, "Keeping entry, setting app to null");
4331 if (r.visible) {
4332 hasVisibleActivities = true;
4333 }
4334 r.app = null;
4335 r.nowVisible = false;
4336 if (!r.haveState) {
4337 r.icicle = null;
4338 }
4339 }
4340
4341 cleanUpActivityLocked(r, true);
4342 r.state = ActivityState.STOPPED;
4343 }
4344 atTop = false;
4345 }
4346
4347 app.activities.clear();
4348
4349 if (app.instrumentationClass != null) {
4350 Log.w(TAG, "Crash of app " + app.processName
4351 + " running instrumentation " + app.instrumentationClass);
4352 Bundle info = new Bundle();
4353 info.putString("shortMsg", "Process crashed.");
4354 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4355 }
4356
4357 if (!restarting) {
4358 if (!resumeTopActivityLocked(null)) {
4359 // If there was nothing to resume, and we are not already
4360 // restarting this process, but there is a visible activity that
4361 // is hosted by the process... then make sure all visible
4362 // activities are running, taking care of restarting this
4363 // process.
4364 if (hasVisibleActivities) {
4365 ensureActivitiesVisibleLocked(null, 0);
4366 }
4367 }
4368 }
4369 }
4370
4371 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4372 IBinder threadBinder = thread.asBinder();
4373
4374 // Find the application record.
4375 int count = mLRUProcesses.size();
4376 int i;
4377 for (i=0; i<count; i++) {
4378 ProcessRecord rec = mLRUProcesses.get(i);
4379 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4380 return i;
4381 }
4382 }
4383 return -1;
4384 }
4385
4386 private final ProcessRecord getRecordForAppLocked(
4387 IApplicationThread thread) {
4388 if (thread == null) {
4389 return null;
4390 }
4391
4392 int appIndex = getLRURecordIndexForAppLocked(thread);
4393 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4394 }
4395
4396 private final void appDiedLocked(ProcessRecord app, int pid,
4397 IApplicationThread thread) {
4398
4399 mProcDeaths[0]++;
4400
4401 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4402 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4403 + ") has died.");
4404 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4405 if (localLOGV) Log.v(
4406 TAG, "Dying app: " + app + ", pid: " + pid
4407 + ", thread: " + thread.asBinder());
4408 boolean doLowMem = app.instrumentationClass == null;
4409 handleAppDiedLocked(app, false);
4410
4411 if (doLowMem) {
4412 // If there are no longer any background processes running,
4413 // and the app that died was not running instrumentation,
4414 // then tell everyone we are now low on memory.
4415 boolean haveBg = false;
4416 int count = mLRUProcesses.size();
4417 int i;
4418 for (i=0; i<count; i++) {
4419 ProcessRecord rec = mLRUProcesses.get(i);
4420 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4421 haveBg = true;
4422 break;
4423 }
4424 }
4425
4426 if (!haveBg) {
4427 Log.i(TAG, "Low Memory: No more background processes.");
4428 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4429 for (i=0; i<count; i++) {
4430 ProcessRecord rec = mLRUProcesses.get(i);
4431 if (rec.thread != null) {
4432 rec.lastRequestedGc = SystemClock.uptimeMillis();
4433 try {
4434 rec.thread.scheduleLowMemory();
4435 } catch (RemoteException e) {
4436 // Don't care if the process is gone.
4437 }
4438 }
4439 }
4440 }
4441 }
4442 } else if (Config.LOGD) {
4443 Log.d(TAG, "Received spurious death notification for thread "
4444 + thread.asBinder());
4445 }
4446 }
4447
4448 final String readFile(String filename) {
4449 try {
4450 FileInputStream fs = new FileInputStream(filename);
4451 byte[] inp = new byte[8192];
4452 int size = fs.read(inp);
4453 fs.close();
4454 return new String(inp, 0, 0, size);
4455 } catch (java.io.IOException e) {
4456 }
4457 return "";
4458 }
4459
4460 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004461 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004462 if (app.notResponding || app.crashing) {
4463 return;
4464 }
4465
4466 // Log the ANR to the event log.
4467 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4468
4469 // If we are on a secure build and the application is not interesting to the user (it is
4470 // not visible or in the background), just kill it instead of displaying a dialog.
4471 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4472 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4473 Process.killProcess(app.pid);
4474 return;
4475 }
4476
4477 // DeviceMonitor.start();
4478
4479 String processInfo = null;
4480 if (MONITOR_CPU_USAGE) {
4481 updateCpuStatsNow();
4482 synchronized (mProcessStatsThread) {
4483 processInfo = mProcessStats.printCurrentState();
4484 }
4485 }
4486
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004487 StringBuilder info = mStringBuilder;
4488 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004489 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004490 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004491 if (reportedActivity != null && reportedActivity.app != null) {
4492 info.append(" (last in ");
4493 info.append(reportedActivity.app.processName);
4494 info.append(")");
4495 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004496 if (annotation != null) {
4497 info.append("\nAnnotation: ");
4498 info.append(annotation);
4499 }
4500 if (MONITOR_CPU_USAGE) {
4501 info.append("\nCPU usage:\n");
4502 info.append(processInfo);
4503 }
4504 Log.i(TAG, info.toString());
4505
4506 // The application is not responding. Dump as many thread traces as we can.
4507 boolean fileDump = prepareTraceFile(true);
4508 if (!fileDump) {
4509 // Dumping traces to the log, just dump the process that isn't responding so
4510 // we don't overflow the log
4511 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4512 } else {
4513 // Dumping traces to a file so dump all active processes we know about
4514 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004515 // First, these are the most important processes.
4516 final int[] imppids = new int[3];
4517 int i=0;
4518 imppids[0] = app.pid;
4519 i++;
4520 if (reportedActivity != null && reportedActivity.app != null
4521 && reportedActivity.app.thread != null
4522 && reportedActivity.app.pid != app.pid) {
4523 imppids[i] = reportedActivity.app.pid;
4524 i++;
4525 }
4526 imppids[i] = Process.myPid();
4527 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4528 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4529 synchronized (this) {
4530 try {
4531 wait(200);
4532 } catch (InterruptedException e) {
4533 }
4534 }
4535 }
4536 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004537 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004538 boolean done = false;
4539 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4540 if (imppids[j] == r.pid) {
4541 done = true;
4542 break;
4543 }
4544 }
4545 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004546 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004547 synchronized (this) {
4548 try {
4549 wait(200);
4550 } catch (InterruptedException e) {
4551 }
4552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 }
4554 }
4555 }
4556 }
4557
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004558 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004559 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004560 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004561 app.pid, info.toString());
4562 if (res != 0) {
4563 if (res < 0) {
4564 // wait until the SIGQUIT has had a chance to process before killing the
4565 // process.
4566 try {
4567 wait(2000);
4568 } catch (InterruptedException e) {
4569 }
4570
4571 Process.killProcess(app.pid);
4572 return;
4573 }
4574 }
4575 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004576 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004577 }
4578 }
4579
4580 makeAppNotRespondingLocked(app,
4581 activity != null ? activity.shortComponentName : null,
4582 annotation != null ? "ANR " + annotation : "ANR",
4583 info.toString(), null);
4584 Message msg = Message.obtain();
4585 HashMap map = new HashMap();
4586 msg.what = SHOW_NOT_RESPONDING_MSG;
4587 msg.obj = map;
4588 map.put("app", app);
4589 if (activity != null) {
4590 map.put("activity", activity);
4591 }
4592
4593 mHandler.sendMessage(msg);
4594 return;
4595 }
4596
4597 /**
4598 * If a stack trace file has been configured, prepare the filesystem
4599 * by creating the directory if it doesn't exist and optionally
4600 * removing the old trace file.
4601 *
4602 * @param removeExisting If set, the existing trace file will be removed.
4603 * @return Returns true if the trace file preparations succeeded
4604 */
4605 public static boolean prepareTraceFile(boolean removeExisting) {
4606 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4607 boolean fileReady = false;
4608 if (!TextUtils.isEmpty(tracesPath)) {
4609 File f = new File(tracesPath);
4610 if (!f.exists()) {
4611 // Ensure the enclosing directory exists
4612 File dir = f.getParentFile();
4613 if (!dir.exists()) {
4614 fileReady = dir.mkdirs();
4615 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004616 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004617 } else if (dir.isDirectory()) {
4618 fileReady = true;
4619 }
4620 } else if (removeExisting) {
4621 // Remove the previous traces file, so we don't fill the disk.
4622 // The VM will recreate it
4623 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4624 fileReady = f.delete();
4625 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004626
4627 if (removeExisting) {
4628 try {
4629 f.createNewFile();
4630 FileUtils.setPermissions(f.getAbsolutePath(),
4631 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4632 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4633 fileReady = true;
4634 } catch (IOException e) {
4635 Log.w(TAG, "Unable to make ANR traces file", e);
4636 }
4637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004638 }
4639
4640 return fileReady;
4641 }
4642
4643
4644 private final void decPersistentCountLocked(ProcessRecord app)
4645 {
4646 app.persistentActivities--;
4647 if (app.persistentActivities > 0) {
4648 // Still more of 'em...
4649 return;
4650 }
4651 if (app.persistent) {
4652 // Ah, but the application itself is persistent. Whatever!
4653 return;
4654 }
4655
4656 // App is no longer persistent... make sure it and the ones
4657 // following it in the LRU list have the correc oom_adj.
4658 updateOomAdjLocked();
4659 }
4660
4661 public void setPersistent(IBinder token, boolean isPersistent) {
4662 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4663 != PackageManager.PERMISSION_GRANTED) {
4664 String msg = "Permission Denial: setPersistent() from pid="
4665 + Binder.getCallingPid()
4666 + ", uid=" + Binder.getCallingUid()
4667 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4668 Log.w(TAG, msg);
4669 throw new SecurityException(msg);
4670 }
4671
4672 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004673 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004674 if (index < 0) {
4675 return;
4676 }
4677 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4678 ProcessRecord app = r.app;
4679
4680 if (localLOGV) Log.v(
4681 TAG, "Setting persistence " + isPersistent + ": " + r);
4682
4683 if (isPersistent) {
4684 if (r.persistent) {
4685 // Okay okay, I heard you already!
4686 if (localLOGV) Log.v(TAG, "Already persistent!");
4687 return;
4688 }
4689 r.persistent = true;
4690 app.persistentActivities++;
4691 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4692 if (app.persistentActivities > 1) {
4693 // We aren't the first...
4694 if (localLOGV) Log.v(TAG, "Not the first!");
4695 return;
4696 }
4697 if (app.persistent) {
4698 // This would be redundant.
4699 if (localLOGV) Log.v(TAG, "App is persistent!");
4700 return;
4701 }
4702
4703 // App is now persistent... make sure it and the ones
4704 // following it now have the correct oom_adj.
4705 final long origId = Binder.clearCallingIdentity();
4706 updateOomAdjLocked();
4707 Binder.restoreCallingIdentity(origId);
4708
4709 } else {
4710 if (!r.persistent) {
4711 // Okay okay, I heard you already!
4712 return;
4713 }
4714 r.persistent = false;
4715 final long origId = Binder.clearCallingIdentity();
4716 decPersistentCountLocked(app);
4717 Binder.restoreCallingIdentity(origId);
4718
4719 }
4720 }
4721 }
4722
4723 public boolean clearApplicationUserData(final String packageName,
4724 final IPackageDataObserver observer) {
4725 int uid = Binder.getCallingUid();
4726 int pid = Binder.getCallingPid();
4727 long callingId = Binder.clearCallingIdentity();
4728 try {
4729 IPackageManager pm = ActivityThread.getPackageManager();
4730 int pkgUid = -1;
4731 synchronized(this) {
4732 try {
4733 pkgUid = pm.getPackageUid(packageName);
4734 } catch (RemoteException e) {
4735 }
4736 if (pkgUid == -1) {
4737 Log.w(TAG, "Invalid packageName:" + packageName);
4738 return false;
4739 }
4740 if (uid == pkgUid || checkComponentPermission(
4741 android.Manifest.permission.CLEAR_APP_USER_DATA,
4742 pid, uid, -1)
4743 == PackageManager.PERMISSION_GRANTED) {
4744 restartPackageLocked(packageName, pkgUid);
4745 } else {
4746 throw new SecurityException(pid+" does not have permission:"+
4747 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4748 "for process:"+packageName);
4749 }
4750 }
4751
4752 try {
4753 //clear application user data
4754 pm.clearApplicationUserData(packageName, observer);
4755 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4756 Uri.fromParts("package", packageName, null));
4757 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4758 broadcastIntentLocked(null, null, intent,
4759 null, null, 0, null, null, null,
4760 false, false, MY_PID, Process.SYSTEM_UID);
4761 } catch (RemoteException e) {
4762 }
4763 } finally {
4764 Binder.restoreCallingIdentity(callingId);
4765 }
4766 return true;
4767 }
4768
4769 public void restartPackage(final String packageName) {
4770 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4771 != PackageManager.PERMISSION_GRANTED) {
4772 String msg = "Permission Denial: restartPackage() from pid="
4773 + Binder.getCallingPid()
4774 + ", uid=" + Binder.getCallingUid()
4775 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4776 Log.w(TAG, msg);
4777 throw new SecurityException(msg);
4778 }
4779
4780 long callingId = Binder.clearCallingIdentity();
4781 try {
4782 IPackageManager pm = ActivityThread.getPackageManager();
4783 int pkgUid = -1;
4784 synchronized(this) {
4785 try {
4786 pkgUid = pm.getPackageUid(packageName);
4787 } catch (RemoteException e) {
4788 }
4789 if (pkgUid == -1) {
4790 Log.w(TAG, "Invalid packageName: " + packageName);
4791 return;
4792 }
4793 restartPackageLocked(packageName, pkgUid);
4794 }
4795 } finally {
4796 Binder.restoreCallingIdentity(callingId);
4797 }
4798 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004799
4800 /*
4801 * The pkg name and uid have to be specified.
4802 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4803 */
4804 public void killApplicationWithUid(String pkg, int uid) {
4805 if (pkg == null) {
4806 return;
4807 }
4808 // Make sure the uid is valid.
4809 if (uid < 0) {
4810 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4811 return;
4812 }
4813 int callerUid = Binder.getCallingUid();
4814 // Only the system server can kill an application
4815 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004816 // Post an aysnc message to kill the application
4817 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4818 msg.arg1 = uid;
4819 msg.arg2 = 0;
4820 msg.obj = pkg;
4821 mHandler.dispatchMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004822 } else {
4823 throw new SecurityException(callerUid + " cannot kill pkg: " +
4824 pkg);
4825 }
4826 }
4827
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004828 public void closeSystemDialogs(String reason) {
4829 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4830 if (reason != null) {
4831 intent.putExtra("reason", reason);
4832 }
4833
4834 final int uid = Binder.getCallingUid();
4835 final long origId = Binder.clearCallingIdentity();
4836 synchronized (this) {
4837 int i = mWatchers.beginBroadcast();
4838 while (i > 0) {
4839 i--;
4840 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4841 if (w != null) {
4842 try {
4843 w.closingSystemDialogs(reason);
4844 } catch (RemoteException e) {
4845 }
4846 }
4847 }
4848 mWatchers.finishBroadcast();
4849
4850 broadcastIntentLocked(null, null, intent, null,
4851 null, 0, null, null, null, false, false, -1, uid);
4852 }
4853 Binder.restoreCallingIdentity(origId);
4854 }
4855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004856 private void restartPackageLocked(final String packageName, int uid) {
4857 uninstallPackageLocked(packageName, uid, false);
4858 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4859 Uri.fromParts("package", packageName, null));
4860 intent.putExtra(Intent.EXTRA_UID, uid);
4861 broadcastIntentLocked(null, null, intent,
4862 null, null, 0, null, null, null,
4863 false, false, MY_PID, Process.SYSTEM_UID);
4864 }
4865
4866 private final void uninstallPackageLocked(String name, int uid,
4867 boolean callerWillRestart) {
4868 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4869
4870 int i, N;
4871
4872 final String procNamePrefix = name + ":";
4873 if (uid < 0) {
4874 try {
4875 uid = ActivityThread.getPackageManager().getPackageUid(name);
4876 } catch (RemoteException e) {
4877 }
4878 }
4879
4880 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4881 while (badApps.hasNext()) {
4882 SparseArray<Long> ba = badApps.next();
4883 if (ba.get(uid) != null) {
4884 badApps.remove();
4885 }
4886 }
4887
4888 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4889
4890 // Remove all processes this package may have touched: all with the
4891 // same UID (except for the system or root user), and all whose name
4892 // matches the package name.
4893 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4894 final int NA = apps.size();
4895 for (int ia=0; ia<NA; ia++) {
4896 ProcessRecord app = apps.valueAt(ia);
4897 if (app.removed) {
4898 procs.add(app);
4899 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4900 || app.processName.equals(name)
4901 || app.processName.startsWith(procNamePrefix)) {
4902 app.removed = true;
4903 procs.add(app);
4904 }
4905 }
4906 }
4907
4908 N = procs.size();
4909 for (i=0; i<N; i++) {
4910 removeProcessLocked(procs.get(i), callerWillRestart);
4911 }
4912
4913 for (i=mHistory.size()-1; i>=0; i--) {
4914 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4915 if (r.packageName.equals(name)) {
4916 if (Config.LOGD) Log.d(
4917 TAG, " Force finishing activity "
4918 + r.intent.getComponent().flattenToShortString());
4919 if (r.app != null) {
4920 r.app.removed = true;
4921 }
4922 r.app = null;
4923 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4924 }
4925 }
4926
4927 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4928 for (ServiceRecord service : mServices.values()) {
4929 if (service.packageName.equals(name)) {
4930 if (service.app != null) {
4931 service.app.removed = true;
4932 }
4933 service.app = null;
4934 services.add(service);
4935 }
4936 }
4937
4938 N = services.size();
4939 for (i=0; i<N; i++) {
4940 bringDownServiceLocked(services.get(i), true);
4941 }
4942
4943 resumeTopActivityLocked(null);
4944 }
4945
4946 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4947 final String name = app.processName;
4948 final int uid = app.info.uid;
4949 if (Config.LOGD) Log.d(
4950 TAG, "Force removing process " + app + " (" + name
4951 + "/" + uid + ")");
4952
4953 mProcessNames.remove(name, uid);
4954 boolean needRestart = false;
4955 if (app.pid > 0 && app.pid != MY_PID) {
4956 int pid = app.pid;
4957 synchronized (mPidsSelfLocked) {
4958 mPidsSelfLocked.remove(pid);
4959 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4960 }
4961 handleAppDiedLocked(app, true);
4962 mLRUProcesses.remove(app);
4963 Process.killProcess(pid);
4964
4965 if (app.persistent) {
4966 if (!callerWillRestart) {
4967 addAppLocked(app.info);
4968 } else {
4969 needRestart = true;
4970 }
4971 }
4972 } else {
4973 mRemovedProcesses.add(app);
4974 }
4975
4976 return needRestart;
4977 }
4978
4979 private final void processStartTimedOutLocked(ProcessRecord app) {
4980 final int pid = app.pid;
4981 boolean gone = false;
4982 synchronized (mPidsSelfLocked) {
4983 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4984 if (knownApp != null && knownApp.thread == null) {
4985 mPidsSelfLocked.remove(pid);
4986 gone = true;
4987 }
4988 }
4989
4990 if (gone) {
4991 Log.w(TAG, "Process " + app + " failed to attach");
4992 mProcessNames.remove(app.processName, app.info.uid);
4993 Process.killProcess(pid);
4994 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4995 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4996 mPendingBroadcast = null;
4997 scheduleBroadcastsLocked();
4998 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004999 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5000 Log.w(TAG, "Unattached app died before backup, skipping");
5001 try {
5002 IBackupManager bm = IBackupManager.Stub.asInterface(
5003 ServiceManager.getService(Context.BACKUP_SERVICE));
5004 bm.agentDisconnected(app.info.packageName);
5005 } catch (RemoteException e) {
5006 // Can't happen; the backup manager is local
5007 }
5008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005009 } else {
5010 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5011 }
5012 }
5013
5014 private final boolean attachApplicationLocked(IApplicationThread thread,
5015 int pid) {
5016
5017 // Find the application record that is being attached... either via
5018 // the pid if we are running in multiple processes, or just pull the
5019 // next app record if we are emulating process with anonymous threads.
5020 ProcessRecord app;
5021 if (pid != MY_PID && pid >= 0) {
5022 synchronized (mPidsSelfLocked) {
5023 app = mPidsSelfLocked.get(pid);
5024 }
5025 } else if (mStartingProcesses.size() > 0) {
5026 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005027 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005028 } else {
5029 app = null;
5030 }
5031
5032 if (app == null) {
5033 Log.w(TAG, "No pending application record for pid " + pid
5034 + " (IApplicationThread " + thread + "); dropping process");
5035 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5036 if (pid > 0 && pid != MY_PID) {
5037 Process.killProcess(pid);
5038 } else {
5039 try {
5040 thread.scheduleExit();
5041 } catch (Exception e) {
5042 // Ignore exceptions.
5043 }
5044 }
5045 return false;
5046 }
5047
5048 // If this application record is still attached to a previous
5049 // process, clean it up now.
5050 if (app.thread != null) {
5051 handleAppDiedLocked(app, true);
5052 }
5053
5054 // Tell the process all about itself.
5055
5056 if (localLOGV) Log.v(
5057 TAG, "Binding process pid " + pid + " to record " + app);
5058
5059 String processName = app.processName;
5060 try {
5061 thread.asBinder().linkToDeath(new AppDeathRecipient(
5062 app, pid, thread), 0);
5063 } catch (RemoteException e) {
5064 app.resetPackageList();
5065 startProcessLocked(app, "link fail", processName);
5066 return false;
5067 }
5068
5069 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5070
5071 app.thread = thread;
5072 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005073 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005074 app.forcingToForeground = null;
5075 app.foregroundServices = false;
5076 app.debugging = false;
5077
5078 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5079
5080 List providers = generateApplicationProvidersLocked(app);
5081
5082 if (localLOGV) Log.v(
5083 TAG, "New app record " + app
5084 + " thread=" + thread.asBinder() + " pid=" + pid);
5085 try {
5086 int testMode = IApplicationThread.DEBUG_OFF;
5087 if (mDebugApp != null && mDebugApp.equals(processName)) {
5088 testMode = mWaitForDebugger
5089 ? IApplicationThread.DEBUG_WAIT
5090 : IApplicationThread.DEBUG_ON;
5091 app.debugging = true;
5092 if (mDebugTransient) {
5093 mDebugApp = mOrigDebugApp;
5094 mWaitForDebugger = mOrigWaitForDebugger;
5095 }
5096 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005097 // If the app is being launched for restore or full backup, set it up specially
5098 boolean isRestrictedBackupMode = false;
5099 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5100 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5101 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5102 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005103 ensurePackageDexOpt(app.instrumentationInfo != null
5104 ? app.instrumentationInfo.packageName
5105 : app.info.packageName);
5106 if (app.instrumentationClass != null) {
5107 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005108 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005109 thread.bindApplication(processName, app.instrumentationInfo != null
5110 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005111 app.instrumentationClass, app.instrumentationProfileFile,
5112 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07005113 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005114 updateLRUListLocked(app, false);
5115 app.lastRequestedGc = SystemClock.uptimeMillis();
5116 } catch (Exception e) {
5117 // todo: Yikes! What should we do? For now we will try to
5118 // start another process, but that could easily get us in
5119 // an infinite loop of restarting processes...
5120 Log.w(TAG, "Exception thrown during bind!", e);
5121
5122 app.resetPackageList();
5123 startProcessLocked(app, "bind fail", processName);
5124 return false;
5125 }
5126
5127 // Remove this record from the list of starting applications.
5128 mPersistentStartingProcesses.remove(app);
5129 mProcessesOnHold.remove(app);
5130
5131 boolean badApp = false;
5132 boolean didSomething = false;
5133
5134 // See if the top visible activity is waiting to run in this process...
5135 HistoryRecord hr = topRunningActivityLocked(null);
5136 if (hr != null) {
5137 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5138 && processName.equals(hr.processName)) {
5139 try {
5140 if (realStartActivityLocked(hr, app, true, true)) {
5141 didSomething = true;
5142 }
5143 } catch (Exception e) {
5144 Log.w(TAG, "Exception in new application when starting activity "
5145 + hr.intent.getComponent().flattenToShortString(), e);
5146 badApp = true;
5147 }
5148 } else {
5149 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5150 }
5151 }
5152
5153 // Find any services that should be running in this process...
5154 if (!badApp && mPendingServices.size() > 0) {
5155 ServiceRecord sr = null;
5156 try {
5157 for (int i=0; i<mPendingServices.size(); i++) {
5158 sr = mPendingServices.get(i);
5159 if (app.info.uid != sr.appInfo.uid
5160 || !processName.equals(sr.processName)) {
5161 continue;
5162 }
5163
5164 mPendingServices.remove(i);
5165 i--;
5166 realStartServiceLocked(sr, app);
5167 didSomething = true;
5168 }
5169 } catch (Exception e) {
5170 Log.w(TAG, "Exception in new application when starting service "
5171 + sr.shortName, e);
5172 badApp = true;
5173 }
5174 }
5175
5176 // Check if the next broadcast receiver is in this process...
5177 BroadcastRecord br = mPendingBroadcast;
5178 if (!badApp && br != null && br.curApp == app) {
5179 try {
5180 mPendingBroadcast = null;
5181 processCurBroadcastLocked(br, app);
5182 didSomething = true;
5183 } catch (Exception e) {
5184 Log.w(TAG, "Exception in new application when starting receiver "
5185 + br.curComponent.flattenToShortString(), e);
5186 badApp = true;
5187 logBroadcastReceiverDiscard(br);
5188 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5189 br.resultExtras, br.resultAbort, true);
5190 scheduleBroadcastsLocked();
5191 }
5192 }
5193
Christopher Tate181fafa2009-05-14 11:12:14 -07005194 // Check whether the next backup agent is in this process...
5195 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5196 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005197 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005198 try {
5199 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5200 } catch (Exception e) {
5201 Log.w(TAG, "Exception scheduling backup agent creation: ");
5202 e.printStackTrace();
5203 }
5204 }
5205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005206 if (badApp) {
5207 // todo: Also need to kill application to deal with all
5208 // kinds of exceptions.
5209 handleAppDiedLocked(app, false);
5210 return false;
5211 }
5212
5213 if (!didSomething) {
5214 updateOomAdjLocked();
5215 }
5216
5217 return true;
5218 }
5219
5220 public final void attachApplication(IApplicationThread thread) {
5221 synchronized (this) {
5222 int callingPid = Binder.getCallingPid();
5223 final long origId = Binder.clearCallingIdentity();
5224 attachApplicationLocked(thread, callingPid);
5225 Binder.restoreCallingIdentity(origId);
5226 }
5227 }
5228
5229 public final void activityIdle(IBinder token) {
5230 final long origId = Binder.clearCallingIdentity();
5231 activityIdleInternal(token, false);
5232 Binder.restoreCallingIdentity(origId);
5233 }
5234
5235 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5236 boolean remove) {
5237 int N = mStoppingActivities.size();
5238 if (N <= 0) return null;
5239
5240 ArrayList<HistoryRecord> stops = null;
5241
5242 final boolean nowVisible = mResumedActivity != null
5243 && mResumedActivity.nowVisible
5244 && !mResumedActivity.waitingVisible;
5245 for (int i=0; i<N; i++) {
5246 HistoryRecord s = mStoppingActivities.get(i);
5247 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5248 + nowVisible + " waitingVisible=" + s.waitingVisible
5249 + " finishing=" + s.finishing);
5250 if (s.waitingVisible && nowVisible) {
5251 mWaitingVisibleActivities.remove(s);
5252 s.waitingVisible = false;
5253 if (s.finishing) {
5254 // If this activity is finishing, it is sitting on top of
5255 // everyone else but we now know it is no longer needed...
5256 // so get rid of it. Otherwise, we need to go through the
5257 // normal flow and hide it once we determine that it is
5258 // hidden by the activities in front of it.
5259 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5260 mWindowManager.setAppVisibility(s, false);
5261 }
5262 }
5263 if (!s.waitingVisible && remove) {
5264 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5265 if (stops == null) {
5266 stops = new ArrayList<HistoryRecord>();
5267 }
5268 stops.add(s);
5269 mStoppingActivities.remove(i);
5270 N--;
5271 i--;
5272 }
5273 }
5274
5275 return stops;
5276 }
5277
5278 void enableScreenAfterBoot() {
5279 mWindowManager.enableScreenAfterBoot();
5280 }
5281
5282 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5283 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5284
5285 ArrayList<HistoryRecord> stops = null;
5286 ArrayList<HistoryRecord> finishes = null;
5287 ArrayList<HistoryRecord> thumbnails = null;
5288 int NS = 0;
5289 int NF = 0;
5290 int NT = 0;
5291 IApplicationThread sendThumbnail = null;
5292 boolean booting = false;
5293 boolean enableScreen = false;
5294
5295 synchronized (this) {
5296 if (token != null) {
5297 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5298 }
5299
5300 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005301 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005302 if (index >= 0) {
5303 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5304
5305 // No longer need to keep the device awake.
5306 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5307 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5308 mLaunchingActivity.release();
5309 }
5310
5311 // We are now idle. If someone is waiting for a thumbnail from
5312 // us, we can now deliver.
5313 r.idle = true;
5314 scheduleAppGcsLocked();
5315 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5316 sendThumbnail = r.app.thread;
5317 r.thumbnailNeeded = false;
5318 }
5319
5320 // If this activity is fullscreen, set up to hide those under it.
5321
5322 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5323 ensureActivitiesVisibleLocked(null, 0);
5324
5325 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5326 if (!mBooted && !fromTimeout) {
5327 mBooted = true;
5328 enableScreen = true;
5329 }
5330 }
5331
5332 // Atomically retrieve all of the other things to do.
5333 stops = processStoppingActivitiesLocked(true);
5334 NS = stops != null ? stops.size() : 0;
5335 if ((NF=mFinishingActivities.size()) > 0) {
5336 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5337 mFinishingActivities.clear();
5338 }
5339 if ((NT=mCancelledThumbnails.size()) > 0) {
5340 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5341 mCancelledThumbnails.clear();
5342 }
5343
5344 booting = mBooting;
5345 mBooting = false;
5346 }
5347
5348 int i;
5349
5350 // Send thumbnail if requested.
5351 if (sendThumbnail != null) {
5352 try {
5353 sendThumbnail.requestThumbnail(token);
5354 } catch (Exception e) {
5355 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5356 sendPendingThumbnail(null, token, null, null, true);
5357 }
5358 }
5359
5360 // Stop any activities that are scheduled to do so but have been
5361 // waiting for the next one to start.
5362 for (i=0; i<NS; i++) {
5363 HistoryRecord r = (HistoryRecord)stops.get(i);
5364 synchronized (this) {
5365 if (r.finishing) {
5366 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5367 } else {
5368 stopActivityLocked(r);
5369 }
5370 }
5371 }
5372
5373 // Finish any activities that are scheduled to do so but have been
5374 // waiting for the next one to start.
5375 for (i=0; i<NF; i++) {
5376 HistoryRecord r = (HistoryRecord)finishes.get(i);
5377 synchronized (this) {
5378 destroyActivityLocked(r, true);
5379 }
5380 }
5381
5382 // Report back to any thumbnail receivers.
5383 for (i=0; i<NT; i++) {
5384 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5385 sendPendingThumbnail(r, null, null, null, true);
5386 }
5387
5388 if (booting) {
5389 // Ensure that any processes we had put on hold are now started
5390 // up.
5391 final int NP = mProcessesOnHold.size();
5392 if (NP > 0) {
5393 ArrayList<ProcessRecord> procs =
5394 new ArrayList<ProcessRecord>(mProcessesOnHold);
5395 for (int ip=0; ip<NP; ip++) {
5396 this.startProcessLocked(procs.get(ip), "on-hold", null);
5397 }
5398 }
5399 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5400 // Tell anyone interested that we are done booting!
5401 synchronized (this) {
5402 broadcastIntentLocked(null, null,
5403 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5404 null, null, 0, null, null,
5405 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5406 false, false, MY_PID, Process.SYSTEM_UID);
5407 }
5408 }
5409 }
5410
5411 trimApplications();
5412 //dump();
5413 //mWindowManager.dump();
5414
5415 if (enableScreen) {
5416 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5417 SystemClock.uptimeMillis());
5418 enableScreenAfterBoot();
5419 }
5420 }
5421
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005422 final void ensureScreenEnabled() {
5423 boolean enableScreen;
5424 synchronized (this) {
5425 enableScreen = !mBooted;
5426 mBooted = true;
5427 }
5428
5429 if (enableScreen) {
5430 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5431 SystemClock.uptimeMillis());
5432 enableScreenAfterBoot();
5433 }
5434 }
5435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005436 public final void activityPaused(IBinder token, Bundle icicle) {
5437 // Refuse possible leaked file descriptors
5438 if (icicle != null && icicle.hasFileDescriptors()) {
5439 throw new IllegalArgumentException("File descriptors passed in Bundle");
5440 }
5441
5442 final long origId = Binder.clearCallingIdentity();
5443 activityPaused(token, icicle, false);
5444 Binder.restoreCallingIdentity(origId);
5445 }
5446
5447 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5448 if (DEBUG_PAUSE) Log.v(
5449 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5450 + ", timeout=" + timeout);
5451
5452 HistoryRecord r = null;
5453
5454 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005455 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005456 if (index >= 0) {
5457 r = (HistoryRecord)mHistory.get(index);
5458 if (!timeout) {
5459 r.icicle = icicle;
5460 r.haveState = true;
5461 }
5462 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5463 if (mPausingActivity == r) {
5464 r.state = ActivityState.PAUSED;
5465 completePauseLocked();
5466 } else {
5467 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5468 System.identityHashCode(r), r.shortComponentName,
5469 mPausingActivity != null
5470 ? mPausingActivity.shortComponentName : "(none)");
5471 }
5472 }
5473 }
5474 }
5475
5476 public final void activityStopped(IBinder token, Bitmap thumbnail,
5477 CharSequence description) {
5478 if (localLOGV) Log.v(
5479 TAG, "Activity stopped: token=" + token);
5480
5481 HistoryRecord r = null;
5482
5483 final long origId = Binder.clearCallingIdentity();
5484
5485 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005486 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005487 if (index >= 0) {
5488 r = (HistoryRecord)mHistory.get(index);
5489 r.thumbnail = thumbnail;
5490 r.description = description;
5491 r.stopped = true;
5492 r.state = ActivityState.STOPPED;
5493 if (!r.finishing) {
5494 if (r.configDestroy) {
5495 destroyActivityLocked(r, true);
5496 resumeTopActivityLocked(null);
5497 }
5498 }
5499 }
5500 }
5501
5502 if (r != null) {
5503 sendPendingThumbnail(r, null, null, null, false);
5504 }
5505
5506 trimApplications();
5507
5508 Binder.restoreCallingIdentity(origId);
5509 }
5510
5511 public final void activityDestroyed(IBinder token) {
5512 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5513 synchronized (this) {
5514 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5515
Dianne Hackborn75b03852009-06-12 15:43:26 -07005516 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005517 if (index >= 0) {
5518 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5519 if (r.state == ActivityState.DESTROYING) {
5520 final long origId = Binder.clearCallingIdentity();
5521 removeActivityFromHistoryLocked(r);
5522 Binder.restoreCallingIdentity(origId);
5523 }
5524 }
5525 }
5526 }
5527
5528 public String getCallingPackage(IBinder token) {
5529 synchronized (this) {
5530 HistoryRecord r = getCallingRecordLocked(token);
5531 return r != null && r.app != null ? r.app.processName : null;
5532 }
5533 }
5534
5535 public ComponentName getCallingActivity(IBinder token) {
5536 synchronized (this) {
5537 HistoryRecord r = getCallingRecordLocked(token);
5538 return r != null ? r.intent.getComponent() : null;
5539 }
5540 }
5541
5542 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005543 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005544 if (index >= 0) {
5545 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5546 if (r != null) {
5547 return r.resultTo;
5548 }
5549 }
5550 return null;
5551 }
5552
5553 public ComponentName getActivityClassForToken(IBinder token) {
5554 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005555 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005556 if (index >= 0) {
5557 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5558 return r.intent.getComponent();
5559 }
5560 return null;
5561 }
5562 }
5563
5564 public String getPackageForToken(IBinder token) {
5565 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005566 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005567 if (index >= 0) {
5568 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5569 return r.packageName;
5570 }
5571 return null;
5572 }
5573 }
5574
5575 public IIntentSender getIntentSender(int type,
5576 String packageName, IBinder token, String resultWho,
5577 int requestCode, Intent intent, String resolvedType, int flags) {
5578 // Refuse possible leaked file descriptors
5579 if (intent != null && intent.hasFileDescriptors() == true) {
5580 throw new IllegalArgumentException("File descriptors passed in Intent");
5581 }
5582
5583 synchronized(this) {
5584 int callingUid = Binder.getCallingUid();
5585 try {
5586 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5587 Process.supportsProcesses()) {
5588 int uid = ActivityThread.getPackageManager()
5589 .getPackageUid(packageName);
5590 if (uid != Binder.getCallingUid()) {
5591 String msg = "Permission Denial: getIntentSender() from pid="
5592 + Binder.getCallingPid()
5593 + ", uid=" + Binder.getCallingUid()
5594 + ", (need uid=" + uid + ")"
5595 + " is not allowed to send as package " + packageName;
5596 Log.w(TAG, msg);
5597 throw new SecurityException(msg);
5598 }
5599 }
5600 } catch (RemoteException e) {
5601 throw new SecurityException(e);
5602 }
5603 HistoryRecord activity = null;
5604 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005605 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005606 if (index < 0) {
5607 return null;
5608 }
5609 activity = (HistoryRecord)mHistory.get(index);
5610 if (activity.finishing) {
5611 return null;
5612 }
5613 }
5614
5615 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5616 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5617 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5618 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5619 |PendingIntent.FLAG_UPDATE_CURRENT);
5620
5621 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5622 type, packageName, activity, resultWho,
5623 requestCode, intent, resolvedType, flags);
5624 WeakReference<PendingIntentRecord> ref;
5625 ref = mIntentSenderRecords.get(key);
5626 PendingIntentRecord rec = ref != null ? ref.get() : null;
5627 if (rec != null) {
5628 if (!cancelCurrent) {
5629 if (updateCurrent) {
5630 rec.key.requestIntent.replaceExtras(intent);
5631 }
5632 return rec;
5633 }
5634 rec.canceled = true;
5635 mIntentSenderRecords.remove(key);
5636 }
5637 if (noCreate) {
5638 return rec;
5639 }
5640 rec = new PendingIntentRecord(this, key, callingUid);
5641 mIntentSenderRecords.put(key, rec.ref);
5642 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5643 if (activity.pendingResults == null) {
5644 activity.pendingResults
5645 = new HashSet<WeakReference<PendingIntentRecord>>();
5646 }
5647 activity.pendingResults.add(rec.ref);
5648 }
5649 return rec;
5650 }
5651 }
5652
5653 public void cancelIntentSender(IIntentSender sender) {
5654 if (!(sender instanceof PendingIntentRecord)) {
5655 return;
5656 }
5657 synchronized(this) {
5658 PendingIntentRecord rec = (PendingIntentRecord)sender;
5659 try {
5660 int uid = ActivityThread.getPackageManager()
5661 .getPackageUid(rec.key.packageName);
5662 if (uid != Binder.getCallingUid()) {
5663 String msg = "Permission Denial: cancelIntentSender() from pid="
5664 + Binder.getCallingPid()
5665 + ", uid=" + Binder.getCallingUid()
5666 + " is not allowed to cancel packges "
5667 + rec.key.packageName;
5668 Log.w(TAG, msg);
5669 throw new SecurityException(msg);
5670 }
5671 } catch (RemoteException e) {
5672 throw new SecurityException(e);
5673 }
5674 cancelIntentSenderLocked(rec, true);
5675 }
5676 }
5677
5678 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5679 rec.canceled = true;
5680 mIntentSenderRecords.remove(rec.key);
5681 if (cleanActivity && rec.key.activity != null) {
5682 rec.key.activity.pendingResults.remove(rec.ref);
5683 }
5684 }
5685
5686 public String getPackageForIntentSender(IIntentSender pendingResult) {
5687 if (!(pendingResult instanceof PendingIntentRecord)) {
5688 return null;
5689 }
5690 synchronized(this) {
5691 try {
5692 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5693 return res.key.packageName;
5694 } catch (ClassCastException e) {
5695 }
5696 }
5697 return null;
5698 }
5699
5700 public void setProcessLimit(int max) {
5701 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5702 "setProcessLimit()");
5703 mProcessLimit = max;
5704 }
5705
5706 public int getProcessLimit() {
5707 return mProcessLimit;
5708 }
5709
5710 void foregroundTokenDied(ForegroundToken token) {
5711 synchronized (ActivityManagerService.this) {
5712 synchronized (mPidsSelfLocked) {
5713 ForegroundToken cur
5714 = mForegroundProcesses.get(token.pid);
5715 if (cur != token) {
5716 return;
5717 }
5718 mForegroundProcesses.remove(token.pid);
5719 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5720 if (pr == null) {
5721 return;
5722 }
5723 pr.forcingToForeground = null;
5724 pr.foregroundServices = false;
5725 }
5726 updateOomAdjLocked();
5727 }
5728 }
5729
5730 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5731 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5732 "setProcessForeground()");
5733 synchronized(this) {
5734 boolean changed = false;
5735
5736 synchronized (mPidsSelfLocked) {
5737 ProcessRecord pr = mPidsSelfLocked.get(pid);
5738 if (pr == null) {
5739 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5740 return;
5741 }
5742 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5743 if (oldToken != null) {
5744 oldToken.token.unlinkToDeath(oldToken, 0);
5745 mForegroundProcesses.remove(pid);
5746 pr.forcingToForeground = null;
5747 changed = true;
5748 }
5749 if (isForeground && token != null) {
5750 ForegroundToken newToken = new ForegroundToken() {
5751 public void binderDied() {
5752 foregroundTokenDied(this);
5753 }
5754 };
5755 newToken.pid = pid;
5756 newToken.token = token;
5757 try {
5758 token.linkToDeath(newToken, 0);
5759 mForegroundProcesses.put(pid, newToken);
5760 pr.forcingToForeground = token;
5761 changed = true;
5762 } catch (RemoteException e) {
5763 // If the process died while doing this, we will later
5764 // do the cleanup with the process death link.
5765 }
5766 }
5767 }
5768
5769 if (changed) {
5770 updateOomAdjLocked();
5771 }
5772 }
5773 }
5774
5775 // =========================================================
5776 // PERMISSIONS
5777 // =========================================================
5778
5779 static class PermissionController extends IPermissionController.Stub {
5780 ActivityManagerService mActivityManagerService;
5781 PermissionController(ActivityManagerService activityManagerService) {
5782 mActivityManagerService = activityManagerService;
5783 }
5784
5785 public boolean checkPermission(String permission, int pid, int uid) {
5786 return mActivityManagerService.checkPermission(permission, pid,
5787 uid) == PackageManager.PERMISSION_GRANTED;
5788 }
5789 }
5790
5791 /**
5792 * This can be called with or without the global lock held.
5793 */
5794 int checkComponentPermission(String permission, int pid, int uid,
5795 int reqUid) {
5796 // We might be performing an operation on behalf of an indirect binder
5797 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5798 // client identity accordingly before proceeding.
5799 Identity tlsIdentity = sCallerIdentity.get();
5800 if (tlsIdentity != null) {
5801 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5802 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5803 uid = tlsIdentity.uid;
5804 pid = tlsIdentity.pid;
5805 }
5806
5807 // Root, system server and our own process get to do everything.
5808 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5809 !Process.supportsProcesses()) {
5810 return PackageManager.PERMISSION_GRANTED;
5811 }
5812 // If the target requires a specific UID, always fail for others.
5813 if (reqUid >= 0 && uid != reqUid) {
5814 return PackageManager.PERMISSION_DENIED;
5815 }
5816 if (permission == null) {
5817 return PackageManager.PERMISSION_GRANTED;
5818 }
5819 try {
5820 return ActivityThread.getPackageManager()
5821 .checkUidPermission(permission, uid);
5822 } catch (RemoteException e) {
5823 // Should never happen, but if it does... deny!
5824 Log.e(TAG, "PackageManager is dead?!?", e);
5825 }
5826 return PackageManager.PERMISSION_DENIED;
5827 }
5828
5829 /**
5830 * As the only public entry point for permissions checking, this method
5831 * can enforce the semantic that requesting a check on a null global
5832 * permission is automatically denied. (Internally a null permission
5833 * string is used when calling {@link #checkComponentPermission} in cases
5834 * when only uid-based security is needed.)
5835 *
5836 * This can be called with or without the global lock held.
5837 */
5838 public int checkPermission(String permission, int pid, int uid) {
5839 if (permission == null) {
5840 return PackageManager.PERMISSION_DENIED;
5841 }
5842 return checkComponentPermission(permission, pid, uid, -1);
5843 }
5844
5845 /**
5846 * Binder IPC calls go through the public entry point.
5847 * This can be called with or without the global lock held.
5848 */
5849 int checkCallingPermission(String permission) {
5850 return checkPermission(permission,
5851 Binder.getCallingPid(),
5852 Binder.getCallingUid());
5853 }
5854
5855 /**
5856 * This can be called with or without the global lock held.
5857 */
5858 void enforceCallingPermission(String permission, String func) {
5859 if (checkCallingPermission(permission)
5860 == PackageManager.PERMISSION_GRANTED) {
5861 return;
5862 }
5863
5864 String msg = "Permission Denial: " + func + " from pid="
5865 + Binder.getCallingPid()
5866 + ", uid=" + Binder.getCallingUid()
5867 + " requires " + permission;
5868 Log.w(TAG, msg);
5869 throw new SecurityException(msg);
5870 }
5871
5872 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5873 ProviderInfo pi, int uid, int modeFlags) {
5874 try {
5875 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5876 if ((pi.readPermission != null) &&
5877 (pm.checkUidPermission(pi.readPermission, uid)
5878 != PackageManager.PERMISSION_GRANTED)) {
5879 return false;
5880 }
5881 }
5882 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5883 if ((pi.writePermission != null) &&
5884 (pm.checkUidPermission(pi.writePermission, uid)
5885 != PackageManager.PERMISSION_GRANTED)) {
5886 return false;
5887 }
5888 }
5889 return true;
5890 } catch (RemoteException e) {
5891 return false;
5892 }
5893 }
5894
5895 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5896 int modeFlags) {
5897 // Root gets to do everything.
5898 if (uid == 0 || !Process.supportsProcesses()) {
5899 return true;
5900 }
5901 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5902 if (perms == null) return false;
5903 UriPermission perm = perms.get(uri);
5904 if (perm == null) return false;
5905 return (modeFlags&perm.modeFlags) == modeFlags;
5906 }
5907
5908 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5909 // Another redirected-binder-call permissions check as in
5910 // {@link checkComponentPermission}.
5911 Identity tlsIdentity = sCallerIdentity.get();
5912 if (tlsIdentity != null) {
5913 uid = tlsIdentity.uid;
5914 pid = tlsIdentity.pid;
5915 }
5916
5917 // Our own process gets to do everything.
5918 if (pid == MY_PID) {
5919 return PackageManager.PERMISSION_GRANTED;
5920 }
5921 synchronized(this) {
5922 return checkUriPermissionLocked(uri, uid, modeFlags)
5923 ? PackageManager.PERMISSION_GRANTED
5924 : PackageManager.PERMISSION_DENIED;
5925 }
5926 }
5927
5928 private void grantUriPermissionLocked(int callingUid,
5929 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5930 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5931 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5932 if (modeFlags == 0) {
5933 return;
5934 }
5935
5936 final IPackageManager pm = ActivityThread.getPackageManager();
5937
5938 // If this is not a content: uri, we can't do anything with it.
5939 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5940 return;
5941 }
5942
5943 String name = uri.getAuthority();
5944 ProviderInfo pi = null;
5945 ContentProviderRecord cpr
5946 = (ContentProviderRecord)mProvidersByName.get(name);
5947 if (cpr != null) {
5948 pi = cpr.info;
5949 } else {
5950 try {
5951 pi = pm.resolveContentProvider(name,
5952 PackageManager.GET_URI_PERMISSION_PATTERNS);
5953 } catch (RemoteException ex) {
5954 }
5955 }
5956 if (pi == null) {
5957 Log.w(TAG, "No content provider found for: " + name);
5958 return;
5959 }
5960
5961 int targetUid;
5962 try {
5963 targetUid = pm.getPackageUid(targetPkg);
5964 if (targetUid < 0) {
5965 return;
5966 }
5967 } catch (RemoteException ex) {
5968 return;
5969 }
5970
5971 // First... does the target actually need this permission?
5972 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5973 // No need to grant the target this permission.
5974 return;
5975 }
5976
5977 // Second... maybe someone else has already granted the
5978 // permission?
5979 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5980 // No need to grant the target this permission.
5981 return;
5982 }
5983
5984 // Third... is the provider allowing granting of URI permissions?
5985 if (!pi.grantUriPermissions) {
5986 throw new SecurityException("Provider " + pi.packageName
5987 + "/" + pi.name
5988 + " does not allow granting of Uri permissions (uri "
5989 + uri + ")");
5990 }
5991 if (pi.uriPermissionPatterns != null) {
5992 final int N = pi.uriPermissionPatterns.length;
5993 boolean allowed = false;
5994 for (int i=0; i<N; i++) {
5995 if (pi.uriPermissionPatterns[i] != null
5996 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5997 allowed = true;
5998 break;
5999 }
6000 }
6001 if (!allowed) {
6002 throw new SecurityException("Provider " + pi.packageName
6003 + "/" + pi.name
6004 + " does not allow granting of permission to path of Uri "
6005 + uri);
6006 }
6007 }
6008
6009 // Fourth... does the caller itself have permission to access
6010 // this uri?
6011 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6012 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6013 throw new SecurityException("Uid " + callingUid
6014 + " does not have permission to uri " + uri);
6015 }
6016 }
6017
6018 // Okay! So here we are: the caller has the assumed permission
6019 // to the uri, and the target doesn't. Let's now give this to
6020 // the target.
6021
6022 HashMap<Uri, UriPermission> targetUris
6023 = mGrantedUriPermissions.get(targetUid);
6024 if (targetUris == null) {
6025 targetUris = new HashMap<Uri, UriPermission>();
6026 mGrantedUriPermissions.put(targetUid, targetUris);
6027 }
6028
6029 UriPermission perm = targetUris.get(uri);
6030 if (perm == null) {
6031 perm = new UriPermission(targetUid, uri);
6032 targetUris.put(uri, perm);
6033
6034 }
6035 perm.modeFlags |= modeFlags;
6036 if (activity == null) {
6037 perm.globalModeFlags |= modeFlags;
6038 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6039 perm.readActivities.add(activity);
6040 if (activity.readUriPermissions == null) {
6041 activity.readUriPermissions = new HashSet<UriPermission>();
6042 }
6043 activity.readUriPermissions.add(perm);
6044 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6045 perm.writeActivities.add(activity);
6046 if (activity.writeUriPermissions == null) {
6047 activity.writeUriPermissions = new HashSet<UriPermission>();
6048 }
6049 activity.writeUriPermissions.add(perm);
6050 }
6051 }
6052
6053 private void grantUriPermissionFromIntentLocked(int callingUid,
6054 String targetPkg, Intent intent, HistoryRecord activity) {
6055 if (intent == null) {
6056 return;
6057 }
6058 Uri data = intent.getData();
6059 if (data == null) {
6060 return;
6061 }
6062 grantUriPermissionLocked(callingUid, targetPkg, data,
6063 intent.getFlags(), activity);
6064 }
6065
6066 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6067 Uri uri, int modeFlags) {
6068 synchronized(this) {
6069 final ProcessRecord r = getRecordForAppLocked(caller);
6070 if (r == null) {
6071 throw new SecurityException("Unable to find app for caller "
6072 + caller
6073 + " when granting permission to uri " + uri);
6074 }
6075 if (targetPkg == null) {
6076 Log.w(TAG, "grantUriPermission: null target");
6077 return;
6078 }
6079 if (uri == null) {
6080 Log.w(TAG, "grantUriPermission: null uri");
6081 return;
6082 }
6083
6084 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6085 null);
6086 }
6087 }
6088
6089 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6090 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6091 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6092 HashMap<Uri, UriPermission> perms
6093 = mGrantedUriPermissions.get(perm.uid);
6094 if (perms != null) {
6095 perms.remove(perm.uri);
6096 if (perms.size() == 0) {
6097 mGrantedUriPermissions.remove(perm.uid);
6098 }
6099 }
6100 }
6101 }
6102
6103 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6104 if (activity.readUriPermissions != null) {
6105 for (UriPermission perm : activity.readUriPermissions) {
6106 perm.readActivities.remove(activity);
6107 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6108 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6109 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6110 removeUriPermissionIfNeededLocked(perm);
6111 }
6112 }
6113 }
6114 if (activity.writeUriPermissions != null) {
6115 for (UriPermission perm : activity.writeUriPermissions) {
6116 perm.writeActivities.remove(activity);
6117 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6118 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6119 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6120 removeUriPermissionIfNeededLocked(perm);
6121 }
6122 }
6123 }
6124 }
6125
6126 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6127 int modeFlags) {
6128 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6129 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6130 if (modeFlags == 0) {
6131 return;
6132 }
6133
6134 final IPackageManager pm = ActivityThread.getPackageManager();
6135
6136 final String authority = uri.getAuthority();
6137 ProviderInfo pi = null;
6138 ContentProviderRecord cpr
6139 = (ContentProviderRecord)mProvidersByName.get(authority);
6140 if (cpr != null) {
6141 pi = cpr.info;
6142 } else {
6143 try {
6144 pi = pm.resolveContentProvider(authority,
6145 PackageManager.GET_URI_PERMISSION_PATTERNS);
6146 } catch (RemoteException ex) {
6147 }
6148 }
6149 if (pi == null) {
6150 Log.w(TAG, "No content provider found for: " + authority);
6151 return;
6152 }
6153
6154 // Does the caller have this permission on the URI?
6155 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6156 // Right now, if you are not the original owner of the permission,
6157 // you are not allowed to revoke it.
6158 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6159 throw new SecurityException("Uid " + callingUid
6160 + " does not have permission to uri " + uri);
6161 //}
6162 }
6163
6164 // Go through all of the permissions and remove any that match.
6165 final List<String> SEGMENTS = uri.getPathSegments();
6166 if (SEGMENTS != null) {
6167 final int NS = SEGMENTS.size();
6168 int N = mGrantedUriPermissions.size();
6169 for (int i=0; i<N; i++) {
6170 HashMap<Uri, UriPermission> perms
6171 = mGrantedUriPermissions.valueAt(i);
6172 Iterator<UriPermission> it = perms.values().iterator();
6173 toploop:
6174 while (it.hasNext()) {
6175 UriPermission perm = it.next();
6176 Uri targetUri = perm.uri;
6177 if (!authority.equals(targetUri.getAuthority())) {
6178 continue;
6179 }
6180 List<String> targetSegments = targetUri.getPathSegments();
6181 if (targetSegments == null) {
6182 continue;
6183 }
6184 if (targetSegments.size() < NS) {
6185 continue;
6186 }
6187 for (int j=0; j<NS; j++) {
6188 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6189 continue toploop;
6190 }
6191 }
6192 perm.clearModes(modeFlags);
6193 if (perm.modeFlags == 0) {
6194 it.remove();
6195 }
6196 }
6197 if (perms.size() == 0) {
6198 mGrantedUriPermissions.remove(
6199 mGrantedUriPermissions.keyAt(i));
6200 N--;
6201 i--;
6202 }
6203 }
6204 }
6205 }
6206
6207 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6208 int modeFlags) {
6209 synchronized(this) {
6210 final ProcessRecord r = getRecordForAppLocked(caller);
6211 if (r == null) {
6212 throw new SecurityException("Unable to find app for caller "
6213 + caller
6214 + " when revoking permission to uri " + uri);
6215 }
6216 if (uri == null) {
6217 Log.w(TAG, "revokeUriPermission: null uri");
6218 return;
6219 }
6220
6221 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6222 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6223 if (modeFlags == 0) {
6224 return;
6225 }
6226
6227 final IPackageManager pm = ActivityThread.getPackageManager();
6228
6229 final String authority = uri.getAuthority();
6230 ProviderInfo pi = null;
6231 ContentProviderRecord cpr
6232 = (ContentProviderRecord)mProvidersByName.get(authority);
6233 if (cpr != null) {
6234 pi = cpr.info;
6235 } else {
6236 try {
6237 pi = pm.resolveContentProvider(authority,
6238 PackageManager.GET_URI_PERMISSION_PATTERNS);
6239 } catch (RemoteException ex) {
6240 }
6241 }
6242 if (pi == null) {
6243 Log.w(TAG, "No content provider found for: " + authority);
6244 return;
6245 }
6246
6247 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6248 }
6249 }
6250
6251 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6252 synchronized (this) {
6253 ProcessRecord app =
6254 who != null ? getRecordForAppLocked(who) : null;
6255 if (app == null) return;
6256
6257 Message msg = Message.obtain();
6258 msg.what = WAIT_FOR_DEBUGGER_MSG;
6259 msg.obj = app;
6260 msg.arg1 = waiting ? 1 : 0;
6261 mHandler.sendMessage(msg);
6262 }
6263 }
6264
6265 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6266 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006267 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006268 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006269 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006270 }
6271
6272 // =========================================================
6273 // TASK MANAGEMENT
6274 // =========================================================
6275
6276 public List getTasks(int maxNum, int flags,
6277 IThumbnailReceiver receiver) {
6278 ArrayList list = new ArrayList();
6279
6280 PendingThumbnailsRecord pending = null;
6281 IApplicationThread topThumbnail = null;
6282 HistoryRecord topRecord = null;
6283
6284 synchronized(this) {
6285 if (localLOGV) Log.v(
6286 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6287 + ", receiver=" + receiver);
6288
6289 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6290 != PackageManager.PERMISSION_GRANTED) {
6291 if (receiver != null) {
6292 // If the caller wants to wait for pending thumbnails,
6293 // it ain't gonna get them.
6294 try {
6295 receiver.finished();
6296 } catch (RemoteException ex) {
6297 }
6298 }
6299 String msg = "Permission Denial: getTasks() from pid="
6300 + Binder.getCallingPid()
6301 + ", uid=" + Binder.getCallingUid()
6302 + " requires " + android.Manifest.permission.GET_TASKS;
6303 Log.w(TAG, msg);
6304 throw new SecurityException(msg);
6305 }
6306
6307 int pos = mHistory.size()-1;
6308 HistoryRecord next =
6309 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6310 HistoryRecord top = null;
6311 CharSequence topDescription = null;
6312 TaskRecord curTask = null;
6313 int numActivities = 0;
6314 int numRunning = 0;
6315 while (pos >= 0 && maxNum > 0) {
6316 final HistoryRecord r = next;
6317 pos--;
6318 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6319
6320 // Initialize state for next task if needed.
6321 if (top == null ||
6322 (top.state == ActivityState.INITIALIZING
6323 && top.task == r.task)) {
6324 top = r;
6325 topDescription = r.description;
6326 curTask = r.task;
6327 numActivities = numRunning = 0;
6328 }
6329
6330 // Add 'r' into the current task.
6331 numActivities++;
6332 if (r.app != null && r.app.thread != null) {
6333 numRunning++;
6334 }
6335 if (topDescription == null) {
6336 topDescription = r.description;
6337 }
6338
6339 if (localLOGV) Log.v(
6340 TAG, r.intent.getComponent().flattenToShortString()
6341 + ": task=" + r.task);
6342
6343 // If the next one is a different task, generate a new
6344 // TaskInfo entry for what we have.
6345 if (next == null || next.task != curTask) {
6346 ActivityManager.RunningTaskInfo ci
6347 = new ActivityManager.RunningTaskInfo();
6348 ci.id = curTask.taskId;
6349 ci.baseActivity = r.intent.getComponent();
6350 ci.topActivity = top.intent.getComponent();
6351 ci.thumbnail = top.thumbnail;
6352 ci.description = topDescription;
6353 ci.numActivities = numActivities;
6354 ci.numRunning = numRunning;
6355 //System.out.println(
6356 // "#" + maxNum + ": " + " descr=" + ci.description);
6357 if (ci.thumbnail == null && receiver != null) {
6358 if (localLOGV) Log.v(
6359 TAG, "State=" + top.state + "Idle=" + top.idle
6360 + " app=" + top.app
6361 + " thr=" + (top.app != null ? top.app.thread : null));
6362 if (top.state == ActivityState.RESUMED
6363 || top.state == ActivityState.PAUSING) {
6364 if (top.idle && top.app != null
6365 && top.app.thread != null) {
6366 topRecord = top;
6367 topThumbnail = top.app.thread;
6368 } else {
6369 top.thumbnailNeeded = true;
6370 }
6371 }
6372 if (pending == null) {
6373 pending = new PendingThumbnailsRecord(receiver);
6374 }
6375 pending.pendingRecords.add(top);
6376 }
6377 list.add(ci);
6378 maxNum--;
6379 top = null;
6380 }
6381 }
6382
6383 if (pending != null) {
6384 mPendingThumbnails.add(pending);
6385 }
6386 }
6387
6388 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6389
6390 if (topThumbnail != null) {
6391 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6392 try {
6393 topThumbnail.requestThumbnail(topRecord);
6394 } catch (Exception e) {
6395 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6396 sendPendingThumbnail(null, topRecord, null, null, true);
6397 }
6398 }
6399
6400 if (pending == null && receiver != null) {
6401 // In this case all thumbnails were available and the client
6402 // is being asked to be told when the remaining ones come in...
6403 // which is unusually, since the top-most currently running
6404 // activity should never have a canned thumbnail! Oh well.
6405 try {
6406 receiver.finished();
6407 } catch (RemoteException ex) {
6408 }
6409 }
6410
6411 return list;
6412 }
6413
6414 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6415 int flags) {
6416 synchronized (this) {
6417 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6418 "getRecentTasks()");
6419
6420 final int N = mRecentTasks.size();
6421 ArrayList<ActivityManager.RecentTaskInfo> res
6422 = new ArrayList<ActivityManager.RecentTaskInfo>(
6423 maxNum < N ? maxNum : N);
6424 for (int i=0; i<N && maxNum > 0; i++) {
6425 TaskRecord tr = mRecentTasks.get(i);
6426 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6427 || (tr.intent == null)
6428 || ((tr.intent.getFlags()
6429 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6430 ActivityManager.RecentTaskInfo rti
6431 = new ActivityManager.RecentTaskInfo();
6432 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6433 rti.baseIntent = new Intent(
6434 tr.intent != null ? tr.intent : tr.affinityIntent);
6435 rti.origActivity = tr.origActivity;
6436 res.add(rti);
6437 maxNum--;
6438 }
6439 }
6440 return res;
6441 }
6442 }
6443
6444 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6445 int j;
6446 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6447 TaskRecord jt = startTask;
6448
6449 // First look backwards
6450 for (j=startIndex-1; j>=0; j--) {
6451 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6452 if (r.task != jt) {
6453 jt = r.task;
6454 if (affinity.equals(jt.affinity)) {
6455 return j;
6456 }
6457 }
6458 }
6459
6460 // Now look forwards
6461 final int N = mHistory.size();
6462 jt = startTask;
6463 for (j=startIndex+1; j<N; j++) {
6464 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6465 if (r.task != jt) {
6466 if (affinity.equals(jt.affinity)) {
6467 return j;
6468 }
6469 jt = r.task;
6470 }
6471 }
6472
6473 // Might it be at the top?
6474 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6475 return N-1;
6476 }
6477
6478 return -1;
6479 }
6480
6481 /**
6482 * Perform a reset of the given task, if needed as part of launching it.
6483 * Returns the new HistoryRecord at the top of the task.
6484 */
6485 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6486 HistoryRecord newActivity) {
6487 boolean forceReset = (newActivity.info.flags
6488 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6489 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6490 if ((newActivity.info.flags
6491 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6492 forceReset = true;
6493 }
6494 }
6495
6496 final TaskRecord task = taskTop.task;
6497
6498 // We are going to move through the history list so that we can look
6499 // at each activity 'target' with 'below' either the interesting
6500 // activity immediately below it in the stack or null.
6501 HistoryRecord target = null;
6502 int targetI = 0;
6503 int taskTopI = -1;
6504 int replyChainEnd = -1;
6505 int lastReparentPos = -1;
6506 for (int i=mHistory.size()-1; i>=-1; i--) {
6507 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6508
6509 if (below != null && below.finishing) {
6510 continue;
6511 }
6512 if (target == null) {
6513 target = below;
6514 targetI = i;
6515 // If we were in the middle of a reply chain before this
6516 // task, it doesn't appear like the root of the chain wants
6517 // anything interesting, so drop it.
6518 replyChainEnd = -1;
6519 continue;
6520 }
6521
6522 final int flags = target.info.flags;
6523
6524 final boolean finishOnTaskLaunch =
6525 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6526 final boolean allowTaskReparenting =
6527 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6528
6529 if (target.task == task) {
6530 // We are inside of the task being reset... we'll either
6531 // finish this activity, push it out for another task,
6532 // or leave it as-is. We only do this
6533 // for activities that are not the root of the task (since
6534 // if we finish the root, we may no longer have the task!).
6535 if (taskTopI < 0) {
6536 taskTopI = targetI;
6537 }
6538 if (below != null && below.task == task) {
6539 final boolean clearWhenTaskReset =
6540 (target.intent.getFlags()
6541 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006542 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006543 // If this activity is sending a reply to a previous
6544 // activity, we can't do anything with it now until
6545 // we reach the start of the reply chain.
6546 // XXX note that we are assuming the result is always
6547 // to the previous activity, which is almost always
6548 // the case but we really shouldn't count on.
6549 if (replyChainEnd < 0) {
6550 replyChainEnd = targetI;
6551 }
Ed Heyl73798232009-03-24 21:32:21 -07006552 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006553 && target.taskAffinity != null
6554 && !target.taskAffinity.equals(task.affinity)) {
6555 // If this activity has an affinity for another
6556 // task, then we need to move it out of here. We will
6557 // move it as far out of the way as possible, to the
6558 // bottom of the activity stack. This also keeps it
6559 // correctly ordered with any activities we previously
6560 // moved.
6561 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6562 if (target.taskAffinity != null
6563 && target.taskAffinity.equals(p.task.affinity)) {
6564 // If the activity currently at the bottom has the
6565 // same task affinity as the one we are moving,
6566 // then merge it into the same task.
6567 target.task = p.task;
6568 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6569 + " out to bottom task " + p.task);
6570 } else {
6571 mCurTask++;
6572 if (mCurTask <= 0) {
6573 mCurTask = 1;
6574 }
6575 target.task = new TaskRecord(mCurTask, target.info, null,
6576 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6577 target.task.affinityIntent = target.intent;
6578 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6579 + " out to new task " + target.task);
6580 }
6581 mWindowManager.setAppGroupId(target, task.taskId);
6582 if (replyChainEnd < 0) {
6583 replyChainEnd = targetI;
6584 }
6585 int dstPos = 0;
6586 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6587 p = (HistoryRecord)mHistory.get(srcPos);
6588 if (p.finishing) {
6589 continue;
6590 }
6591 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6592 + " out to target's task " + target.task);
6593 task.numActivities--;
6594 p.task = target.task;
6595 target.task.numActivities++;
6596 mHistory.remove(srcPos);
6597 mHistory.add(dstPos, p);
6598 mWindowManager.moveAppToken(dstPos, p);
6599 mWindowManager.setAppGroupId(p, p.task.taskId);
6600 dstPos++;
6601 if (VALIDATE_TOKENS) {
6602 mWindowManager.validateAppTokens(mHistory);
6603 }
6604 i++;
6605 }
6606 if (taskTop == p) {
6607 taskTop = below;
6608 }
6609 if (taskTopI == replyChainEnd) {
6610 taskTopI = -1;
6611 }
6612 replyChainEnd = -1;
6613 addRecentTask(target.task);
6614 } else if (forceReset || finishOnTaskLaunch
6615 || clearWhenTaskReset) {
6616 // If the activity should just be removed -- either
6617 // because it asks for it, or the task should be
6618 // cleared -- then finish it and anything that is
6619 // part of its reply chain.
6620 if (clearWhenTaskReset) {
6621 // In this case, we want to finish this activity
6622 // and everything above it, so be sneaky and pretend
6623 // like these are all in the reply chain.
6624 replyChainEnd = targetI+1;
6625 while (replyChainEnd < mHistory.size() &&
6626 ((HistoryRecord)mHistory.get(
6627 replyChainEnd)).task == task) {
6628 replyChainEnd++;
6629 }
6630 replyChainEnd--;
6631 } else if (replyChainEnd < 0) {
6632 replyChainEnd = targetI;
6633 }
6634 HistoryRecord p = null;
6635 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6636 p = (HistoryRecord)mHistory.get(srcPos);
6637 if (p.finishing) {
6638 continue;
6639 }
6640 if (finishActivityLocked(p, srcPos,
6641 Activity.RESULT_CANCELED, null, "reset")) {
6642 replyChainEnd--;
6643 srcPos--;
6644 }
6645 }
6646 if (taskTop == p) {
6647 taskTop = below;
6648 }
6649 if (taskTopI == replyChainEnd) {
6650 taskTopI = -1;
6651 }
6652 replyChainEnd = -1;
6653 } else {
6654 // If we were in the middle of a chain, well the
6655 // activity that started it all doesn't want anything
6656 // special, so leave it all as-is.
6657 replyChainEnd = -1;
6658 }
6659 } else {
6660 // Reached the bottom of the task -- any reply chain
6661 // should be left as-is.
6662 replyChainEnd = -1;
6663 }
6664
6665 } else if (target.resultTo != null) {
6666 // If this activity is sending a reply to a previous
6667 // activity, we can't do anything with it now until
6668 // we reach the start of the reply chain.
6669 // XXX note that we are assuming the result is always
6670 // to the previous activity, which is almost always
6671 // the case but we really shouldn't count on.
6672 if (replyChainEnd < 0) {
6673 replyChainEnd = targetI;
6674 }
6675
6676 } else if (taskTopI >= 0 && allowTaskReparenting
6677 && task.affinity != null
6678 && task.affinity.equals(target.taskAffinity)) {
6679 // We are inside of another task... if this activity has
6680 // an affinity for our task, then either remove it if we are
6681 // clearing or move it over to our task. Note that
6682 // we currently punt on the case where we are resetting a
6683 // task that is not at the top but who has activities above
6684 // with an affinity to it... this is really not a normal
6685 // case, and we will need to later pull that task to the front
6686 // and usually at that point we will do the reset and pick
6687 // up those remaining activities. (This only happens if
6688 // someone starts an activity in a new task from an activity
6689 // in a task that is not currently on top.)
6690 if (forceReset || finishOnTaskLaunch) {
6691 if (replyChainEnd < 0) {
6692 replyChainEnd = targetI;
6693 }
6694 HistoryRecord p = null;
6695 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6696 p = (HistoryRecord)mHistory.get(srcPos);
6697 if (p.finishing) {
6698 continue;
6699 }
6700 if (finishActivityLocked(p, srcPos,
6701 Activity.RESULT_CANCELED, null, "reset")) {
6702 taskTopI--;
6703 lastReparentPos--;
6704 replyChainEnd--;
6705 srcPos--;
6706 }
6707 }
6708 replyChainEnd = -1;
6709 } else {
6710 if (replyChainEnd < 0) {
6711 replyChainEnd = targetI;
6712 }
6713 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6714 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6715 if (p.finishing) {
6716 continue;
6717 }
6718 if (lastReparentPos < 0) {
6719 lastReparentPos = taskTopI;
6720 taskTop = p;
6721 } else {
6722 lastReparentPos--;
6723 }
6724 mHistory.remove(srcPos);
6725 p.task.numActivities--;
6726 p.task = task;
6727 mHistory.add(lastReparentPos, p);
6728 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6729 + " in to resetting task " + task);
6730 task.numActivities++;
6731 mWindowManager.moveAppToken(lastReparentPos, p);
6732 mWindowManager.setAppGroupId(p, p.task.taskId);
6733 if (VALIDATE_TOKENS) {
6734 mWindowManager.validateAppTokens(mHistory);
6735 }
6736 }
6737 replyChainEnd = -1;
6738
6739 // Now we've moved it in to place... but what if this is
6740 // a singleTop activity and we have put it on top of another
6741 // instance of the same activity? Then we drop the instance
6742 // below so it remains singleTop.
6743 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6744 for (int j=lastReparentPos-1; j>=0; j--) {
6745 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6746 if (p.finishing) {
6747 continue;
6748 }
6749 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6750 if (finishActivityLocked(p, j,
6751 Activity.RESULT_CANCELED, null, "replace")) {
6752 taskTopI--;
6753 lastReparentPos--;
6754 }
6755 }
6756 }
6757 }
6758 }
6759 }
6760
6761 target = below;
6762 targetI = i;
6763 }
6764
6765 return taskTop;
6766 }
6767
6768 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006769 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006770 */
6771 public void moveTaskToFront(int task) {
6772 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6773 "moveTaskToFront()");
6774
6775 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006776 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6777 Binder.getCallingUid(), "Task to front")) {
6778 return;
6779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006780 final long origId = Binder.clearCallingIdentity();
6781 try {
6782 int N = mRecentTasks.size();
6783 for (int i=0; i<N; i++) {
6784 TaskRecord tr = mRecentTasks.get(i);
6785 if (tr.taskId == task) {
6786 moveTaskToFrontLocked(tr);
6787 return;
6788 }
6789 }
6790 for (int i=mHistory.size()-1; i>=0; i--) {
6791 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6792 if (hr.task.taskId == task) {
6793 moveTaskToFrontLocked(hr.task);
6794 return;
6795 }
6796 }
6797 } finally {
6798 Binder.restoreCallingIdentity(origId);
6799 }
6800 }
6801 }
6802
6803 private final void moveTaskToFrontLocked(TaskRecord tr) {
6804 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6805
6806 final int task = tr.taskId;
6807 int top = mHistory.size()-1;
6808
6809 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6810 // nothing to do!
6811 return;
6812 }
6813
6814 if (DEBUG_TRANSITION) Log.v(TAG,
6815 "Prepare to front transition: task=" + tr);
6816 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6817
6818 ArrayList moved = new ArrayList();
6819
6820 // Applying the affinities may have removed entries from the history,
6821 // so get the size again.
6822 top = mHistory.size()-1;
6823 int pos = top;
6824
6825 // Shift all activities with this task up to the top
6826 // of the stack, keeping them in the same internal order.
6827 while (pos >= 0) {
6828 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6829 if (localLOGV) Log.v(
6830 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6831 boolean first = true;
6832 if (r.task.taskId == task) {
6833 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6834 mHistory.remove(pos);
6835 mHistory.add(top, r);
6836 moved.add(0, r);
6837 top--;
6838 if (first) {
6839 addRecentTask(r.task);
6840 first = false;
6841 }
6842 }
6843 pos--;
6844 }
6845
6846 mWindowManager.moveAppTokensToTop(moved);
6847 if (VALIDATE_TOKENS) {
6848 mWindowManager.validateAppTokens(mHistory);
6849 }
6850
6851 finishTaskMove(task);
6852 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6853 }
6854
6855 private final void finishTaskMove(int task) {
6856 resumeTopActivityLocked(null);
6857 }
6858
6859 public void moveTaskToBack(int task) {
6860 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6861 "moveTaskToBack()");
6862
6863 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006864 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6865 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6866 Binder.getCallingUid(), "Task to back")) {
6867 return;
6868 }
6869 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006870 final long origId = Binder.clearCallingIdentity();
6871 moveTaskToBackLocked(task);
6872 Binder.restoreCallingIdentity(origId);
6873 }
6874 }
6875
6876 /**
6877 * Moves an activity, and all of the other activities within the same task, to the bottom
6878 * of the history stack. The activity's order within the task is unchanged.
6879 *
6880 * @param token A reference to the activity we wish to move
6881 * @param nonRoot If false then this only works if the activity is the root
6882 * of a task; if true it will work for any activity in a task.
6883 * @return Returns true if the move completed, false if not.
6884 */
6885 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6886 synchronized(this) {
6887 final long origId = Binder.clearCallingIdentity();
6888 int taskId = getTaskForActivityLocked(token, !nonRoot);
6889 if (taskId >= 0) {
6890 return moveTaskToBackLocked(taskId);
6891 }
6892 Binder.restoreCallingIdentity(origId);
6893 }
6894 return false;
6895 }
6896
6897 /**
6898 * Worker method for rearranging history stack. Implements the function of moving all
6899 * activities for a specific task (gathering them if disjoint) into a single group at the
6900 * bottom of the stack.
6901 *
6902 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6903 * to premeptively cancel the move.
6904 *
6905 * @param task The taskId to collect and move to the bottom.
6906 * @return Returns true if the move completed, false if not.
6907 */
6908 private final boolean moveTaskToBackLocked(int task) {
6909 Log.i(TAG, "moveTaskToBack: " + task);
6910
6911 // If we have a watcher, preflight the move before committing to it. First check
6912 // for *other* available tasks, but if none are available, then try again allowing the
6913 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006914 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006915 HistoryRecord next = topRunningActivityLocked(null, task);
6916 if (next == null) {
6917 next = topRunningActivityLocked(null, 0);
6918 }
6919 if (next != null) {
6920 // ask watcher if this is allowed
6921 boolean moveOK = true;
6922 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006923 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006924 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006925 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006926 }
6927 if (!moveOK) {
6928 return false;
6929 }
6930 }
6931 }
6932
6933 ArrayList moved = new ArrayList();
6934
6935 if (DEBUG_TRANSITION) Log.v(TAG,
6936 "Prepare to back transition: task=" + task);
6937 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6938
6939 final int N = mHistory.size();
6940 int bottom = 0;
6941 int pos = 0;
6942
6943 // Shift all activities with this task down to the bottom
6944 // of the stack, keeping them in the same internal order.
6945 while (pos < N) {
6946 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6947 if (localLOGV) Log.v(
6948 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6949 if (r.task.taskId == task) {
6950 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6951 mHistory.remove(pos);
6952 mHistory.add(bottom, r);
6953 moved.add(r);
6954 bottom++;
6955 }
6956 pos++;
6957 }
6958
6959 mWindowManager.moveAppTokensToBottom(moved);
6960 if (VALIDATE_TOKENS) {
6961 mWindowManager.validateAppTokens(mHistory);
6962 }
6963
6964 finishTaskMove(task);
6965 return true;
6966 }
6967
6968 public void moveTaskBackwards(int task) {
6969 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6970 "moveTaskBackwards()");
6971
6972 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006973 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6974 Binder.getCallingUid(), "Task backwards")) {
6975 return;
6976 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006977 final long origId = Binder.clearCallingIdentity();
6978 moveTaskBackwardsLocked(task);
6979 Binder.restoreCallingIdentity(origId);
6980 }
6981 }
6982
6983 private final void moveTaskBackwardsLocked(int task) {
6984 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6985 }
6986
6987 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6988 synchronized(this) {
6989 return getTaskForActivityLocked(token, onlyRoot);
6990 }
6991 }
6992
6993 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6994 final int N = mHistory.size();
6995 TaskRecord lastTask = null;
6996 for (int i=0; i<N; i++) {
6997 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6998 if (r == token) {
6999 if (!onlyRoot || lastTask != r.task) {
7000 return r.task.taskId;
7001 }
7002 return -1;
7003 }
7004 lastTask = r.task;
7005 }
7006
7007 return -1;
7008 }
7009
7010 /**
7011 * Returns the top activity in any existing task matching the given
7012 * Intent. Returns null if no such task is found.
7013 */
7014 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7015 ComponentName cls = intent.getComponent();
7016 if (info.targetActivity != null) {
7017 cls = new ComponentName(info.packageName, info.targetActivity);
7018 }
7019
7020 TaskRecord cp = null;
7021
7022 final int N = mHistory.size();
7023 for (int i=(N-1); i>=0; i--) {
7024 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7025 if (!r.finishing && r.task != cp
7026 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7027 cp = r.task;
7028 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7029 // + "/aff=" + r.task.affinity + " to new cls="
7030 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7031 if (r.task.affinity != null) {
7032 if (r.task.affinity.equals(info.taskAffinity)) {
7033 //Log.i(TAG, "Found matching affinity!");
7034 return r;
7035 }
7036 } else if (r.task.intent != null
7037 && r.task.intent.getComponent().equals(cls)) {
7038 //Log.i(TAG, "Found matching class!");
7039 //dump();
7040 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7041 return r;
7042 } else if (r.task.affinityIntent != null
7043 && r.task.affinityIntent.getComponent().equals(cls)) {
7044 //Log.i(TAG, "Found matching class!");
7045 //dump();
7046 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7047 return r;
7048 }
7049 }
7050 }
7051
7052 return null;
7053 }
7054
7055 /**
7056 * Returns the first activity (starting from the top of the stack) that
7057 * is the same as the given activity. Returns null if no such activity
7058 * is found.
7059 */
7060 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7061 ComponentName cls = intent.getComponent();
7062 if (info.targetActivity != null) {
7063 cls = new ComponentName(info.packageName, info.targetActivity);
7064 }
7065
7066 final int N = mHistory.size();
7067 for (int i=(N-1); i>=0; i--) {
7068 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7069 if (!r.finishing) {
7070 if (r.intent.getComponent().equals(cls)) {
7071 //Log.i(TAG, "Found matching class!");
7072 //dump();
7073 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7074 return r;
7075 }
7076 }
7077 }
7078
7079 return null;
7080 }
7081
7082 public void finishOtherInstances(IBinder token, ComponentName className) {
7083 synchronized(this) {
7084 final long origId = Binder.clearCallingIdentity();
7085
7086 int N = mHistory.size();
7087 TaskRecord lastTask = null;
7088 for (int i=0; i<N; i++) {
7089 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7090 if (r.realActivity.equals(className)
7091 && r != token && lastTask != r.task) {
7092 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7093 null, "others")) {
7094 i--;
7095 N--;
7096 }
7097 }
7098 lastTask = r.task;
7099 }
7100
7101 Binder.restoreCallingIdentity(origId);
7102 }
7103 }
7104
7105 // =========================================================
7106 // THUMBNAILS
7107 // =========================================================
7108
7109 public void reportThumbnail(IBinder token,
7110 Bitmap thumbnail, CharSequence description) {
7111 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7112 final long origId = Binder.clearCallingIdentity();
7113 sendPendingThumbnail(null, token, thumbnail, description, true);
7114 Binder.restoreCallingIdentity(origId);
7115 }
7116
7117 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7118 Bitmap thumbnail, CharSequence description, boolean always) {
7119 TaskRecord task = null;
7120 ArrayList receivers = null;
7121
7122 //System.out.println("Send pending thumbnail: " + r);
7123
7124 synchronized(this) {
7125 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007126 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007127 if (index < 0) {
7128 return;
7129 }
7130 r = (HistoryRecord)mHistory.get(index);
7131 }
7132 if (thumbnail == null) {
7133 thumbnail = r.thumbnail;
7134 description = r.description;
7135 }
7136 if (thumbnail == null && !always) {
7137 // If there is no thumbnail, and this entry is not actually
7138 // going away, then abort for now and pick up the next
7139 // thumbnail we get.
7140 return;
7141 }
7142 task = r.task;
7143
7144 int N = mPendingThumbnails.size();
7145 int i=0;
7146 while (i<N) {
7147 PendingThumbnailsRecord pr =
7148 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7149 //System.out.println("Looking in " + pr.pendingRecords);
7150 if (pr.pendingRecords.remove(r)) {
7151 if (receivers == null) {
7152 receivers = new ArrayList();
7153 }
7154 receivers.add(pr);
7155 if (pr.pendingRecords.size() == 0) {
7156 pr.finished = true;
7157 mPendingThumbnails.remove(i);
7158 N--;
7159 continue;
7160 }
7161 }
7162 i++;
7163 }
7164 }
7165
7166 if (receivers != null) {
7167 final int N = receivers.size();
7168 for (int i=0; i<N; i++) {
7169 try {
7170 PendingThumbnailsRecord pr =
7171 (PendingThumbnailsRecord)receivers.get(i);
7172 pr.receiver.newThumbnail(
7173 task != null ? task.taskId : -1, thumbnail, description);
7174 if (pr.finished) {
7175 pr.receiver.finished();
7176 }
7177 } catch (Exception e) {
7178 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7179 }
7180 }
7181 }
7182 }
7183
7184 // =========================================================
7185 // CONTENT PROVIDERS
7186 // =========================================================
7187
7188 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7189 List providers = null;
7190 try {
7191 providers = ActivityThread.getPackageManager().
7192 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007193 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007194 } catch (RemoteException ex) {
7195 }
7196 if (providers != null) {
7197 final int N = providers.size();
7198 for (int i=0; i<N; i++) {
7199 ProviderInfo cpi =
7200 (ProviderInfo)providers.get(i);
7201 ContentProviderRecord cpr =
7202 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7203 if (cpr == null) {
7204 cpr = new ContentProviderRecord(cpi, app.info);
7205 mProvidersByClass.put(cpi.name, cpr);
7206 }
7207 app.pubProviders.put(cpi.name, cpr);
7208 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007209 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007210 }
7211 }
7212 return providers;
7213 }
7214
7215 private final String checkContentProviderPermissionLocked(
7216 ProviderInfo cpi, ProcessRecord r, int mode) {
7217 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7218 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7219 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7220 cpi.exported ? -1 : cpi.applicationInfo.uid)
7221 == PackageManager.PERMISSION_GRANTED
7222 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7223 return null;
7224 }
7225 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7226 cpi.exported ? -1 : cpi.applicationInfo.uid)
7227 == PackageManager.PERMISSION_GRANTED) {
7228 return null;
7229 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007230
7231 PathPermission[] pps = cpi.pathPermissions;
7232 if (pps != null) {
7233 int i = pps.length;
7234 while (i > 0) {
7235 i--;
7236 PathPermission pp = pps[i];
7237 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7238 cpi.exported ? -1 : cpi.applicationInfo.uid)
7239 == PackageManager.PERMISSION_GRANTED
7240 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7241 return null;
7242 }
7243 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7244 cpi.exported ? -1 : cpi.applicationInfo.uid)
7245 == PackageManager.PERMISSION_GRANTED) {
7246 return null;
7247 }
7248 }
7249 }
7250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007251 String msg = "Permission Denial: opening provider " + cpi.name
7252 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7253 + ", uid=" + callingUid + ") requires "
7254 + cpi.readPermission + " or " + cpi.writePermission;
7255 Log.w(TAG, msg);
7256 return msg;
7257 }
7258
7259 private final ContentProviderHolder getContentProviderImpl(
7260 IApplicationThread caller, String name) {
7261 ContentProviderRecord cpr;
7262 ProviderInfo cpi = null;
7263
7264 synchronized(this) {
7265 ProcessRecord r = null;
7266 if (caller != null) {
7267 r = getRecordForAppLocked(caller);
7268 if (r == null) {
7269 throw new SecurityException(
7270 "Unable to find app for caller " + caller
7271 + " (pid=" + Binder.getCallingPid()
7272 + ") when getting content provider " + name);
7273 }
7274 }
7275
7276 // First check if this content provider has been published...
7277 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7278 if (cpr != null) {
7279 cpi = cpr.info;
7280 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7281 return new ContentProviderHolder(cpi,
7282 cpi.readPermission != null
7283 ? cpi.readPermission : cpi.writePermission);
7284 }
7285
7286 if (r != null && cpr.canRunHere(r)) {
7287 // This provider has been published or is in the process
7288 // of being published... but it is also allowed to run
7289 // in the caller's process, so don't make a connection
7290 // and just let the caller instantiate its own instance.
7291 if (cpr.provider != null) {
7292 // don't give caller the provider object, it needs
7293 // to make its own.
7294 cpr = new ContentProviderRecord(cpr);
7295 }
7296 return cpr;
7297 }
7298
7299 final long origId = Binder.clearCallingIdentity();
7300
7301 // In this case the provider is a single instance, so we can
7302 // return it right away.
7303 if (r != null) {
7304 r.conProviders.add(cpr);
7305 cpr.clients.add(r);
7306 } else {
7307 cpr.externals++;
7308 }
7309
7310 if (cpr.app != null) {
7311 updateOomAdjLocked(cpr.app);
7312 }
7313
7314 Binder.restoreCallingIdentity(origId);
7315
7316 } else {
7317 try {
7318 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007319 resolveContentProvider(name,
7320 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007321 } catch (RemoteException ex) {
7322 }
7323 if (cpi == null) {
7324 return null;
7325 }
7326
7327 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7328 return new ContentProviderHolder(cpi,
7329 cpi.readPermission != null
7330 ? cpi.readPermission : cpi.writePermission);
7331 }
7332
7333 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7334 final boolean firstClass = cpr == null;
7335 if (firstClass) {
7336 try {
7337 ApplicationInfo ai =
7338 ActivityThread.getPackageManager().
7339 getApplicationInfo(
7340 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007341 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007342 if (ai == null) {
7343 Log.w(TAG, "No package info for content provider "
7344 + cpi.name);
7345 return null;
7346 }
7347 cpr = new ContentProviderRecord(cpi, ai);
7348 } catch (RemoteException ex) {
7349 // pm is in same process, this will never happen.
7350 }
7351 }
7352
7353 if (r != null && cpr.canRunHere(r)) {
7354 // If this is a multiprocess provider, then just return its
7355 // info and allow the caller to instantiate it. Only do
7356 // this if the provider is the same user as the caller's
7357 // process, or can run as root (so can be in any process).
7358 return cpr;
7359 }
7360
7361 if (false) {
7362 RuntimeException e = new RuntimeException("foo");
7363 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7364 // + " pruid " + ai.uid + "): " + cpi.className, e);
7365 }
7366
7367 // This is single process, and our app is now connecting to it.
7368 // See if we are already in the process of launching this
7369 // provider.
7370 final int N = mLaunchingProviders.size();
7371 int i;
7372 for (i=0; i<N; i++) {
7373 if (mLaunchingProviders.get(i) == cpr) {
7374 break;
7375 }
7376 if (false) {
7377 final ContentProviderRecord rec =
7378 (ContentProviderRecord)mLaunchingProviders.get(i);
7379 if (rec.info.name.equals(cpr.info.name)) {
7380 cpr = rec;
7381 break;
7382 }
7383 }
7384 }
7385
7386 // If the provider is not already being launched, then get it
7387 // started.
7388 if (i >= N) {
7389 final long origId = Binder.clearCallingIdentity();
7390 ProcessRecord proc = startProcessLocked(cpi.processName,
7391 cpr.appInfo, false, 0, "content provider",
7392 new ComponentName(cpi.applicationInfo.packageName,
7393 cpi.name));
7394 if (proc == null) {
7395 Log.w(TAG, "Unable to launch app "
7396 + cpi.applicationInfo.packageName + "/"
7397 + cpi.applicationInfo.uid + " for provider "
7398 + name + ": process is bad");
7399 return null;
7400 }
7401 cpr.launchingApp = proc;
7402 mLaunchingProviders.add(cpr);
7403 Binder.restoreCallingIdentity(origId);
7404 }
7405
7406 // Make sure the provider is published (the same provider class
7407 // may be published under multiple names).
7408 if (firstClass) {
7409 mProvidersByClass.put(cpi.name, cpr);
7410 }
7411 mProvidersByName.put(name, cpr);
7412
7413 if (r != null) {
7414 r.conProviders.add(cpr);
7415 cpr.clients.add(r);
7416 } else {
7417 cpr.externals++;
7418 }
7419 }
7420 }
7421
7422 // Wait for the provider to be published...
7423 synchronized (cpr) {
7424 while (cpr.provider == null) {
7425 if (cpr.launchingApp == null) {
7426 Log.w(TAG, "Unable to launch app "
7427 + cpi.applicationInfo.packageName + "/"
7428 + cpi.applicationInfo.uid + " for provider "
7429 + name + ": launching app became null");
7430 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7431 cpi.applicationInfo.packageName,
7432 cpi.applicationInfo.uid, name);
7433 return null;
7434 }
7435 try {
7436 cpr.wait();
7437 } catch (InterruptedException ex) {
7438 }
7439 }
7440 }
7441 return cpr;
7442 }
7443
7444 public final ContentProviderHolder getContentProvider(
7445 IApplicationThread caller, String name) {
7446 if (caller == null) {
7447 String msg = "null IApplicationThread when getting content provider "
7448 + name;
7449 Log.w(TAG, msg);
7450 throw new SecurityException(msg);
7451 }
7452
7453 return getContentProviderImpl(caller, name);
7454 }
7455
7456 private ContentProviderHolder getContentProviderExternal(String name) {
7457 return getContentProviderImpl(null, name);
7458 }
7459
7460 /**
7461 * Drop a content provider from a ProcessRecord's bookkeeping
7462 * @param cpr
7463 */
7464 public void removeContentProvider(IApplicationThread caller, String name) {
7465 synchronized (this) {
7466 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7467 if(cpr == null) {
7468 //remove from mProvidersByClass
7469 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7470 return;
7471 }
7472 final ProcessRecord r = getRecordForAppLocked(caller);
7473 if (r == null) {
7474 throw new SecurityException(
7475 "Unable to find app for caller " + caller +
7476 " when removing content provider " + name);
7477 }
7478 //update content provider record entry info
7479 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7480 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7481 r.info.processName+" from process "+localCpr.appInfo.processName);
7482 if(localCpr.appInfo.processName == r.info.processName) {
7483 //should not happen. taken care of as a local provider
7484 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7485 return;
7486 } else {
7487 localCpr.clients.remove(r);
7488 r.conProviders.remove(localCpr);
7489 }
7490 updateOomAdjLocked();
7491 }
7492 }
7493
7494 private void removeContentProviderExternal(String name) {
7495 synchronized (this) {
7496 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7497 if(cpr == null) {
7498 //remove from mProvidersByClass
7499 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7500 return;
7501 }
7502
7503 //update content provider record entry info
7504 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7505 localCpr.externals--;
7506 if (localCpr.externals < 0) {
7507 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7508 }
7509 updateOomAdjLocked();
7510 }
7511 }
7512
7513 public final void publishContentProviders(IApplicationThread caller,
7514 List<ContentProviderHolder> providers) {
7515 if (providers == null) {
7516 return;
7517 }
7518
7519 synchronized(this) {
7520 final ProcessRecord r = getRecordForAppLocked(caller);
7521 if (r == null) {
7522 throw new SecurityException(
7523 "Unable to find app for caller " + caller
7524 + " (pid=" + Binder.getCallingPid()
7525 + ") when publishing content providers");
7526 }
7527
7528 final long origId = Binder.clearCallingIdentity();
7529
7530 final int N = providers.size();
7531 for (int i=0; i<N; i++) {
7532 ContentProviderHolder src = providers.get(i);
7533 if (src == null || src.info == null || src.provider == null) {
7534 continue;
7535 }
7536 ContentProviderRecord dst =
7537 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7538 if (dst != null) {
7539 mProvidersByClass.put(dst.info.name, dst);
7540 String names[] = dst.info.authority.split(";");
7541 for (int j = 0; j < names.length; j++) {
7542 mProvidersByName.put(names[j], dst);
7543 }
7544
7545 int NL = mLaunchingProviders.size();
7546 int j;
7547 for (j=0; j<NL; j++) {
7548 if (mLaunchingProviders.get(j) == dst) {
7549 mLaunchingProviders.remove(j);
7550 j--;
7551 NL--;
7552 }
7553 }
7554 synchronized (dst) {
7555 dst.provider = src.provider;
7556 dst.app = r;
7557 dst.notifyAll();
7558 }
7559 updateOomAdjLocked(r);
7560 }
7561 }
7562
7563 Binder.restoreCallingIdentity(origId);
7564 }
7565 }
7566
7567 public static final void installSystemProviders() {
7568 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7569 List providers = mSelf.generateApplicationProvidersLocked(app);
7570 mSystemThread.installSystemProviders(providers);
7571 }
7572
7573 // =========================================================
7574 // GLOBAL MANAGEMENT
7575 // =========================================================
7576
7577 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7578 ApplicationInfo info, String customProcess) {
7579 String proc = customProcess != null ? customProcess : info.processName;
7580 BatteryStatsImpl.Uid.Proc ps = null;
7581 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7582 synchronized (stats) {
7583 ps = stats.getProcessStatsLocked(info.uid, proc);
7584 }
7585 return new ProcessRecord(ps, thread, info, proc);
7586 }
7587
7588 final ProcessRecord addAppLocked(ApplicationInfo info) {
7589 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7590
7591 if (app == null) {
7592 app = newProcessRecordLocked(null, info, null);
7593 mProcessNames.put(info.processName, info.uid, app);
7594 updateLRUListLocked(app, true);
7595 }
7596
7597 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7598 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7599 app.persistent = true;
7600 app.maxAdj = CORE_SERVER_ADJ;
7601 }
7602 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7603 mPersistentStartingProcesses.add(app);
7604 startProcessLocked(app, "added application", app.processName);
7605 }
7606
7607 return app;
7608 }
7609
7610 public void unhandledBack() {
7611 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7612 "unhandledBack()");
7613
7614 synchronized(this) {
7615 int count = mHistory.size();
7616 if (Config.LOGD) Log.d(
7617 TAG, "Performing unhandledBack(): stack size = " + count);
7618 if (count > 1) {
7619 final long origId = Binder.clearCallingIdentity();
7620 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7621 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7622 Binder.restoreCallingIdentity(origId);
7623 }
7624 }
7625 }
7626
7627 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7628 String name = uri.getAuthority();
7629 ContentProviderHolder cph = getContentProviderExternal(name);
7630 ParcelFileDescriptor pfd = null;
7631 if (cph != null) {
7632 // We record the binder invoker's uid in thread-local storage before
7633 // going to the content provider to open the file. Later, in the code
7634 // that handles all permissions checks, we look for this uid and use
7635 // that rather than the Activity Manager's own uid. The effect is that
7636 // we do the check against the caller's permissions even though it looks
7637 // to the content provider like the Activity Manager itself is making
7638 // the request.
7639 sCallerIdentity.set(new Identity(
7640 Binder.getCallingPid(), Binder.getCallingUid()));
7641 try {
7642 pfd = cph.provider.openFile(uri, "r");
7643 } catch (FileNotFoundException e) {
7644 // do nothing; pfd will be returned null
7645 } finally {
7646 // Ensure that whatever happens, we clean up the identity state
7647 sCallerIdentity.remove();
7648 }
7649
7650 // We've got the fd now, so we're done with the provider.
7651 removeContentProviderExternal(name);
7652 } else {
7653 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7654 }
7655 return pfd;
7656 }
7657
7658 public void goingToSleep() {
7659 synchronized(this) {
7660 mSleeping = true;
7661 mWindowManager.setEventDispatching(false);
7662
7663 if (mResumedActivity != null) {
7664 pauseIfSleepingLocked();
7665 } else {
7666 Log.w(TAG, "goingToSleep with no resumed activity!");
7667 }
7668 }
7669 }
7670
Dianne Hackborn55280a92009-05-07 15:53:46 -07007671 public boolean shutdown(int timeout) {
7672 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7673 != PackageManager.PERMISSION_GRANTED) {
7674 throw new SecurityException("Requires permission "
7675 + android.Manifest.permission.SHUTDOWN);
7676 }
7677
7678 boolean timedout = false;
7679
7680 synchronized(this) {
7681 mShuttingDown = true;
7682 mWindowManager.setEventDispatching(false);
7683
7684 if (mResumedActivity != null) {
7685 pauseIfSleepingLocked();
7686 final long endTime = System.currentTimeMillis() + timeout;
7687 while (mResumedActivity != null || mPausingActivity != null) {
7688 long delay = endTime - System.currentTimeMillis();
7689 if (delay <= 0) {
7690 Log.w(TAG, "Activity manager shutdown timed out");
7691 timedout = true;
7692 break;
7693 }
7694 try {
7695 this.wait();
7696 } catch (InterruptedException e) {
7697 }
7698 }
7699 }
7700 }
7701
7702 mUsageStatsService.shutdown();
7703 mBatteryStatsService.shutdown();
7704
7705 return timedout;
7706 }
7707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007708 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007709 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007710 if (!mGoingToSleep.isHeld()) {
7711 mGoingToSleep.acquire();
7712 if (mLaunchingActivity.isHeld()) {
7713 mLaunchingActivity.release();
7714 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7715 }
7716 }
7717
7718 // If we are not currently pausing an activity, get the current
7719 // one to pause. If we are pausing one, we will just let that stuff
7720 // run and release the wake lock when all done.
7721 if (mPausingActivity == null) {
7722 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7723 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7724 startPausingLocked(false, true);
7725 }
7726 }
7727 }
7728
7729 public void wakingUp() {
7730 synchronized(this) {
7731 if (mGoingToSleep.isHeld()) {
7732 mGoingToSleep.release();
7733 }
7734 mWindowManager.setEventDispatching(true);
7735 mSleeping = false;
7736 resumeTopActivityLocked(null);
7737 }
7738 }
7739
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007740 public void stopAppSwitches() {
7741 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7742 != PackageManager.PERMISSION_GRANTED) {
7743 throw new SecurityException("Requires permission "
7744 + android.Manifest.permission.STOP_APP_SWITCHES);
7745 }
7746
7747 synchronized(this) {
7748 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7749 + APP_SWITCH_DELAY_TIME;
7750 mDidAppSwitch = false;
7751 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7752 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7753 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7754 }
7755 }
7756
7757 public void resumeAppSwitches() {
7758 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7759 != PackageManager.PERMISSION_GRANTED) {
7760 throw new SecurityException("Requires permission "
7761 + android.Manifest.permission.STOP_APP_SWITCHES);
7762 }
7763
7764 synchronized(this) {
7765 // Note that we don't execute any pending app switches... we will
7766 // let those wait until either the timeout, or the next start
7767 // activity request.
7768 mAppSwitchesAllowedTime = 0;
7769 }
7770 }
7771
7772 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7773 String name) {
7774 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7775 return true;
7776 }
7777
7778 final int perm = checkComponentPermission(
7779 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7780 callingUid, -1);
7781 if (perm == PackageManager.PERMISSION_GRANTED) {
7782 return true;
7783 }
7784
7785 Log.w(TAG, name + " request from " + callingUid + " stopped");
7786 return false;
7787 }
7788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007789 public void setDebugApp(String packageName, boolean waitForDebugger,
7790 boolean persistent) {
7791 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7792 "setDebugApp()");
7793
7794 // Note that this is not really thread safe if there are multiple
7795 // callers into it at the same time, but that's not a situation we
7796 // care about.
7797 if (persistent) {
7798 final ContentResolver resolver = mContext.getContentResolver();
7799 Settings.System.putString(
7800 resolver, Settings.System.DEBUG_APP,
7801 packageName);
7802 Settings.System.putInt(
7803 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7804 waitForDebugger ? 1 : 0);
7805 }
7806
7807 synchronized (this) {
7808 if (!persistent) {
7809 mOrigDebugApp = mDebugApp;
7810 mOrigWaitForDebugger = mWaitForDebugger;
7811 }
7812 mDebugApp = packageName;
7813 mWaitForDebugger = waitForDebugger;
7814 mDebugTransient = !persistent;
7815 if (packageName != null) {
7816 final long origId = Binder.clearCallingIdentity();
7817 uninstallPackageLocked(packageName, -1, false);
7818 Binder.restoreCallingIdentity(origId);
7819 }
7820 }
7821 }
7822
7823 public void setAlwaysFinish(boolean enabled) {
7824 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7825 "setAlwaysFinish()");
7826
7827 Settings.System.putInt(
7828 mContext.getContentResolver(),
7829 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7830
7831 synchronized (this) {
7832 mAlwaysFinishActivities = enabled;
7833 }
7834 }
7835
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007836 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007837 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007838 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007839 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007840 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007841 }
7842 }
7843
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007844 public void registerActivityWatcher(IActivityWatcher watcher) {
7845 mWatchers.register(watcher);
7846 }
7847
7848 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7849 mWatchers.unregister(watcher);
7850 }
7851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007852 public final void enterSafeMode() {
7853 synchronized(this) {
7854 // It only makes sense to do this before the system is ready
7855 // and started launching other packages.
7856 if (!mSystemReady) {
7857 try {
7858 ActivityThread.getPackageManager().enterSafeMode();
7859 } catch (RemoteException e) {
7860 }
7861
7862 View v = LayoutInflater.from(mContext).inflate(
7863 com.android.internal.R.layout.safe_mode, null);
7864 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7865 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7866 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7867 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7868 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7869 lp.format = v.getBackground().getOpacity();
7870 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7871 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7872 ((WindowManager)mContext.getSystemService(
7873 Context.WINDOW_SERVICE)).addView(v, lp);
7874 }
7875 }
7876 }
7877
7878 public void noteWakeupAlarm(IIntentSender sender) {
7879 if (!(sender instanceof PendingIntentRecord)) {
7880 return;
7881 }
7882 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7883 synchronized (stats) {
7884 if (mBatteryStatsService.isOnBattery()) {
7885 mBatteryStatsService.enforceCallingPermission();
7886 PendingIntentRecord rec = (PendingIntentRecord)sender;
7887 int MY_UID = Binder.getCallingUid();
7888 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7889 BatteryStatsImpl.Uid.Pkg pkg =
7890 stats.getPackageStatsLocked(uid, rec.key.packageName);
7891 pkg.incWakeupsLocked();
7892 }
7893 }
7894 }
7895
7896 public boolean killPidsForMemory(int[] pids) {
7897 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7898 throw new SecurityException("killPidsForMemory only available to the system");
7899 }
7900
7901 // XXX Note: don't acquire main activity lock here, because the window
7902 // manager calls in with its locks held.
7903
7904 boolean killed = false;
7905 synchronized (mPidsSelfLocked) {
7906 int[] types = new int[pids.length];
7907 int worstType = 0;
7908 for (int i=0; i<pids.length; i++) {
7909 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7910 if (proc != null) {
7911 int type = proc.setAdj;
7912 types[i] = type;
7913 if (type > worstType) {
7914 worstType = type;
7915 }
7916 }
7917 }
7918
7919 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7920 // then constrain it so we will kill all hidden procs.
7921 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7922 worstType = HIDDEN_APP_MIN_ADJ;
7923 }
7924 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7925 for (int i=0; i<pids.length; i++) {
7926 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7927 if (proc == null) {
7928 continue;
7929 }
7930 int adj = proc.setAdj;
7931 if (adj >= worstType) {
7932 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7933 + adj + ")");
7934 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7935 proc.processName, adj);
7936 killed = true;
7937 Process.killProcess(pids[i]);
7938 }
7939 }
7940 }
7941 return killed;
7942 }
7943
7944 public void reportPss(IApplicationThread caller, int pss) {
7945 Watchdog.PssRequestor req;
7946 String name;
7947 ProcessRecord callerApp;
7948 synchronized (this) {
7949 if (caller == null) {
7950 return;
7951 }
7952 callerApp = getRecordForAppLocked(caller);
7953 if (callerApp == null) {
7954 return;
7955 }
7956 callerApp.lastPss = pss;
7957 req = callerApp;
7958 name = callerApp.processName;
7959 }
7960 Watchdog.getInstance().reportPss(req, name, pss);
7961 if (!callerApp.persistent) {
7962 removeRequestedPss(callerApp);
7963 }
7964 }
7965
7966 public void requestPss(Runnable completeCallback) {
7967 ArrayList<ProcessRecord> procs;
7968 synchronized (this) {
7969 mRequestPssCallback = completeCallback;
7970 mRequestPssList.clear();
7971 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7972 ProcessRecord proc = mLRUProcesses.get(i);
7973 if (!proc.persistent) {
7974 mRequestPssList.add(proc);
7975 }
7976 }
7977 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7978 }
7979
7980 int oldPri = Process.getThreadPriority(Process.myTid());
7981 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7982 for (int i=procs.size()-1; i>=0; i--) {
7983 ProcessRecord proc = procs.get(i);
7984 proc.lastPss = 0;
7985 proc.requestPss();
7986 }
7987 Process.setThreadPriority(oldPri);
7988 }
7989
7990 void removeRequestedPss(ProcessRecord proc) {
7991 Runnable callback = null;
7992 synchronized (this) {
7993 if (mRequestPssList.remove(proc)) {
7994 if (mRequestPssList.size() == 0) {
7995 callback = mRequestPssCallback;
7996 mRequestPssCallback = null;
7997 }
7998 }
7999 }
8000
8001 if (callback != null) {
8002 callback.run();
8003 }
8004 }
8005
8006 public void collectPss(Watchdog.PssStats stats) {
8007 stats.mEmptyPss = 0;
8008 stats.mEmptyCount = 0;
8009 stats.mBackgroundPss = 0;
8010 stats.mBackgroundCount = 0;
8011 stats.mServicePss = 0;
8012 stats.mServiceCount = 0;
8013 stats.mVisiblePss = 0;
8014 stats.mVisibleCount = 0;
8015 stats.mForegroundPss = 0;
8016 stats.mForegroundCount = 0;
8017 stats.mNoPssCount = 0;
8018 synchronized (this) {
8019 int i;
8020 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8021 ? mProcDeaths.length : stats.mProcDeaths.length;
8022 int aggr = 0;
8023 for (i=0; i<NPD; i++) {
8024 aggr += mProcDeaths[i];
8025 stats.mProcDeaths[i] = aggr;
8026 }
8027 while (i<stats.mProcDeaths.length) {
8028 stats.mProcDeaths[i] = 0;
8029 i++;
8030 }
8031
8032 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8033 ProcessRecord proc = mLRUProcesses.get(i);
8034 if (proc.persistent) {
8035 continue;
8036 }
8037 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8038 if (proc.lastPss == 0) {
8039 stats.mNoPssCount++;
8040 continue;
8041 }
8042 if (proc.setAdj == EMPTY_APP_ADJ) {
8043 stats.mEmptyPss += proc.lastPss;
8044 stats.mEmptyCount++;
8045 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8046 stats.mEmptyPss += proc.lastPss;
8047 stats.mEmptyCount++;
8048 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8049 stats.mBackgroundPss += proc.lastPss;
8050 stats.mBackgroundCount++;
8051 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8052 stats.mVisiblePss += proc.lastPss;
8053 stats.mVisibleCount++;
8054 } else {
8055 stats.mForegroundPss += proc.lastPss;
8056 stats.mForegroundCount++;
8057 }
8058 }
8059 }
8060 }
8061
8062 public final void startRunning(String pkg, String cls, String action,
8063 String data) {
8064 synchronized(this) {
8065 if (mStartRunning) {
8066 return;
8067 }
8068 mStartRunning = true;
8069 mTopComponent = pkg != null && cls != null
8070 ? new ComponentName(pkg, cls) : null;
8071 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8072 mTopData = data;
8073 if (!mSystemReady) {
8074 return;
8075 }
8076 }
8077
8078 systemReady();
8079 }
8080
8081 private void retrieveSettings() {
8082 final ContentResolver resolver = mContext.getContentResolver();
8083 String debugApp = Settings.System.getString(
8084 resolver, Settings.System.DEBUG_APP);
8085 boolean waitForDebugger = Settings.System.getInt(
8086 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8087 boolean alwaysFinishActivities = Settings.System.getInt(
8088 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8089
8090 Configuration configuration = new Configuration();
8091 Settings.System.getConfiguration(resolver, configuration);
8092
8093 synchronized (this) {
8094 mDebugApp = mOrigDebugApp = debugApp;
8095 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8096 mAlwaysFinishActivities = alwaysFinishActivities;
8097 // This happens before any activities are started, so we can
8098 // change mConfiguration in-place.
8099 mConfiguration.updateFrom(configuration);
8100 }
8101 }
8102
8103 public boolean testIsSystemReady() {
8104 // no need to synchronize(this) just to read & return the value
8105 return mSystemReady;
8106 }
8107
8108 public void systemReady() {
8109 // In the simulator, startRunning will never have been called, which
8110 // normally sets a few crucial variables. Do it here instead.
8111 if (!Process.supportsProcesses()) {
8112 mStartRunning = true;
8113 mTopAction = Intent.ACTION_MAIN;
8114 }
8115
8116 synchronized(this) {
8117 if (mSystemReady) {
8118 return;
8119 }
8120 mSystemReady = true;
8121 if (!mStartRunning) {
8122 return;
8123 }
8124 }
8125
8126 if (Config.LOGD) Log.d(TAG, "Start running!");
8127 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8128 SystemClock.uptimeMillis());
8129
8130 synchronized(this) {
8131 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8132 ResolveInfo ri = mContext.getPackageManager()
8133 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008134 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008135 CharSequence errorMsg = null;
8136 if (ri != null) {
8137 ActivityInfo ai = ri.activityInfo;
8138 ApplicationInfo app = ai.applicationInfo;
8139 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8140 mTopAction = Intent.ACTION_FACTORY_TEST;
8141 mTopData = null;
8142 mTopComponent = new ComponentName(app.packageName,
8143 ai.name);
8144 } else {
8145 errorMsg = mContext.getResources().getText(
8146 com.android.internal.R.string.factorytest_not_system);
8147 }
8148 } else {
8149 errorMsg = mContext.getResources().getText(
8150 com.android.internal.R.string.factorytest_no_action);
8151 }
8152 if (errorMsg != null) {
8153 mTopAction = null;
8154 mTopData = null;
8155 mTopComponent = null;
8156 Message msg = Message.obtain();
8157 msg.what = SHOW_FACTORY_ERROR_MSG;
8158 msg.getData().putCharSequence("msg", errorMsg);
8159 mHandler.sendMessage(msg);
8160 }
8161 }
8162 }
8163
8164 retrieveSettings();
8165
8166 synchronized (this) {
8167 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8168 try {
8169 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008170 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008171 if (apps != null) {
8172 int N = apps.size();
8173 int i;
8174 for (i=0; i<N; i++) {
8175 ApplicationInfo info
8176 = (ApplicationInfo)apps.get(i);
8177 if (info != null &&
8178 !info.packageName.equals("android")) {
8179 addAppLocked(info);
8180 }
8181 }
8182 }
8183 } catch (RemoteException ex) {
8184 // pm is in same process, this will never happen.
8185 }
8186 }
8187
8188 try {
8189 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8190 Message msg = Message.obtain();
8191 msg.what = SHOW_UID_ERROR_MSG;
8192 mHandler.sendMessage(msg);
8193 }
8194 } catch (RemoteException e) {
8195 }
8196
8197 // Start up initial activity.
8198 mBooting = true;
8199 resumeTopActivityLocked(null);
8200 }
8201 }
8202
8203 boolean makeAppCrashingLocked(ProcessRecord app,
8204 String tag, String shortMsg, String longMsg, byte[] crashData) {
8205 app.crashing = true;
8206 app.crashingReport = generateProcessError(app,
8207 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8208 startAppProblemLocked(app);
8209 app.stopFreezingAllLocked();
8210 return handleAppCrashLocked(app);
8211 }
8212
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008213 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8214 IPackageManager pm = ActivityThread.getPackageManager();
8215 try {
8216 // was an installer package name specified when this app was
8217 // installed?
8218 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8219 if (installerPackageName == null) {
8220 return null;
8221 }
8222
8223 // is there an Activity in this package that handles ACTION_APP_ERROR?
8224 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008225 intent.setPackage(installerPackageName);
8226 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008227 if (info == null || info.activityInfo == null) {
8228 return null;
8229 }
8230
8231 return new ComponentName(installerPackageName, info.activityInfo.name);
8232 } catch (RemoteException e) {
8233 // will return null and no error report will be delivered
8234 }
8235 return null;
8236 }
8237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008238 void makeAppNotRespondingLocked(ProcessRecord app,
8239 String tag, String shortMsg, String longMsg, byte[] crashData) {
8240 app.notResponding = true;
8241 app.notRespondingReport = generateProcessError(app,
8242 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8243 crashData);
8244 startAppProblemLocked(app);
8245 app.stopFreezingAllLocked();
8246 }
8247
8248 /**
8249 * Generate a process error record, suitable for attachment to a ProcessRecord.
8250 *
8251 * @param app The ProcessRecord in which the error occurred.
8252 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8253 * ActivityManager.AppErrorStateInfo
8254 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8255 * @param shortMsg Short message describing the crash.
8256 * @param longMsg Long message describing the crash.
8257 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8258 *
8259 * @return Returns a fully-formed AppErrorStateInfo record.
8260 */
8261 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8262 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8263 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8264
8265 report.condition = condition;
8266 report.processName = app.processName;
8267 report.pid = app.pid;
8268 report.uid = app.info.uid;
8269 report.tag = tag;
8270 report.shortMsg = shortMsg;
8271 report.longMsg = longMsg;
8272 report.crashData = crashData;
8273
8274 return report;
8275 }
8276
8277 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8278 boolean crashed) {
8279 synchronized (this) {
8280 app.crashing = false;
8281 app.crashingReport = null;
8282 app.notResponding = false;
8283 app.notRespondingReport = null;
8284 if (app.anrDialog == fromDialog) {
8285 app.anrDialog = null;
8286 }
8287 if (app.waitDialog == fromDialog) {
8288 app.waitDialog = null;
8289 }
8290 if (app.pid > 0 && app.pid != MY_PID) {
8291 if (crashed) {
8292 handleAppCrashLocked(app);
8293 }
8294 Log.i(ActivityManagerService.TAG, "Killing process "
8295 + app.processName
8296 + " (pid=" + app.pid + ") at user's request");
8297 Process.killProcess(app.pid);
8298 }
8299
8300 }
8301 }
8302
8303 boolean handleAppCrashLocked(ProcessRecord app) {
8304 long now = SystemClock.uptimeMillis();
8305
8306 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8307 app.info.uid);
8308 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8309 // This process loses!
8310 Log.w(TAG, "Process " + app.info.processName
8311 + " has crashed too many times: killing!");
8312 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8313 app.info.processName, app.info.uid);
8314 killServicesLocked(app, false);
8315 for (int i=mHistory.size()-1; i>=0; i--) {
8316 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8317 if (r.app == app) {
8318 if (Config.LOGD) Log.d(
8319 TAG, " Force finishing activity "
8320 + r.intent.getComponent().flattenToShortString());
8321 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8322 }
8323 }
8324 if (!app.persistent) {
8325 // We don't want to start this process again until the user
8326 // explicitly does so... but for persistent process, we really
8327 // need to keep it running. If a persistent process is actually
8328 // repeatedly crashing, then badness for everyone.
8329 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8330 app.info.processName);
8331 mBadProcesses.put(app.info.processName, app.info.uid, now);
8332 app.bad = true;
8333 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8334 app.removed = true;
8335 removeProcessLocked(app, false);
8336 return false;
8337 }
8338 }
8339
8340 // Bump up the crash count of any services currently running in the proc.
8341 if (app.services.size() != 0) {
8342 // Any services running in the application need to be placed
8343 // back in the pending list.
8344 Iterator it = app.services.iterator();
8345 while (it.hasNext()) {
8346 ServiceRecord sr = (ServiceRecord)it.next();
8347 sr.crashCount++;
8348 }
8349 }
8350
8351 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8352 return true;
8353 }
8354
8355 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008356 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008357 skipCurrentReceiverLocked(app);
8358 }
8359
8360 void skipCurrentReceiverLocked(ProcessRecord app) {
8361 boolean reschedule = false;
8362 BroadcastRecord r = app.curReceiver;
8363 if (r != null) {
8364 // The current broadcast is waiting for this app's receiver
8365 // to be finished. Looks like that's not going to happen, so
8366 // let the broadcast continue.
8367 logBroadcastReceiverDiscard(r);
8368 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8369 r.resultExtras, r.resultAbort, true);
8370 reschedule = true;
8371 }
8372 r = mPendingBroadcast;
8373 if (r != null && r.curApp == app) {
8374 if (DEBUG_BROADCAST) Log.v(TAG,
8375 "skip & discard pending app " + r);
8376 logBroadcastReceiverDiscard(r);
8377 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8378 r.resultExtras, r.resultAbort, true);
8379 reschedule = true;
8380 }
8381 if (reschedule) {
8382 scheduleBroadcastsLocked();
8383 }
8384 }
8385
8386 public int handleApplicationError(IBinder app, int flags,
8387 String tag, String shortMsg, String longMsg, byte[] crashData) {
8388 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008389 ProcessRecord r = null;
8390 synchronized (this) {
8391 if (app != null) {
8392 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8393 final int NA = apps.size();
8394 for (int ia=0; ia<NA; ia++) {
8395 ProcessRecord p = apps.valueAt(ia);
8396 if (p.thread != null && p.thread.asBinder() == app) {
8397 r = p;
8398 break;
8399 }
8400 }
8401 }
8402 }
8403
8404 if (r != null) {
8405 // The application has crashed. Send the SIGQUIT to the process so
8406 // that it can dump its state.
8407 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8408 //Log.i(TAG, "Current system threads:");
8409 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8410 }
8411
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008412 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 try {
8414 String name = r != null ? r.processName : null;
8415 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008416 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008417 shortMsg, longMsg, crashData)) {
8418 Log.w(TAG, "Force-killing crashed app " + name
8419 + " at watcher's request");
8420 Process.killProcess(pid);
8421 return 0;
8422 }
8423 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008424 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008425 }
8426 }
8427
8428 final long origId = Binder.clearCallingIdentity();
8429
8430 // If this process is running instrumentation, finish it.
8431 if (r != null && r.instrumentationClass != null) {
8432 Log.w(TAG, "Error in app " + r.processName
8433 + " running instrumentation " + r.instrumentationClass + ":");
8434 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8435 if (longMsg != null) Log.w(TAG, " " + longMsg);
8436 Bundle info = new Bundle();
8437 info.putString("shortMsg", shortMsg);
8438 info.putString("longMsg", longMsg);
8439 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8440 Binder.restoreCallingIdentity(origId);
8441 return 0;
8442 }
8443
8444 if (r != null) {
8445 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8446 return 0;
8447 }
8448 } else {
8449 Log.w(TAG, "Some application object " + app + " tag " + tag
8450 + " has crashed, but I don't know who it is.");
8451 Log.w(TAG, "ShortMsg:" + shortMsg);
8452 Log.w(TAG, "LongMsg:" + longMsg);
8453 Binder.restoreCallingIdentity(origId);
8454 return 0;
8455 }
8456
8457 Message msg = Message.obtain();
8458 msg.what = SHOW_ERROR_MSG;
8459 HashMap data = new HashMap();
8460 data.put("result", result);
8461 data.put("app", r);
8462 data.put("flags", flags);
8463 data.put("shortMsg", shortMsg);
8464 data.put("longMsg", longMsg);
8465 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8466 // For system processes, submit crash data to the server.
8467 data.put("crashData", crashData);
8468 }
8469 msg.obj = data;
8470 mHandler.sendMessage(msg);
8471
8472 Binder.restoreCallingIdentity(origId);
8473 }
8474
8475 int res = result.get();
8476
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008477 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008478 synchronized (this) {
8479 if (r != null) {
8480 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8481 SystemClock.uptimeMillis());
8482 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008483 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8484 appErrorIntent = createAppErrorIntentLocked(r);
8485 res = AppErrorDialog.FORCE_QUIT;
8486 }
8487 }
8488
8489 if (appErrorIntent != null) {
8490 try {
8491 mContext.startActivity(appErrorIntent);
8492 } catch (ActivityNotFoundException e) {
8493 Log.w(TAG, "bug report receiver dissappeared", e);
8494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008495 }
8496
8497 return res;
8498 }
8499
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008500 Intent createAppErrorIntentLocked(ProcessRecord r) {
8501 ApplicationErrorReport report = createAppErrorReportLocked(r);
8502 if (report == null) {
8503 return null;
8504 }
8505 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8506 result.setComponent(r.errorReportReceiver);
8507 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8508 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8509 return result;
8510 }
8511
8512 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8513 if (r.errorReportReceiver == null) {
8514 return null;
8515 }
8516
8517 if (!r.crashing && !r.notResponding) {
8518 return null;
8519 }
8520
8521 try {
8522 ApplicationErrorReport report = new ApplicationErrorReport();
8523 report.packageName = r.info.packageName;
8524 report.installerPackageName = r.errorReportReceiver.getPackageName();
8525 report.processName = r.processName;
8526
8527 if (r.crashing) {
8528 report.type = ApplicationErrorReport.TYPE_CRASH;
8529 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8530
8531 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8532 r.crashingReport.crashData);
8533 DataInputStream dataStream = new DataInputStream(byteStream);
8534 CrashData crashData = new CrashData(dataStream);
8535 ThrowableData throwData = crashData.getThrowableData();
8536
8537 report.time = crashData.getTime();
8538 report.crashInfo.stackTrace = throwData.toString();
8539
Jacek Surazskif829a782009-06-11 22:47:02 +02008540 // Extract the source of the exception, useful for report
8541 // clustering. Also extract the "deepest" non-null exception
8542 // message.
8543 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008544 while (throwData.getCause() != null) {
8545 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008546 String msg = throwData.getMessage();
8547 if (msg != null && msg.length() > 0) {
8548 exceptionMessage = msg;
8549 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008550 }
8551 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008552 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008553 report.crashInfo.exceptionClassName = throwData.getType();
8554 report.crashInfo.throwFileName = trace.getFileName();
8555 report.crashInfo.throwClassName = trace.getClassName();
8556 report.crashInfo.throwMethodName = trace.getMethodName();
8557 } else if (r.notResponding) {
8558 report.type = ApplicationErrorReport.TYPE_ANR;
8559 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8560
8561 report.anrInfo.activity = r.notRespondingReport.tag;
8562 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8563 report.anrInfo.info = r.notRespondingReport.longMsg;
8564 }
8565
8566 return report;
8567 } catch (IOException e) {
8568 // we don't send it
8569 }
8570
8571 return null;
8572 }
8573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008574 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8575 // assume our apps are happy - lazy create the list
8576 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8577
8578 synchronized (this) {
8579
8580 // iterate across all processes
8581 final int N = mLRUProcesses.size();
8582 for (int i = 0; i < N; i++) {
8583 ProcessRecord app = mLRUProcesses.get(i);
8584 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8585 // This one's in trouble, so we'll generate a report for it
8586 // crashes are higher priority (in case there's a crash *and* an anr)
8587 ActivityManager.ProcessErrorStateInfo report = null;
8588 if (app.crashing) {
8589 report = app.crashingReport;
8590 } else if (app.notResponding) {
8591 report = app.notRespondingReport;
8592 }
8593
8594 if (report != null) {
8595 if (errList == null) {
8596 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8597 }
8598 errList.add(report);
8599 } else {
8600 Log.w(TAG, "Missing app error report, app = " + app.processName +
8601 " crashing = " + app.crashing +
8602 " notResponding = " + app.notResponding);
8603 }
8604 }
8605 }
8606 }
8607
8608 return errList;
8609 }
8610
8611 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8612 // Lazy instantiation of list
8613 List<ActivityManager.RunningAppProcessInfo> runList = null;
8614 synchronized (this) {
8615 // Iterate across all processes
8616 final int N = mLRUProcesses.size();
8617 for (int i = 0; i < N; i++) {
8618 ProcessRecord app = mLRUProcesses.get(i);
8619 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8620 // Generate process state info for running application
8621 ActivityManager.RunningAppProcessInfo currApp =
8622 new ActivityManager.RunningAppProcessInfo(app.processName,
8623 app.pid, app.getPackageList());
8624 int adj = app.curAdj;
8625 if (adj >= CONTENT_PROVIDER_ADJ) {
8626 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8627 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8628 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008629 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8630 } else if (adj >= HOME_APP_ADJ) {
8631 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8632 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008633 } else if (adj >= SECONDARY_SERVER_ADJ) {
8634 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8635 } else if (adj >= VISIBLE_APP_ADJ) {
8636 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8637 } else {
8638 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8639 }
8640 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8641 // + " lru=" + currApp.lru);
8642 if (runList == null) {
8643 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8644 }
8645 runList.add(currApp);
8646 }
8647 }
8648 }
8649 return runList;
8650 }
8651
8652 @Override
8653 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8654 synchronized (this) {
8655 if (checkCallingPermission(android.Manifest.permission.DUMP)
8656 != PackageManager.PERMISSION_GRANTED) {
8657 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8658 + Binder.getCallingPid()
8659 + ", uid=" + Binder.getCallingUid()
8660 + " without permission "
8661 + android.Manifest.permission.DUMP);
8662 return;
8663 }
8664 if (args.length != 0 && "service".equals(args[0])) {
8665 dumpService(fd, pw, args);
8666 return;
8667 }
8668 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008669 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008670 pw.println(" ");
8671 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008672 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008673 if (mWaitingVisibleActivities.size() > 0) {
8674 pw.println(" ");
8675 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008676 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008677 }
8678 if (mStoppingActivities.size() > 0) {
8679 pw.println(" ");
8680 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008681 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008682 }
8683 if (mFinishingActivities.size() > 0) {
8684 pw.println(" ");
8685 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008686 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008687 }
8688
8689 pw.println(" ");
8690 pw.println(" mPausingActivity: " + mPausingActivity);
8691 pw.println(" mResumedActivity: " + mResumedActivity);
8692 pw.println(" mFocusedActivity: " + mFocusedActivity);
8693 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8694
8695 if (mRecentTasks.size() > 0) {
8696 pw.println(" ");
8697 pw.println("Recent tasks in Current Activity Manager State:");
8698
8699 final int N = mRecentTasks.size();
8700 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008701 TaskRecord tr = mRecentTasks.get(i);
8702 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8703 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008704 mRecentTasks.get(i).dump(pw, " ");
8705 }
8706 }
8707
8708 pw.println(" ");
8709 pw.println(" mCurTask: " + mCurTask);
8710
8711 pw.println(" ");
8712 pw.println("Processes in Current Activity Manager State:");
8713
8714 boolean needSep = false;
8715 int numPers = 0;
8716
8717 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8718 final int NA = procs.size();
8719 for (int ia=0; ia<NA; ia++) {
8720 if (!needSep) {
8721 pw.println(" All known processes:");
8722 needSep = true;
8723 }
8724 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008725 pw.print(r.persistent ? " *PERS*" : " *APP*");
8726 pw.print(" UID "); pw.print(procs.keyAt(ia));
8727 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008728 r.dump(pw, " ");
8729 if (r.persistent) {
8730 numPers++;
8731 }
8732 }
8733 }
8734
8735 if (mLRUProcesses.size() > 0) {
8736 if (needSep) pw.println(" ");
8737 needSep = true;
8738 pw.println(" Running processes (most recent first):");
8739 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008740 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008741 needSep = true;
8742 }
8743
8744 synchronized (mPidsSelfLocked) {
8745 if (mPidsSelfLocked.size() > 0) {
8746 if (needSep) pw.println(" ");
8747 needSep = true;
8748 pw.println(" PID mappings:");
8749 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008750 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8751 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008752 }
8753 }
8754 }
8755
8756 if (mForegroundProcesses.size() > 0) {
8757 if (needSep) pw.println(" ");
8758 needSep = true;
8759 pw.println(" Foreground Processes:");
8760 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008761 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8762 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008763 }
8764 }
8765
8766 if (mPersistentStartingProcesses.size() > 0) {
8767 if (needSep) pw.println(" ");
8768 needSep = true;
8769 pw.println(" Persisent processes that are starting:");
8770 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008771 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 }
8773
8774 if (mStartingProcesses.size() > 0) {
8775 if (needSep) pw.println(" ");
8776 needSep = true;
8777 pw.println(" Processes that are starting:");
8778 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008779 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008780 }
8781
8782 if (mRemovedProcesses.size() > 0) {
8783 if (needSep) pw.println(" ");
8784 needSep = true;
8785 pw.println(" Processes that are being removed:");
8786 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008787 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008788 }
8789
8790 if (mProcessesOnHold.size() > 0) {
8791 if (needSep) pw.println(" ");
8792 needSep = true;
8793 pw.println(" Processes that are on old until the system is ready:");
8794 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008795 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008796 }
8797
8798 if (mProcessCrashTimes.getMap().size() > 0) {
8799 if (needSep) pw.println(" ");
8800 needSep = true;
8801 pw.println(" Time since processes crashed:");
8802 long now = SystemClock.uptimeMillis();
8803 for (Map.Entry<String, SparseArray<Long>> procs
8804 : mProcessCrashTimes.getMap().entrySet()) {
8805 SparseArray<Long> uids = procs.getValue();
8806 final int N = uids.size();
8807 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008808 pw.print(" Process "); pw.print(procs.getKey());
8809 pw.print(" uid "); pw.print(uids.keyAt(i));
8810 pw.print(": last crashed ");
8811 pw.print((now-uids.valueAt(i)));
8812 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008813 }
8814 }
8815 }
8816
8817 if (mBadProcesses.getMap().size() > 0) {
8818 if (needSep) pw.println(" ");
8819 needSep = true;
8820 pw.println(" Bad processes:");
8821 for (Map.Entry<String, SparseArray<Long>> procs
8822 : mBadProcesses.getMap().entrySet()) {
8823 SparseArray<Long> uids = procs.getValue();
8824 final int N = uids.size();
8825 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008826 pw.print(" Bad process "); pw.print(procs.getKey());
8827 pw.print(" uid "); pw.print(uids.keyAt(i));
8828 pw.print(": crashed at time ");
8829 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008830 }
8831 }
8832 }
8833
8834 pw.println(" ");
8835 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008836 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008837 pw.println(" mConfiguration: " + mConfiguration);
8838 pw.println(" mStartRunning=" + mStartRunning
8839 + " mSystemReady=" + mSystemReady
8840 + " mBooting=" + mBooting
8841 + " mBooted=" + mBooted
8842 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008843 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008844 pw.println(" mGoingToSleep=" + mGoingToSleep);
8845 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8846 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8847 + " mDebugTransient=" + mDebugTransient
8848 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8849 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008850 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008851 }
8852 }
8853
8854 /**
8855 * There are three ways to call this:
8856 * - no service specified: dump all the services
8857 * - a flattened component name that matched an existing service was specified as the
8858 * first arg: dump that one service
8859 * - the first arg isn't the flattened component name of an existing service:
8860 * dump all services whose component contains the first arg as a substring
8861 */
8862 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8863 String[] newArgs;
8864 String componentNameString;
8865 ServiceRecord r;
8866 if (args.length == 1) {
8867 componentNameString = null;
8868 newArgs = EMPTY_STRING_ARRAY;
8869 r = null;
8870 } else {
8871 componentNameString = args[1];
8872 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8873 r = componentName != null ? mServices.get(componentName) : null;
8874 newArgs = new String[args.length - 2];
8875 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8876 }
8877
8878 if (r != null) {
8879 dumpService(fd, pw, r, newArgs);
8880 } else {
8881 for (ServiceRecord r1 : mServices.values()) {
8882 if (componentNameString == null
8883 || r1.name.flattenToString().contains(componentNameString)) {
8884 dumpService(fd, pw, r1, newArgs);
8885 }
8886 }
8887 }
8888 }
8889
8890 /**
8891 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8892 * there is a thread associated with the service.
8893 */
8894 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8895 pw.println(" Service " + r.name.flattenToString());
8896 if (r.app != null && r.app.thread != null) {
8897 try {
8898 // flush anything that is already in the PrintWriter since the thread is going
8899 // to write to the file descriptor directly
8900 pw.flush();
8901 r.app.thread.dumpService(fd, r, args);
8902 pw.print("\n");
8903 } catch (RemoteException e) {
8904 pw.println("got a RemoteException while dumping the service");
8905 }
8906 }
8907 }
8908
8909 void dumpBroadcasts(PrintWriter pw) {
8910 synchronized (this) {
8911 if (checkCallingPermission(android.Manifest.permission.DUMP)
8912 != PackageManager.PERMISSION_GRANTED) {
8913 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8914 + Binder.getCallingPid()
8915 + ", uid=" + Binder.getCallingUid()
8916 + " without permission "
8917 + android.Manifest.permission.DUMP);
8918 return;
8919 }
8920 pw.println("Broadcasts in Current Activity Manager State:");
8921
8922 if (mRegisteredReceivers.size() > 0) {
8923 pw.println(" ");
8924 pw.println(" Registered Receivers:");
8925 Iterator it = mRegisteredReceivers.values().iterator();
8926 while (it.hasNext()) {
8927 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008928 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008929 r.dump(pw, " ");
8930 }
8931 }
8932
8933 pw.println(" ");
8934 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008935 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008936
8937 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8938 || mPendingBroadcast != null) {
8939 if (mParallelBroadcasts.size() > 0) {
8940 pw.println(" ");
8941 pw.println(" Active broadcasts:");
8942 }
8943 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8944 pw.println(" Broadcast #" + i + ":");
8945 mParallelBroadcasts.get(i).dump(pw, " ");
8946 }
8947 if (mOrderedBroadcasts.size() > 0) {
8948 pw.println(" ");
8949 pw.println(" Active serialized broadcasts:");
8950 }
8951 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8952 pw.println(" Serialized Broadcast #" + i + ":");
8953 mOrderedBroadcasts.get(i).dump(pw, " ");
8954 }
8955 pw.println(" ");
8956 pw.println(" Pending broadcast:");
8957 if (mPendingBroadcast != null) {
8958 mPendingBroadcast.dump(pw, " ");
8959 } else {
8960 pw.println(" (null)");
8961 }
8962 }
8963
8964 pw.println(" ");
8965 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8966 if (mStickyBroadcasts != null) {
8967 pw.println(" ");
8968 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008969 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 for (Map.Entry<String, ArrayList<Intent>> ent
8971 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008972 pw.print(" * Sticky action "); pw.print(ent.getKey());
8973 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008974 ArrayList<Intent> intents = ent.getValue();
8975 final int N = intents.size();
8976 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008977 sb.setLength(0);
8978 sb.append(" Intent: ");
8979 intents.get(i).toShortString(sb, true, false);
8980 pw.println(sb.toString());
8981 Bundle bundle = intents.get(i).getExtras();
8982 if (bundle != null) {
8983 pw.print(" ");
8984 pw.println(bundle.toString());
8985 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008986 }
8987 }
8988 }
8989
8990 pw.println(" ");
8991 pw.println(" mHandler:");
8992 mHandler.dump(new PrintWriterPrinter(pw), " ");
8993 }
8994 }
8995
8996 void dumpServices(PrintWriter pw) {
8997 synchronized (this) {
8998 if (checkCallingPermission(android.Manifest.permission.DUMP)
8999 != PackageManager.PERMISSION_GRANTED) {
9000 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9001 + Binder.getCallingPid()
9002 + ", uid=" + Binder.getCallingUid()
9003 + " without permission "
9004 + android.Manifest.permission.DUMP);
9005 return;
9006 }
9007 pw.println("Services in Current Activity Manager State:");
9008
9009 boolean needSep = false;
9010
9011 if (mServices.size() > 0) {
9012 pw.println(" Active services:");
9013 Iterator<ServiceRecord> it = mServices.values().iterator();
9014 while (it.hasNext()) {
9015 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009016 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009017 r.dump(pw, " ");
9018 }
9019 needSep = true;
9020 }
9021
9022 if (mPendingServices.size() > 0) {
9023 if (needSep) pw.println(" ");
9024 pw.println(" Pending services:");
9025 for (int i=0; i<mPendingServices.size(); i++) {
9026 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009027 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009028 r.dump(pw, " ");
9029 }
9030 needSep = true;
9031 }
9032
9033 if (mRestartingServices.size() > 0) {
9034 if (needSep) pw.println(" ");
9035 pw.println(" Restarting services:");
9036 for (int i=0; i<mRestartingServices.size(); i++) {
9037 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009038 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009039 r.dump(pw, " ");
9040 }
9041 needSep = true;
9042 }
9043
9044 if (mStoppingServices.size() > 0) {
9045 if (needSep) pw.println(" ");
9046 pw.println(" Stopping services:");
9047 for (int i=0; i<mStoppingServices.size(); i++) {
9048 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009049 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009050 r.dump(pw, " ");
9051 }
9052 needSep = true;
9053 }
9054
9055 if (mServiceConnections.size() > 0) {
9056 if (needSep) pw.println(" ");
9057 pw.println(" Connection bindings to services:");
9058 Iterator<ConnectionRecord> it
9059 = mServiceConnections.values().iterator();
9060 while (it.hasNext()) {
9061 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009062 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009063 r.dump(pw, " ");
9064 }
9065 }
9066 }
9067 }
9068
9069 void dumpProviders(PrintWriter pw) {
9070 synchronized (this) {
9071 if (checkCallingPermission(android.Manifest.permission.DUMP)
9072 != PackageManager.PERMISSION_GRANTED) {
9073 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9074 + Binder.getCallingPid()
9075 + ", uid=" + Binder.getCallingUid()
9076 + " without permission "
9077 + android.Manifest.permission.DUMP);
9078 return;
9079 }
9080
9081 pw.println("Content Providers in Current Activity Manager State:");
9082
9083 boolean needSep = false;
9084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009085 if (mProvidersByClass.size() > 0) {
9086 if (needSep) pw.println(" ");
9087 pw.println(" Published content providers (by class):");
9088 Iterator it = mProvidersByClass.entrySet().iterator();
9089 while (it.hasNext()) {
9090 Map.Entry e = (Map.Entry)it.next();
9091 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009092 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009093 r.dump(pw, " ");
9094 }
9095 needSep = true;
9096 }
9097
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009098 if (mProvidersByName.size() > 0) {
9099 pw.println(" ");
9100 pw.println(" Authority to provider mappings:");
9101 Iterator it = mProvidersByName.entrySet().iterator();
9102 while (it.hasNext()) {
9103 Map.Entry e = (Map.Entry)it.next();
9104 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9105 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9106 pw.println(r);
9107 }
9108 needSep = true;
9109 }
9110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009111 if (mLaunchingProviders.size() > 0) {
9112 if (needSep) pw.println(" ");
9113 pw.println(" Launching content providers:");
9114 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009115 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9116 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009117 }
9118 needSep = true;
9119 }
9120
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009121 if (mGrantedUriPermissions.size() > 0) {
9122 pw.println();
9123 pw.println("Granted Uri Permissions:");
9124 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9125 int uid = mGrantedUriPermissions.keyAt(i);
9126 HashMap<Uri, UriPermission> perms
9127 = mGrantedUriPermissions.valueAt(i);
9128 pw.print(" * UID "); pw.print(uid);
9129 pw.println(" holds:");
9130 for (UriPermission perm : perms.values()) {
9131 pw.print(" "); pw.println(perm);
9132 perm.dump(pw, " ");
9133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009134 }
9135 }
9136 }
9137 }
9138
9139 void dumpSenders(PrintWriter pw) {
9140 synchronized (this) {
9141 if (checkCallingPermission(android.Manifest.permission.DUMP)
9142 != PackageManager.PERMISSION_GRANTED) {
9143 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9144 + Binder.getCallingPid()
9145 + ", uid=" + Binder.getCallingUid()
9146 + " without permission "
9147 + android.Manifest.permission.DUMP);
9148 return;
9149 }
9150
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009151 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009152
9153 if (this.mIntentSenderRecords.size() > 0) {
9154 Iterator<WeakReference<PendingIntentRecord>> it
9155 = mIntentSenderRecords.values().iterator();
9156 while (it.hasNext()) {
9157 WeakReference<PendingIntentRecord> ref = it.next();
9158 PendingIntentRecord rec = ref != null ? ref.get(): null;
9159 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009160 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009161 rec.dump(pw, " ");
9162 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009163 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009164 }
9165 }
9166 }
9167 }
9168 }
9169
9170 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009171 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009172 TaskRecord lastTask = null;
9173 for (int i=list.size()-1; i>=0; i--) {
9174 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009175 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009176 if (lastTask != r.task) {
9177 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009178 pw.print(prefix);
9179 pw.print(full ? "* " : " ");
9180 pw.println(lastTask);
9181 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009182 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009184 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009185 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9186 pw.print(" #"); pw.print(i); pw.print(": ");
9187 pw.println(r);
9188 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009189 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191 }
9192 }
9193
9194 private static final int dumpProcessList(PrintWriter pw, List list,
9195 String prefix, String normalLabel, String persistentLabel,
9196 boolean inclOomAdj) {
9197 int numPers = 0;
9198 for (int i=list.size()-1; i>=0; i--) {
9199 ProcessRecord r = (ProcessRecord)list.get(i);
9200 if (false) {
9201 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9202 + " #" + i + ":");
9203 r.dump(pw, prefix + " ");
9204 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009205 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009206 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009207 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9208 if (r.adjSource != null || r.adjTarget != null) {
9209 pw.println(prefix + " " + r.adjTarget
9210 + " used by " + r.adjSource);
9211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009212 } else {
9213 pw.println(String.format("%s%s #%2d: %s",
9214 prefix, (r.persistent ? persistentLabel : normalLabel),
9215 i, r.toString()));
9216 }
9217 if (r.persistent) {
9218 numPers++;
9219 }
9220 }
9221 return numPers;
9222 }
9223
9224 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9225 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009226 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009227 long uptime = SystemClock.uptimeMillis();
9228 long realtime = SystemClock.elapsedRealtime();
9229
9230 if (isCheckinRequest) {
9231 // short checkin version
9232 pw.println(uptime + "," + realtime);
9233 pw.flush();
9234 } else {
9235 pw.println("Applications Memory Usage (kB):");
9236 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9237 }
9238 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9239 ProcessRecord r = (ProcessRecord)list.get(i);
9240 if (r.thread != null) {
9241 if (!isCheckinRequest) {
9242 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9243 pw.flush();
9244 }
9245 try {
9246 r.thread.asBinder().dump(fd, args);
9247 } catch (RemoteException e) {
9248 if (!isCheckinRequest) {
9249 pw.println("Got RemoteException!");
9250 pw.flush();
9251 }
9252 }
9253 }
9254 }
9255 }
9256
9257 /**
9258 * Searches array of arguments for the specified string
9259 * @param args array of argument strings
9260 * @param value value to search for
9261 * @return true if the value is contained in the array
9262 */
9263 private static boolean scanArgs(String[] args, String value) {
9264 if (args != null) {
9265 for (String arg : args) {
9266 if (value.equals(arg)) {
9267 return true;
9268 }
9269 }
9270 }
9271 return false;
9272 }
9273
Dianne Hackborn75b03852009-06-12 15:43:26 -07009274 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009275 int count = mHistory.size();
9276
9277 // convert the token to an entry in the history.
9278 HistoryRecord r = null;
9279 int index = -1;
9280 for (int i=count-1; i>=0; i--) {
9281 Object o = mHistory.get(i);
9282 if (o == token) {
9283 r = (HistoryRecord)o;
9284 index = i;
9285 break;
9286 }
9287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009288
9289 return index;
9290 }
9291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009292 private final void killServicesLocked(ProcessRecord app,
9293 boolean allowRestart) {
9294 // Report disconnected services.
9295 if (false) {
9296 // XXX we are letting the client link to the service for
9297 // death notifications.
9298 if (app.services.size() > 0) {
9299 Iterator it = app.services.iterator();
9300 while (it.hasNext()) {
9301 ServiceRecord r = (ServiceRecord)it.next();
9302 if (r.connections.size() > 0) {
9303 Iterator<ConnectionRecord> jt
9304 = r.connections.values().iterator();
9305 while (jt.hasNext()) {
9306 ConnectionRecord c = jt.next();
9307 if (c.binding.client != app) {
9308 try {
9309 //c.conn.connected(r.className, null);
9310 } catch (Exception e) {
9311 // todo: this should be asynchronous!
9312 Log.w(TAG, "Exception thrown disconnected servce "
9313 + r.shortName
9314 + " from app " + app.processName, e);
9315 }
9316 }
9317 }
9318 }
9319 }
9320 }
9321 }
9322
9323 // Clean up any connections this application has to other services.
9324 if (app.connections.size() > 0) {
9325 Iterator<ConnectionRecord> it = app.connections.iterator();
9326 while (it.hasNext()) {
9327 ConnectionRecord r = it.next();
9328 removeConnectionLocked(r, app, null);
9329 }
9330 }
9331 app.connections.clear();
9332
9333 if (app.services.size() != 0) {
9334 // Any services running in the application need to be placed
9335 // back in the pending list.
9336 Iterator it = app.services.iterator();
9337 while (it.hasNext()) {
9338 ServiceRecord sr = (ServiceRecord)it.next();
9339 synchronized (sr.stats.getBatteryStats()) {
9340 sr.stats.stopLaunchedLocked();
9341 }
9342 sr.app = null;
9343 sr.executeNesting = 0;
9344 mStoppingServices.remove(sr);
9345 if (sr.bindings.size() > 0) {
9346 Iterator<IntentBindRecord> bindings
9347 = sr.bindings.values().iterator();
9348 while (bindings.hasNext()) {
9349 IntentBindRecord b = bindings.next();
9350 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9351 + ": shouldUnbind=" + b.hasBound);
9352 b.binder = null;
9353 b.requested = b.received = b.hasBound = false;
9354 }
9355 }
9356
9357 if (sr.crashCount >= 2) {
9358 Log.w(TAG, "Service crashed " + sr.crashCount
9359 + " times, stopping: " + sr);
9360 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9361 sr.crashCount, sr.shortName, app.pid);
9362 bringDownServiceLocked(sr, true);
9363 } else if (!allowRestart) {
9364 bringDownServiceLocked(sr, true);
9365 } else {
9366 scheduleServiceRestartLocked(sr);
9367 }
9368 }
9369
9370 if (!allowRestart) {
9371 app.services.clear();
9372 }
9373 }
9374
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009375 // Make sure we have no more records on the stopping list.
9376 int i = mStoppingServices.size();
9377 while (i > 0) {
9378 i--;
9379 ServiceRecord sr = mStoppingServices.get(i);
9380 if (sr.app == app) {
9381 mStoppingServices.remove(i);
9382 }
9383 }
9384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009385 app.executingServices.clear();
9386 }
9387
9388 private final void removeDyingProviderLocked(ProcessRecord proc,
9389 ContentProviderRecord cpr) {
9390 synchronized (cpr) {
9391 cpr.launchingApp = null;
9392 cpr.notifyAll();
9393 }
9394
9395 mProvidersByClass.remove(cpr.info.name);
9396 String names[] = cpr.info.authority.split(";");
9397 for (int j = 0; j < names.length; j++) {
9398 mProvidersByName.remove(names[j]);
9399 }
9400
9401 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9402 while (cit.hasNext()) {
9403 ProcessRecord capp = cit.next();
9404 if (!capp.persistent && capp.thread != null
9405 && capp.pid != 0
9406 && capp.pid != MY_PID) {
9407 Log.i(TAG, "Killing app " + capp.processName
9408 + " (pid " + capp.pid
9409 + ") because provider " + cpr.info.name
9410 + " is in dying process " + proc.processName);
9411 Process.killProcess(capp.pid);
9412 }
9413 }
9414
9415 mLaunchingProviders.remove(cpr);
9416 }
9417
9418 /**
9419 * Main code for cleaning up a process when it has gone away. This is
9420 * called both as a result of the process dying, or directly when stopping
9421 * a process when running in single process mode.
9422 */
9423 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9424 boolean restarting, int index) {
9425 if (index >= 0) {
9426 mLRUProcesses.remove(index);
9427 }
9428
9429 // Dismiss any open dialogs.
9430 if (app.crashDialog != null) {
9431 app.crashDialog.dismiss();
9432 app.crashDialog = null;
9433 }
9434 if (app.anrDialog != null) {
9435 app.anrDialog.dismiss();
9436 app.anrDialog = null;
9437 }
9438 if (app.waitDialog != null) {
9439 app.waitDialog.dismiss();
9440 app.waitDialog = null;
9441 }
9442
9443 app.crashing = false;
9444 app.notResponding = false;
9445
9446 app.resetPackageList();
9447 app.thread = null;
9448 app.forcingToForeground = null;
9449 app.foregroundServices = false;
9450
9451 killServicesLocked(app, true);
9452
9453 boolean restart = false;
9454
9455 int NL = mLaunchingProviders.size();
9456
9457 // Remove published content providers.
9458 if (!app.pubProviders.isEmpty()) {
9459 Iterator it = app.pubProviders.values().iterator();
9460 while (it.hasNext()) {
9461 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9462 cpr.provider = null;
9463 cpr.app = null;
9464
9465 // See if someone is waiting for this provider... in which
9466 // case we don't remove it, but just let it restart.
9467 int i = 0;
9468 if (!app.bad) {
9469 for (; i<NL; i++) {
9470 if (mLaunchingProviders.get(i) == cpr) {
9471 restart = true;
9472 break;
9473 }
9474 }
9475 } else {
9476 i = NL;
9477 }
9478
9479 if (i >= NL) {
9480 removeDyingProviderLocked(app, cpr);
9481 NL = mLaunchingProviders.size();
9482 }
9483 }
9484 app.pubProviders.clear();
9485 }
9486
9487 // Look through the content providers we are waiting to have launched,
9488 // and if any run in this process then either schedule a restart of
9489 // the process or kill the client waiting for it if this process has
9490 // gone bad.
9491 for (int i=0; i<NL; i++) {
9492 ContentProviderRecord cpr = (ContentProviderRecord)
9493 mLaunchingProviders.get(i);
9494 if (cpr.launchingApp == app) {
9495 if (!app.bad) {
9496 restart = true;
9497 } else {
9498 removeDyingProviderLocked(app, cpr);
9499 NL = mLaunchingProviders.size();
9500 }
9501 }
9502 }
9503
9504 // Unregister from connected content providers.
9505 if (!app.conProviders.isEmpty()) {
9506 Iterator it = app.conProviders.iterator();
9507 while (it.hasNext()) {
9508 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9509 cpr.clients.remove(app);
9510 }
9511 app.conProviders.clear();
9512 }
9513
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009514 // At this point there may be remaining entries in mLaunchingProviders
9515 // where we were the only one waiting, so they are no longer of use.
9516 // Look for these and clean up if found.
9517 // XXX Commented out for now. Trying to figure out a way to reproduce
9518 // the actual situation to identify what is actually going on.
9519 if (false) {
9520 for (int i=0; i<NL; i++) {
9521 ContentProviderRecord cpr = (ContentProviderRecord)
9522 mLaunchingProviders.get(i);
9523 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9524 synchronized (cpr) {
9525 cpr.launchingApp = null;
9526 cpr.notifyAll();
9527 }
9528 }
9529 }
9530 }
9531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009532 skipCurrentReceiverLocked(app);
9533
9534 // Unregister any receivers.
9535 if (app.receivers.size() > 0) {
9536 Iterator<ReceiverList> it = app.receivers.iterator();
9537 while (it.hasNext()) {
9538 removeReceiverLocked(it.next());
9539 }
9540 app.receivers.clear();
9541 }
9542
Christopher Tate181fafa2009-05-14 11:12:14 -07009543 // If the app is undergoing backup, tell the backup manager about it
9544 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9545 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9546 try {
9547 IBackupManager bm = IBackupManager.Stub.asInterface(
9548 ServiceManager.getService(Context.BACKUP_SERVICE));
9549 bm.agentDisconnected(app.info.packageName);
9550 } catch (RemoteException e) {
9551 // can't happen; backup manager is local
9552 }
9553 }
9554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009555 // If the caller is restarting this app, then leave it in its
9556 // current lists and let the caller take care of it.
9557 if (restarting) {
9558 return;
9559 }
9560
9561 if (!app.persistent) {
9562 if (DEBUG_PROCESSES) Log.v(TAG,
9563 "Removing non-persistent process during cleanup: " + app);
9564 mProcessNames.remove(app.processName, app.info.uid);
9565 } else if (!app.removed) {
9566 // This app is persistent, so we need to keep its record around.
9567 // If it is not already on the pending app list, add it there
9568 // and start a new process for it.
9569 app.thread = null;
9570 app.forcingToForeground = null;
9571 app.foregroundServices = false;
9572 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9573 mPersistentStartingProcesses.add(app);
9574 restart = true;
9575 }
9576 }
9577 mProcessesOnHold.remove(app);
9578
The Android Open Source Project4df24232009-03-05 14:34:35 -08009579 if (app == mHomeProcess) {
9580 mHomeProcess = null;
9581 }
9582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009583 if (restart) {
9584 // We have components that still need to be running in the
9585 // process, so re-launch it.
9586 mProcessNames.put(app.processName, app.info.uid, app);
9587 startProcessLocked(app, "restart", app.processName);
9588 } else if (app.pid > 0 && app.pid != MY_PID) {
9589 // Goodbye!
9590 synchronized (mPidsSelfLocked) {
9591 mPidsSelfLocked.remove(app.pid);
9592 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9593 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009594 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009595 }
9596 }
9597
9598 // =========================================================
9599 // SERVICES
9600 // =========================================================
9601
9602 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9603 ActivityManager.RunningServiceInfo info =
9604 new ActivityManager.RunningServiceInfo();
9605 info.service = r.name;
9606 if (r.app != null) {
9607 info.pid = r.app.pid;
9608 }
9609 info.process = r.processName;
9610 info.foreground = r.isForeground;
9611 info.activeSince = r.createTime;
9612 info.started = r.startRequested;
9613 info.clientCount = r.connections.size();
9614 info.crashCount = r.crashCount;
9615 info.lastActivityTime = r.lastActivity;
9616 return info;
9617 }
9618
9619 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9620 int flags) {
9621 synchronized (this) {
9622 ArrayList<ActivityManager.RunningServiceInfo> res
9623 = new ArrayList<ActivityManager.RunningServiceInfo>();
9624
9625 if (mServices.size() > 0) {
9626 Iterator<ServiceRecord> it = mServices.values().iterator();
9627 while (it.hasNext() && res.size() < maxNum) {
9628 res.add(makeRunningServiceInfoLocked(it.next()));
9629 }
9630 }
9631
9632 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9633 ServiceRecord r = mRestartingServices.get(i);
9634 ActivityManager.RunningServiceInfo info =
9635 makeRunningServiceInfoLocked(r);
9636 info.restarting = r.nextRestartTime;
9637 res.add(info);
9638 }
9639
9640 return res;
9641 }
9642 }
9643
9644 private final ServiceRecord findServiceLocked(ComponentName name,
9645 IBinder token) {
9646 ServiceRecord r = mServices.get(name);
9647 return r == token ? r : null;
9648 }
9649
9650 private final class ServiceLookupResult {
9651 final ServiceRecord record;
9652 final String permission;
9653
9654 ServiceLookupResult(ServiceRecord _record, String _permission) {
9655 record = _record;
9656 permission = _permission;
9657 }
9658 };
9659
9660 private ServiceLookupResult findServiceLocked(Intent service,
9661 String resolvedType) {
9662 ServiceRecord r = null;
9663 if (service.getComponent() != null) {
9664 r = mServices.get(service.getComponent());
9665 }
9666 if (r == null) {
9667 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9668 r = mServicesByIntent.get(filter);
9669 }
9670
9671 if (r == null) {
9672 try {
9673 ResolveInfo rInfo =
9674 ActivityThread.getPackageManager().resolveService(
9675 service, resolvedType, 0);
9676 ServiceInfo sInfo =
9677 rInfo != null ? rInfo.serviceInfo : null;
9678 if (sInfo == null) {
9679 return null;
9680 }
9681
9682 ComponentName name = new ComponentName(
9683 sInfo.applicationInfo.packageName, sInfo.name);
9684 r = mServices.get(name);
9685 } catch (RemoteException ex) {
9686 // pm is in same process, this will never happen.
9687 }
9688 }
9689 if (r != null) {
9690 int callingPid = Binder.getCallingPid();
9691 int callingUid = Binder.getCallingUid();
9692 if (checkComponentPermission(r.permission,
9693 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9694 != PackageManager.PERMISSION_GRANTED) {
9695 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9696 + " from pid=" + callingPid
9697 + ", uid=" + callingUid
9698 + " requires " + r.permission);
9699 return new ServiceLookupResult(null, r.permission);
9700 }
9701 return new ServiceLookupResult(r, null);
9702 }
9703 return null;
9704 }
9705
9706 private class ServiceRestarter implements Runnable {
9707 private ServiceRecord mService;
9708
9709 void setService(ServiceRecord service) {
9710 mService = service;
9711 }
9712
9713 public void run() {
9714 synchronized(ActivityManagerService.this) {
9715 performServiceRestartLocked(mService);
9716 }
9717 }
9718 }
9719
9720 private ServiceLookupResult retrieveServiceLocked(Intent service,
9721 String resolvedType, int callingPid, int callingUid) {
9722 ServiceRecord r = null;
9723 if (service.getComponent() != null) {
9724 r = mServices.get(service.getComponent());
9725 }
9726 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9727 r = mServicesByIntent.get(filter);
9728 if (r == null) {
9729 try {
9730 ResolveInfo rInfo =
9731 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009732 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009733 ServiceInfo sInfo =
9734 rInfo != null ? rInfo.serviceInfo : null;
9735 if (sInfo == null) {
9736 Log.w(TAG, "Unable to start service " + service +
9737 ": not found");
9738 return null;
9739 }
9740
9741 ComponentName name = new ComponentName(
9742 sInfo.applicationInfo.packageName, sInfo.name);
9743 r = mServices.get(name);
9744 if (r == null) {
9745 filter = new Intent.FilterComparison(service.cloneFilter());
9746 ServiceRestarter res = new ServiceRestarter();
9747 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9748 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9749 synchronized (stats) {
9750 ss = stats.getServiceStatsLocked(
9751 sInfo.applicationInfo.uid, sInfo.packageName,
9752 sInfo.name);
9753 }
9754 r = new ServiceRecord(ss, name, filter, sInfo, res);
9755 res.setService(r);
9756 mServices.put(name, r);
9757 mServicesByIntent.put(filter, r);
9758
9759 // Make sure this component isn't in the pending list.
9760 int N = mPendingServices.size();
9761 for (int i=0; i<N; i++) {
9762 ServiceRecord pr = mPendingServices.get(i);
9763 if (pr.name.equals(name)) {
9764 mPendingServices.remove(i);
9765 i--;
9766 N--;
9767 }
9768 }
9769 }
9770 } catch (RemoteException ex) {
9771 // pm is in same process, this will never happen.
9772 }
9773 }
9774 if (r != null) {
9775 if (checkComponentPermission(r.permission,
9776 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9777 != PackageManager.PERMISSION_GRANTED) {
9778 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9779 + " from pid=" + Binder.getCallingPid()
9780 + ", uid=" + Binder.getCallingUid()
9781 + " requires " + r.permission);
9782 return new ServiceLookupResult(null, r.permission);
9783 }
9784 return new ServiceLookupResult(r, null);
9785 }
9786 return null;
9787 }
9788
9789 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9790 long now = SystemClock.uptimeMillis();
9791 if (r.executeNesting == 0 && r.app != null) {
9792 if (r.app.executingServices.size() == 0) {
9793 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9794 msg.obj = r.app;
9795 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9796 }
9797 r.app.executingServices.add(r);
9798 }
9799 r.executeNesting++;
9800 r.executingStart = now;
9801 }
9802
9803 private final void sendServiceArgsLocked(ServiceRecord r,
9804 boolean oomAdjusted) {
9805 final int N = r.startArgs.size();
9806 if (N == 0) {
9807 return;
9808 }
9809
9810 final int BASEID = r.lastStartId - N + 1;
9811 int i = 0;
9812 while (i < N) {
9813 try {
9814 Intent args = r.startArgs.get(i);
9815 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9816 + r.name + " " + r.intent + " args=" + args);
9817 bumpServiceExecutingLocked(r);
9818 if (!oomAdjusted) {
9819 oomAdjusted = true;
9820 updateOomAdjLocked(r.app);
9821 }
9822 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9823 i++;
9824 } catch (Exception e) {
9825 break;
9826 }
9827 }
9828 if (i == N) {
9829 r.startArgs.clear();
9830 } else {
9831 while (i > 0) {
9832 r.startArgs.remove(0);
9833 i--;
9834 }
9835 }
9836 }
9837
9838 private final boolean requestServiceBindingLocked(ServiceRecord r,
9839 IntentBindRecord i, boolean rebind) {
9840 if (r.app == null || r.app.thread == null) {
9841 // If service is not currently running, can't yet bind.
9842 return false;
9843 }
9844 if ((!i.requested || rebind) && i.apps.size() > 0) {
9845 try {
9846 bumpServiceExecutingLocked(r);
9847 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9848 + ": shouldUnbind=" + i.hasBound);
9849 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9850 if (!rebind) {
9851 i.requested = true;
9852 }
9853 i.hasBound = true;
9854 i.doRebind = false;
9855 } catch (RemoteException e) {
9856 return false;
9857 }
9858 }
9859 return true;
9860 }
9861
9862 private final void requestServiceBindingsLocked(ServiceRecord r) {
9863 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9864 while (bindings.hasNext()) {
9865 IntentBindRecord i = bindings.next();
9866 if (!requestServiceBindingLocked(r, i, false)) {
9867 break;
9868 }
9869 }
9870 }
9871
9872 private final void realStartServiceLocked(ServiceRecord r,
9873 ProcessRecord app) throws RemoteException {
9874 if (app.thread == null) {
9875 throw new RemoteException();
9876 }
9877
9878 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009879 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009880
9881 app.services.add(r);
9882 bumpServiceExecutingLocked(r);
9883 updateLRUListLocked(app, true);
9884
9885 boolean created = false;
9886 try {
9887 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9888 + r.name + " " + r.intent);
9889 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9890 System.identityHashCode(r), r.shortName,
9891 r.intent.getIntent().toString(), r.app.pid);
9892 synchronized (r.stats.getBatteryStats()) {
9893 r.stats.startLaunchedLocked();
9894 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009895 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009896 app.thread.scheduleCreateService(r, r.serviceInfo);
9897 created = true;
9898 } finally {
9899 if (!created) {
9900 app.services.remove(r);
9901 scheduleServiceRestartLocked(r);
9902 }
9903 }
9904
9905 requestServiceBindingsLocked(r);
9906 sendServiceArgsLocked(r, true);
9907 }
9908
9909 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9910 r.totalRestartCount++;
9911 if (r.restartDelay == 0) {
9912 r.restartCount++;
9913 r.restartDelay = SERVICE_RESTART_DURATION;
9914 } else {
9915 // If it has been a "reasonably long time" since the service
9916 // was started, then reset our restart duration back to
9917 // the beginning, so we don't infinitely increase the duration
9918 // on a service that just occasionally gets killed (which is
9919 // a normal case, due to process being killed to reclaim memory).
9920 long now = SystemClock.uptimeMillis();
9921 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9922 r.restartCount = 1;
9923 r.restartDelay = SERVICE_RESTART_DURATION;
9924 } else {
9925 r.restartDelay *= 2;
9926 }
9927 }
9928 if (!mRestartingServices.contains(r)) {
9929 mRestartingServices.add(r);
9930 }
9931 mHandler.removeCallbacks(r.restarter);
9932 mHandler.postDelayed(r.restarter, r.restartDelay);
9933 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9934 Log.w(TAG, "Scheduling restart of crashed service "
9935 + r.shortName + " in " + r.restartDelay + "ms");
9936 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9937 r.shortName, r.restartDelay);
9938
9939 Message msg = Message.obtain();
9940 msg.what = SERVICE_ERROR_MSG;
9941 msg.obj = r;
9942 mHandler.sendMessage(msg);
9943 }
9944
9945 final void performServiceRestartLocked(ServiceRecord r) {
9946 if (!mRestartingServices.contains(r)) {
9947 return;
9948 }
9949 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9950 }
9951
9952 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9953 if (r.restartDelay == 0) {
9954 return false;
9955 }
9956 r.resetRestartCounter();
9957 mRestartingServices.remove(r);
9958 mHandler.removeCallbacks(r.restarter);
9959 return true;
9960 }
9961
9962 private final boolean bringUpServiceLocked(ServiceRecord r,
9963 int intentFlags, boolean whileRestarting) {
9964 //Log.i(TAG, "Bring up service:");
9965 //r.dump(" ");
9966
9967 if (r.app != null) {
9968 sendServiceArgsLocked(r, false);
9969 return true;
9970 }
9971
9972 if (!whileRestarting && r.restartDelay > 0) {
9973 // If waiting for a restart, then do nothing.
9974 return true;
9975 }
9976
9977 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9978 + " " + r.intent);
9979
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009980 // We are now bringing the service up, so no longer in the
9981 // restarting state.
9982 mRestartingServices.remove(r);
9983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009984 final String appName = r.processName;
9985 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9986 if (app != null && app.thread != null) {
9987 try {
9988 realStartServiceLocked(r, app);
9989 return true;
9990 } catch (RemoteException e) {
9991 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9992 }
9993
9994 // If a dead object exception was thrown -- fall through to
9995 // restart the application.
9996 }
9997
9998 if (!mPendingServices.contains(r)) {
9999 // Not running -- get it started, and enqueue this service record
10000 // to be executed when the app comes up.
10001 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10002 "service", r.name) == null) {
10003 Log.w(TAG, "Unable to launch app "
10004 + r.appInfo.packageName + "/"
10005 + r.appInfo.uid + " for service "
10006 + r.intent.getIntent() + ": process is bad");
10007 bringDownServiceLocked(r, true);
10008 return false;
10009 }
10010 mPendingServices.add(r);
10011 }
10012 return true;
10013 }
10014
10015 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10016 //Log.i(TAG, "Bring down service:");
10017 //r.dump(" ");
10018
10019 // Does it still need to run?
10020 if (!force && r.startRequested) {
10021 return;
10022 }
10023 if (r.connections.size() > 0) {
10024 if (!force) {
10025 // XXX should probably keep a count of the number of auto-create
10026 // connections directly in the service.
10027 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10028 while (it.hasNext()) {
10029 ConnectionRecord cr = it.next();
10030 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10031 return;
10032 }
10033 }
10034 }
10035
10036 // Report to all of the connections that the service is no longer
10037 // available.
10038 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10039 while (it.hasNext()) {
10040 ConnectionRecord c = it.next();
10041 try {
10042 // todo: shouldn't be a synchronous call!
10043 c.conn.connected(r.name, null);
10044 } catch (Exception e) {
10045 Log.w(TAG, "Failure disconnecting service " + r.name +
10046 " to connection " + c.conn.asBinder() +
10047 " (in " + c.binding.client.processName + ")", e);
10048 }
10049 }
10050 }
10051
10052 // Tell the service that it has been unbound.
10053 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10054 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10055 while (it.hasNext()) {
10056 IntentBindRecord ibr = it.next();
10057 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10058 + ": hasBound=" + ibr.hasBound);
10059 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10060 try {
10061 bumpServiceExecutingLocked(r);
10062 updateOomAdjLocked(r.app);
10063 ibr.hasBound = false;
10064 r.app.thread.scheduleUnbindService(r,
10065 ibr.intent.getIntent());
10066 } catch (Exception e) {
10067 Log.w(TAG, "Exception when unbinding service "
10068 + r.shortName, e);
10069 serviceDoneExecutingLocked(r, true);
10070 }
10071 }
10072 }
10073 }
10074
10075 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10076 + " " + r.intent);
10077 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10078 System.identityHashCode(r), r.shortName,
10079 (r.app != null) ? r.app.pid : -1);
10080
10081 mServices.remove(r.name);
10082 mServicesByIntent.remove(r.intent);
10083 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10084 r.totalRestartCount = 0;
10085 unscheduleServiceRestartLocked(r);
10086
10087 // Also make sure it is not on the pending list.
10088 int N = mPendingServices.size();
10089 for (int i=0; i<N; i++) {
10090 if (mPendingServices.get(i) == r) {
10091 mPendingServices.remove(i);
10092 if (DEBUG_SERVICE) Log.v(
10093 TAG, "Removed pending service: " + r.shortName);
10094 i--;
10095 N--;
10096 }
10097 }
10098
10099 if (r.app != null) {
10100 synchronized (r.stats.getBatteryStats()) {
10101 r.stats.stopLaunchedLocked();
10102 }
10103 r.app.services.remove(r);
10104 if (r.app.thread != null) {
10105 updateServiceForegroundLocked(r.app, false);
10106 try {
10107 Log.i(TAG, "Stopping service: " + r.shortName);
10108 bumpServiceExecutingLocked(r);
10109 mStoppingServices.add(r);
10110 updateOomAdjLocked(r.app);
10111 r.app.thread.scheduleStopService(r);
10112 } catch (Exception e) {
10113 Log.w(TAG, "Exception when stopping service "
10114 + r.shortName, e);
10115 serviceDoneExecutingLocked(r, true);
10116 }
10117 } else {
10118 if (DEBUG_SERVICE) Log.v(
10119 TAG, "Removed service that has no process: " + r.shortName);
10120 }
10121 } else {
10122 if (DEBUG_SERVICE) Log.v(
10123 TAG, "Removed service that is not running: " + r.shortName);
10124 }
10125 }
10126
10127 ComponentName startServiceLocked(IApplicationThread caller,
10128 Intent service, String resolvedType,
10129 int callingPid, int callingUid) {
10130 synchronized(this) {
10131 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10132 + " type=" + resolvedType + " args=" + service.getExtras());
10133
10134 if (caller != null) {
10135 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10136 if (callerApp == null) {
10137 throw new SecurityException(
10138 "Unable to find app for caller " + caller
10139 + " (pid=" + Binder.getCallingPid()
10140 + ") when starting service " + service);
10141 }
10142 }
10143
10144 ServiceLookupResult res =
10145 retrieveServiceLocked(service, resolvedType,
10146 callingPid, callingUid);
10147 if (res == null) {
10148 return null;
10149 }
10150 if (res.record == null) {
10151 return new ComponentName("!", res.permission != null
10152 ? res.permission : "private to package");
10153 }
10154 ServiceRecord r = res.record;
10155 if (unscheduleServiceRestartLocked(r)) {
10156 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10157 + r.shortName);
10158 }
10159 r.startRequested = true;
10160 r.startArgs.add(service);
10161 r.lastStartId++;
10162 if (r.lastStartId < 1) {
10163 r.lastStartId = 1;
10164 }
10165 r.lastActivity = SystemClock.uptimeMillis();
10166 synchronized (r.stats.getBatteryStats()) {
10167 r.stats.startRunningLocked();
10168 }
10169 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10170 return new ComponentName("!", "Service process is bad");
10171 }
10172 return r.name;
10173 }
10174 }
10175
10176 public ComponentName startService(IApplicationThread caller, Intent service,
10177 String resolvedType) {
10178 // Refuse possible leaked file descriptors
10179 if (service != null && service.hasFileDescriptors() == true) {
10180 throw new IllegalArgumentException("File descriptors passed in Intent");
10181 }
10182
10183 synchronized(this) {
10184 final int callingPid = Binder.getCallingPid();
10185 final int callingUid = Binder.getCallingUid();
10186 final long origId = Binder.clearCallingIdentity();
10187 ComponentName res = startServiceLocked(caller, service,
10188 resolvedType, callingPid, callingUid);
10189 Binder.restoreCallingIdentity(origId);
10190 return res;
10191 }
10192 }
10193
10194 ComponentName startServiceInPackage(int uid,
10195 Intent service, String resolvedType) {
10196 synchronized(this) {
10197 final long origId = Binder.clearCallingIdentity();
10198 ComponentName res = startServiceLocked(null, service,
10199 resolvedType, -1, uid);
10200 Binder.restoreCallingIdentity(origId);
10201 return res;
10202 }
10203 }
10204
10205 public int stopService(IApplicationThread caller, Intent service,
10206 String resolvedType) {
10207 // Refuse possible leaked file descriptors
10208 if (service != null && service.hasFileDescriptors() == true) {
10209 throw new IllegalArgumentException("File descriptors passed in Intent");
10210 }
10211
10212 synchronized(this) {
10213 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10214 + " type=" + resolvedType);
10215
10216 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10217 if (caller != null && callerApp == null) {
10218 throw new SecurityException(
10219 "Unable to find app for caller " + caller
10220 + " (pid=" + Binder.getCallingPid()
10221 + ") when stopping service " + service);
10222 }
10223
10224 // If this service is active, make sure it is stopped.
10225 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10226 if (r != null) {
10227 if (r.record != null) {
10228 synchronized (r.record.stats.getBatteryStats()) {
10229 r.record.stats.stopRunningLocked();
10230 }
10231 r.record.startRequested = false;
10232 final long origId = Binder.clearCallingIdentity();
10233 bringDownServiceLocked(r.record, false);
10234 Binder.restoreCallingIdentity(origId);
10235 return 1;
10236 }
10237 return -1;
10238 }
10239 }
10240
10241 return 0;
10242 }
10243
10244 public IBinder peekService(Intent service, String resolvedType) {
10245 // Refuse possible leaked file descriptors
10246 if (service != null && service.hasFileDescriptors() == true) {
10247 throw new IllegalArgumentException("File descriptors passed in Intent");
10248 }
10249
10250 IBinder ret = null;
10251
10252 synchronized(this) {
10253 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10254
10255 if (r != null) {
10256 // r.record is null if findServiceLocked() failed the caller permission check
10257 if (r.record == null) {
10258 throw new SecurityException(
10259 "Permission Denial: Accessing service " + r.record.name
10260 + " from pid=" + Binder.getCallingPid()
10261 + ", uid=" + Binder.getCallingUid()
10262 + " requires " + r.permission);
10263 }
10264 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10265 if (ib != null) {
10266 ret = ib.binder;
10267 }
10268 }
10269 }
10270
10271 return ret;
10272 }
10273
10274 public boolean stopServiceToken(ComponentName className, IBinder token,
10275 int startId) {
10276 synchronized(this) {
10277 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10278 + " " + token + " startId=" + startId);
10279 ServiceRecord r = findServiceLocked(className, token);
10280 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10281 synchronized (r.stats.getBatteryStats()) {
10282 r.stats.stopRunningLocked();
10283 r.startRequested = false;
10284 }
10285 final long origId = Binder.clearCallingIdentity();
10286 bringDownServiceLocked(r, false);
10287 Binder.restoreCallingIdentity(origId);
10288 return true;
10289 }
10290 }
10291 return false;
10292 }
10293
10294 public void setServiceForeground(ComponentName className, IBinder token,
10295 boolean isForeground) {
10296 synchronized(this) {
10297 ServiceRecord r = findServiceLocked(className, token);
10298 if (r != null) {
10299 if (r.isForeground != isForeground) {
10300 final long origId = Binder.clearCallingIdentity();
10301 r.isForeground = isForeground;
10302 if (r.app != null) {
10303 updateServiceForegroundLocked(r.app, true);
10304 }
10305 Binder.restoreCallingIdentity(origId);
10306 }
10307 }
10308 }
10309 }
10310
10311 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10312 boolean anyForeground = false;
10313 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10314 if (sr.isForeground) {
10315 anyForeground = true;
10316 break;
10317 }
10318 }
10319 if (anyForeground != proc.foregroundServices) {
10320 proc.foregroundServices = anyForeground;
10321 if (oomAdj) {
10322 updateOomAdjLocked();
10323 }
10324 }
10325 }
10326
10327 public int bindService(IApplicationThread caller, IBinder token,
10328 Intent service, String resolvedType,
10329 IServiceConnection connection, int flags) {
10330 // Refuse possible leaked file descriptors
10331 if (service != null && service.hasFileDescriptors() == true) {
10332 throw new IllegalArgumentException("File descriptors passed in Intent");
10333 }
10334
10335 synchronized(this) {
10336 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10337 + " type=" + resolvedType + " conn=" + connection.asBinder()
10338 + " flags=0x" + Integer.toHexString(flags));
10339 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10340 if (callerApp == null) {
10341 throw new SecurityException(
10342 "Unable to find app for caller " + caller
10343 + " (pid=" + Binder.getCallingPid()
10344 + ") when binding service " + service);
10345 }
10346
10347 HistoryRecord activity = null;
10348 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010349 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010350 if (aindex < 0) {
10351 Log.w(TAG, "Binding with unknown activity: " + token);
10352 return 0;
10353 }
10354 activity = (HistoryRecord)mHistory.get(aindex);
10355 }
10356
10357 ServiceLookupResult res =
10358 retrieveServiceLocked(service, resolvedType,
10359 Binder.getCallingPid(), Binder.getCallingUid());
10360 if (res == null) {
10361 return 0;
10362 }
10363 if (res.record == null) {
10364 return -1;
10365 }
10366 ServiceRecord s = res.record;
10367
10368 final long origId = Binder.clearCallingIdentity();
10369
10370 if (unscheduleServiceRestartLocked(s)) {
10371 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10372 + s.shortName);
10373 }
10374
10375 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10376 ConnectionRecord c = new ConnectionRecord(b, activity,
10377 connection, flags);
10378
10379 IBinder binder = connection.asBinder();
10380 s.connections.put(binder, c);
10381 b.connections.add(c);
10382 if (activity != null) {
10383 if (activity.connections == null) {
10384 activity.connections = new HashSet<ConnectionRecord>();
10385 }
10386 activity.connections.add(c);
10387 }
10388 b.client.connections.add(c);
10389 mServiceConnections.put(binder, c);
10390
10391 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10392 s.lastActivity = SystemClock.uptimeMillis();
10393 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10394 return 0;
10395 }
10396 }
10397
10398 if (s.app != null) {
10399 // This could have made the service more important.
10400 updateOomAdjLocked(s.app);
10401 }
10402
10403 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10404 + ": received=" + b.intent.received
10405 + " apps=" + b.intent.apps.size()
10406 + " doRebind=" + b.intent.doRebind);
10407
10408 if (s.app != null && b.intent.received) {
10409 // Service is already running, so we can immediately
10410 // publish the connection.
10411 try {
10412 c.conn.connected(s.name, b.intent.binder);
10413 } catch (Exception e) {
10414 Log.w(TAG, "Failure sending service " + s.shortName
10415 + " to connection " + c.conn.asBinder()
10416 + " (in " + c.binding.client.processName + ")", e);
10417 }
10418
10419 // If this is the first app connected back to this binding,
10420 // and the service had previously asked to be told when
10421 // rebound, then do so.
10422 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10423 requestServiceBindingLocked(s, b.intent, true);
10424 }
10425 } else if (!b.intent.requested) {
10426 requestServiceBindingLocked(s, b.intent, false);
10427 }
10428
10429 Binder.restoreCallingIdentity(origId);
10430 }
10431
10432 return 1;
10433 }
10434
10435 private void removeConnectionLocked(
10436 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10437 IBinder binder = c.conn.asBinder();
10438 AppBindRecord b = c.binding;
10439 ServiceRecord s = b.service;
10440 s.connections.remove(binder);
10441 b.connections.remove(c);
10442 if (c.activity != null && c.activity != skipAct) {
10443 if (c.activity.connections != null) {
10444 c.activity.connections.remove(c);
10445 }
10446 }
10447 if (b.client != skipApp) {
10448 b.client.connections.remove(c);
10449 }
10450 mServiceConnections.remove(binder);
10451
10452 if (b.connections.size() == 0) {
10453 b.intent.apps.remove(b.client);
10454 }
10455
10456 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10457 + ": shouldUnbind=" + b.intent.hasBound);
10458 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10459 && b.intent.hasBound) {
10460 try {
10461 bumpServiceExecutingLocked(s);
10462 updateOomAdjLocked(s.app);
10463 b.intent.hasBound = false;
10464 // Assume the client doesn't want to know about a rebind;
10465 // we will deal with that later if it asks for one.
10466 b.intent.doRebind = false;
10467 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10468 } catch (Exception e) {
10469 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10470 serviceDoneExecutingLocked(s, true);
10471 }
10472 }
10473
10474 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10475 bringDownServiceLocked(s, false);
10476 }
10477 }
10478
10479 public boolean unbindService(IServiceConnection connection) {
10480 synchronized (this) {
10481 IBinder binder = connection.asBinder();
10482 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10483 ConnectionRecord r = mServiceConnections.get(binder);
10484 if (r == null) {
10485 Log.w(TAG, "Unbind failed: could not find connection for "
10486 + connection.asBinder());
10487 return false;
10488 }
10489
10490 final long origId = Binder.clearCallingIdentity();
10491
10492 removeConnectionLocked(r, null, null);
10493
10494 if (r.binding.service.app != null) {
10495 // This could have made the service less important.
10496 updateOomAdjLocked(r.binding.service.app);
10497 }
10498
10499 Binder.restoreCallingIdentity(origId);
10500 }
10501
10502 return true;
10503 }
10504
10505 public void publishService(IBinder token, Intent intent, IBinder service) {
10506 // Refuse possible leaked file descriptors
10507 if (intent != null && intent.hasFileDescriptors() == true) {
10508 throw new IllegalArgumentException("File descriptors passed in Intent");
10509 }
10510
10511 synchronized(this) {
10512 if (!(token instanceof ServiceRecord)) {
10513 throw new IllegalArgumentException("Invalid service token");
10514 }
10515 ServiceRecord r = (ServiceRecord)token;
10516
10517 final long origId = Binder.clearCallingIdentity();
10518
10519 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10520 + " " + intent + ": " + service);
10521 if (r != null) {
10522 Intent.FilterComparison filter
10523 = new Intent.FilterComparison(intent);
10524 IntentBindRecord b = r.bindings.get(filter);
10525 if (b != null && !b.received) {
10526 b.binder = service;
10527 b.requested = true;
10528 b.received = true;
10529 if (r.connections.size() > 0) {
10530 Iterator<ConnectionRecord> it
10531 = r.connections.values().iterator();
10532 while (it.hasNext()) {
10533 ConnectionRecord c = it.next();
10534 if (!filter.equals(c.binding.intent.intent)) {
10535 if (DEBUG_SERVICE) Log.v(
10536 TAG, "Not publishing to: " + c);
10537 if (DEBUG_SERVICE) Log.v(
10538 TAG, "Bound intent: " + c.binding.intent.intent);
10539 if (DEBUG_SERVICE) Log.v(
10540 TAG, "Published intent: " + intent);
10541 continue;
10542 }
10543 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10544 try {
10545 c.conn.connected(r.name, service);
10546 } catch (Exception e) {
10547 Log.w(TAG, "Failure sending service " + r.name +
10548 " to connection " + c.conn.asBinder() +
10549 " (in " + c.binding.client.processName + ")", e);
10550 }
10551 }
10552 }
10553 }
10554
10555 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10556
10557 Binder.restoreCallingIdentity(origId);
10558 }
10559 }
10560 }
10561
10562 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10563 // Refuse possible leaked file descriptors
10564 if (intent != null && intent.hasFileDescriptors() == true) {
10565 throw new IllegalArgumentException("File descriptors passed in Intent");
10566 }
10567
10568 synchronized(this) {
10569 if (!(token instanceof ServiceRecord)) {
10570 throw new IllegalArgumentException("Invalid service token");
10571 }
10572 ServiceRecord r = (ServiceRecord)token;
10573
10574 final long origId = Binder.clearCallingIdentity();
10575
10576 if (r != null) {
10577 Intent.FilterComparison filter
10578 = new Intent.FilterComparison(intent);
10579 IntentBindRecord b = r.bindings.get(filter);
10580 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10581 + " at " + b + ": apps="
10582 + (b != null ? b.apps.size() : 0));
10583 if (b != null) {
10584 if (b.apps.size() > 0) {
10585 // Applications have already bound since the last
10586 // unbind, so just rebind right here.
10587 requestServiceBindingLocked(r, b, true);
10588 } else {
10589 // Note to tell the service the next time there is
10590 // a new client.
10591 b.doRebind = true;
10592 }
10593 }
10594
10595 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10596
10597 Binder.restoreCallingIdentity(origId);
10598 }
10599 }
10600 }
10601
10602 public void serviceDoneExecuting(IBinder token) {
10603 synchronized(this) {
10604 if (!(token instanceof ServiceRecord)) {
10605 throw new IllegalArgumentException("Invalid service token");
10606 }
10607 ServiceRecord r = (ServiceRecord)token;
10608 boolean inStopping = mStoppingServices.contains(token);
10609 if (r != null) {
10610 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10611 + ": nesting=" + r.executeNesting
10612 + ", inStopping=" + inStopping);
10613 if (r != token) {
10614 Log.w(TAG, "Done executing service " + r.name
10615 + " with incorrect token: given " + token
10616 + ", expected " + r);
10617 return;
10618 }
10619
10620 final long origId = Binder.clearCallingIdentity();
10621 serviceDoneExecutingLocked(r, inStopping);
10622 Binder.restoreCallingIdentity(origId);
10623 } else {
10624 Log.w(TAG, "Done executing unknown service " + r.name
10625 + " with token " + token);
10626 }
10627 }
10628 }
10629
10630 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10631 r.executeNesting--;
10632 if (r.executeNesting <= 0 && r.app != null) {
10633 r.app.executingServices.remove(r);
10634 if (r.app.executingServices.size() == 0) {
10635 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10636 }
10637 if (inStopping) {
10638 mStoppingServices.remove(r);
10639 }
10640 updateOomAdjLocked(r.app);
10641 }
10642 }
10643
10644 void serviceTimeout(ProcessRecord proc) {
10645 synchronized(this) {
10646 if (proc.executingServices.size() == 0 || proc.thread == null) {
10647 return;
10648 }
10649 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10650 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10651 ServiceRecord timeout = null;
10652 long nextTime = 0;
10653 while (it.hasNext()) {
10654 ServiceRecord sr = it.next();
10655 if (sr.executingStart < maxTime) {
10656 timeout = sr;
10657 break;
10658 }
10659 if (sr.executingStart > nextTime) {
10660 nextTime = sr.executingStart;
10661 }
10662 }
10663 if (timeout != null && mLRUProcesses.contains(proc)) {
10664 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070010665 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010666 + timeout.name);
10667 } else {
10668 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10669 msg.obj = proc;
10670 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10671 }
10672 }
10673 }
10674
10675 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010676 // BACKUP AND RESTORE
10677 // =========================================================
10678
10679 // Cause the target app to be launched if necessary and its backup agent
10680 // instantiated. The backup agent will invoke backupAgentCreated() on the
10681 // activity manager to announce its creation.
10682 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10683 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10684 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10685
10686 synchronized(this) {
10687 // !!! TODO: currently no check here that we're already bound
10688 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10689 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10690 synchronized (stats) {
10691 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10692 }
10693
10694 BackupRecord r = new BackupRecord(ss, app, backupMode);
10695 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10696 // startProcessLocked() returns existing proc's record if it's already running
10697 ProcessRecord proc = startProcessLocked(app.processName, app,
10698 false, 0, "backup", hostingName);
10699 if (proc == null) {
10700 Log.e(TAG, "Unable to start backup agent process " + r);
10701 return false;
10702 }
10703
10704 r.app = proc;
10705 mBackupTarget = r;
10706 mBackupAppName = app.packageName;
10707
Christopher Tate6fa95972009-06-05 18:43:55 -070010708 // Try not to kill the process during backup
10709 updateOomAdjLocked(proc);
10710
Christopher Tate181fafa2009-05-14 11:12:14 -070010711 // If the process is already attached, schedule the creation of the backup agent now.
10712 // If it is not yet live, this will be done when it attaches to the framework.
10713 if (proc.thread != null) {
10714 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10715 try {
10716 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10717 } catch (RemoteException e) {
10718 // !!! TODO: notify the backup manager that we crashed, or rely on
10719 // death notices, or...?
10720 }
10721 } else {
10722 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10723 }
10724 // Invariants: at this point, the target app process exists and the application
10725 // is either already running or in the process of coming up. mBackupTarget and
10726 // mBackupAppName describe the app, so that when it binds back to the AM we
10727 // know that it's scheduled for a backup-agent operation.
10728 }
10729
10730 return true;
10731 }
10732
10733 // A backup agent has just come up
10734 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10735 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10736 + " = " + agent);
10737
10738 synchronized(this) {
10739 if (!agentPackageName.equals(mBackupAppName)) {
10740 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10741 return;
10742 }
10743
Christopher Tate043dadc2009-06-02 16:11:00 -070010744 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010745 try {
10746 IBackupManager bm = IBackupManager.Stub.asInterface(
10747 ServiceManager.getService(Context.BACKUP_SERVICE));
10748 bm.agentConnected(agentPackageName, agent);
10749 } catch (RemoteException e) {
10750 // can't happen; the backup manager service is local
10751 } catch (Exception e) {
10752 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10753 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010754 } finally {
10755 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010756 }
10757 }
10758 }
10759
10760 // done with this agent
10761 public void unbindBackupAgent(ApplicationInfo appInfo) {
10762 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010763 if (appInfo == null) {
10764 Log.w(TAG, "unbind backup agent for null app");
10765 return;
10766 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010767
10768 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010769 if (mBackupAppName == null) {
10770 Log.w(TAG, "Unbinding backup agent with no active backup");
10771 return;
10772 }
10773
Christopher Tate181fafa2009-05-14 11:12:14 -070010774 if (!mBackupAppName.equals(appInfo.packageName)) {
10775 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10776 return;
10777 }
10778
Christopher Tate6fa95972009-06-05 18:43:55 -070010779 ProcessRecord proc = mBackupTarget.app;
10780 mBackupTarget = null;
10781 mBackupAppName = null;
10782
10783 // Not backing this app up any more; reset its OOM adjustment
10784 updateOomAdjLocked(proc);
10785
Christopher Tatec7b31e32009-06-10 15:49:30 -070010786 // If the app crashed during backup, 'thread' will be null here
10787 if (proc.thread != null) {
10788 try {
10789 proc.thread.scheduleDestroyBackupAgent(appInfo);
10790 } catch (Exception e) {
10791 Log.e(TAG, "Exception when unbinding backup agent:");
10792 e.printStackTrace();
10793 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010794 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010795 }
10796 }
10797 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010798 // BROADCASTS
10799 // =========================================================
10800
10801 private final List getStickies(String action, IntentFilter filter,
10802 List cur) {
10803 final ContentResolver resolver = mContext.getContentResolver();
10804 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10805 if (list == null) {
10806 return cur;
10807 }
10808 int N = list.size();
10809 for (int i=0; i<N; i++) {
10810 Intent intent = list.get(i);
10811 if (filter.match(resolver, intent, true, TAG) >= 0) {
10812 if (cur == null) {
10813 cur = new ArrayList<Intent>();
10814 }
10815 cur.add(intent);
10816 }
10817 }
10818 return cur;
10819 }
10820
10821 private final void scheduleBroadcastsLocked() {
10822 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10823 + mBroadcastsScheduled);
10824
10825 if (mBroadcastsScheduled) {
10826 return;
10827 }
10828 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10829 mBroadcastsScheduled = true;
10830 }
10831
10832 public Intent registerReceiver(IApplicationThread caller,
10833 IIntentReceiver receiver, IntentFilter filter, String permission) {
10834 synchronized(this) {
10835 ProcessRecord callerApp = null;
10836 if (caller != null) {
10837 callerApp = getRecordForAppLocked(caller);
10838 if (callerApp == null) {
10839 throw new SecurityException(
10840 "Unable to find app for caller " + caller
10841 + " (pid=" + Binder.getCallingPid()
10842 + ") when registering receiver " + receiver);
10843 }
10844 }
10845
10846 List allSticky = null;
10847
10848 // Look for any matching sticky broadcasts...
10849 Iterator actions = filter.actionsIterator();
10850 if (actions != null) {
10851 while (actions.hasNext()) {
10852 String action = (String)actions.next();
10853 allSticky = getStickies(action, filter, allSticky);
10854 }
10855 } else {
10856 allSticky = getStickies(null, filter, allSticky);
10857 }
10858
10859 // The first sticky in the list is returned directly back to
10860 // the client.
10861 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10862
10863 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10864 + ": " + sticky);
10865
10866 if (receiver == null) {
10867 return sticky;
10868 }
10869
10870 ReceiverList rl
10871 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10872 if (rl == null) {
10873 rl = new ReceiverList(this, callerApp,
10874 Binder.getCallingPid(),
10875 Binder.getCallingUid(), receiver);
10876 if (rl.app != null) {
10877 rl.app.receivers.add(rl);
10878 } else {
10879 try {
10880 receiver.asBinder().linkToDeath(rl, 0);
10881 } catch (RemoteException e) {
10882 return sticky;
10883 }
10884 rl.linkedToDeath = true;
10885 }
10886 mRegisteredReceivers.put(receiver.asBinder(), rl);
10887 }
10888 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10889 rl.add(bf);
10890 if (!bf.debugCheck()) {
10891 Log.w(TAG, "==> For Dynamic broadast");
10892 }
10893 mReceiverResolver.addFilter(bf);
10894
10895 // Enqueue broadcasts for all existing stickies that match
10896 // this filter.
10897 if (allSticky != null) {
10898 ArrayList receivers = new ArrayList();
10899 receivers.add(bf);
10900
10901 int N = allSticky.size();
10902 for (int i=0; i<N; i++) {
10903 Intent intent = (Intent)allSticky.get(i);
10904 BroadcastRecord r = new BroadcastRecord(intent, null,
10905 null, -1, -1, null, receivers, null, 0, null, null,
10906 false);
10907 if (mParallelBroadcasts.size() == 0) {
10908 scheduleBroadcastsLocked();
10909 }
10910 mParallelBroadcasts.add(r);
10911 }
10912 }
10913
10914 return sticky;
10915 }
10916 }
10917
10918 public void unregisterReceiver(IIntentReceiver receiver) {
10919 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10920
10921 boolean doNext = false;
10922
10923 synchronized(this) {
10924 ReceiverList rl
10925 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10926 if (rl != null) {
10927 if (rl.curBroadcast != null) {
10928 BroadcastRecord r = rl.curBroadcast;
10929 doNext = finishReceiverLocked(
10930 receiver.asBinder(), r.resultCode, r.resultData,
10931 r.resultExtras, r.resultAbort, true);
10932 }
10933
10934 if (rl.app != null) {
10935 rl.app.receivers.remove(rl);
10936 }
10937 removeReceiverLocked(rl);
10938 if (rl.linkedToDeath) {
10939 rl.linkedToDeath = false;
10940 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10941 }
10942 }
10943 }
10944
10945 if (!doNext) {
10946 return;
10947 }
10948
10949 final long origId = Binder.clearCallingIdentity();
10950 processNextBroadcast(false);
10951 trimApplications();
10952 Binder.restoreCallingIdentity(origId);
10953 }
10954
10955 void removeReceiverLocked(ReceiverList rl) {
10956 mRegisteredReceivers.remove(rl.receiver.asBinder());
10957 int N = rl.size();
10958 for (int i=0; i<N; i++) {
10959 mReceiverResolver.removeFilter(rl.get(i));
10960 }
10961 }
10962
10963 private final int broadcastIntentLocked(ProcessRecord callerApp,
10964 String callerPackage, Intent intent, String resolvedType,
10965 IIntentReceiver resultTo, int resultCode, String resultData,
10966 Bundle map, String requiredPermission,
10967 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10968 intent = new Intent(intent);
10969
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010970 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010971 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10972 + " ordered=" + ordered);
10973 if ((resultTo != null) && !ordered) {
10974 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10975 }
10976
10977 // Handle special intents: if this broadcast is from the package
10978 // manager about a package being removed, we need to remove all of
10979 // its activities from the history stack.
10980 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10981 intent.getAction());
10982 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10983 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10984 || uidRemoved) {
10985 if (checkComponentPermission(
10986 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10987 callingPid, callingUid, -1)
10988 == PackageManager.PERMISSION_GRANTED) {
10989 if (uidRemoved) {
10990 final Bundle intentExtras = intent.getExtras();
10991 final int uid = intentExtras != null
10992 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10993 if (uid >= 0) {
10994 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10995 synchronized (bs) {
10996 bs.removeUidStatsLocked(uid);
10997 }
10998 }
10999 } else {
11000 Uri data = intent.getData();
11001 String ssp;
11002 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11003 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11004 uninstallPackageLocked(ssp,
11005 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011006 AttributeCache ac = AttributeCache.instance();
11007 if (ac != null) {
11008 ac.removePackage(ssp);
11009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011010 }
11011 }
11012 }
11013 } else {
11014 String msg = "Permission Denial: " + intent.getAction()
11015 + " broadcast from " + callerPackage + " (pid=" + callingPid
11016 + ", uid=" + callingUid + ")"
11017 + " requires "
11018 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11019 Log.w(TAG, msg);
11020 throw new SecurityException(msg);
11021 }
11022 }
11023
11024 /*
11025 * If this is the time zone changed action, queue up a message that will reset the timezone
11026 * of all currently running processes. This message will get queued up before the broadcast
11027 * happens.
11028 */
11029 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11030 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11031 }
11032
Dianne Hackborn854060af2009-07-09 18:14:31 -070011033 /*
11034 * Prevent non-system code (defined here to be non-persistent
11035 * processes) from sending protected broadcasts.
11036 */
11037 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11038 || callingUid == Process.SHELL_UID || callingUid == 0) {
11039 // Always okay.
11040 } else if (callerApp == null || !callerApp.persistent) {
11041 try {
11042 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11043 intent.getAction())) {
11044 String msg = "Permission Denial: not allowed to send broadcast "
11045 + intent.getAction() + " from pid="
11046 + callingPid + ", uid=" + callingUid;
11047 Log.w(TAG, msg);
11048 throw new SecurityException(msg);
11049 }
11050 } catch (RemoteException e) {
11051 Log.w(TAG, "Remote exception", e);
11052 return BROADCAST_SUCCESS;
11053 }
11054 }
11055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011056 // Add to the sticky list if requested.
11057 if (sticky) {
11058 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11059 callingPid, callingUid)
11060 != PackageManager.PERMISSION_GRANTED) {
11061 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11062 + callingPid + ", uid=" + callingUid
11063 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11064 Log.w(TAG, msg);
11065 throw new SecurityException(msg);
11066 }
11067 if (requiredPermission != null) {
11068 Log.w(TAG, "Can't broadcast sticky intent " + intent
11069 + " and enforce permission " + requiredPermission);
11070 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11071 }
11072 if (intent.getComponent() != null) {
11073 throw new SecurityException(
11074 "Sticky broadcasts can't target a specific component");
11075 }
11076 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11077 if (list == null) {
11078 list = new ArrayList<Intent>();
11079 mStickyBroadcasts.put(intent.getAction(), list);
11080 }
11081 int N = list.size();
11082 int i;
11083 for (i=0; i<N; i++) {
11084 if (intent.filterEquals(list.get(i))) {
11085 // This sticky already exists, replace it.
11086 list.set(i, new Intent(intent));
11087 break;
11088 }
11089 }
11090 if (i >= N) {
11091 list.add(new Intent(intent));
11092 }
11093 }
11094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011095 // Figure out who all will receive this broadcast.
11096 List receivers = null;
11097 List<BroadcastFilter> registeredReceivers = null;
11098 try {
11099 if (intent.getComponent() != null) {
11100 // Broadcast is going to one specific receiver class...
11101 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011102 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011103 if (ai != null) {
11104 receivers = new ArrayList();
11105 ResolveInfo ri = new ResolveInfo();
11106 ri.activityInfo = ai;
11107 receivers.add(ri);
11108 }
11109 } else {
11110 // Need to resolve the intent to interested receivers...
11111 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11112 == 0) {
11113 receivers =
11114 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011115 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011116 }
Mihai Preda074edef2009-05-18 17:13:31 +020011117 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011118 }
11119 } catch (RemoteException ex) {
11120 // pm is in same process, this will never happen.
11121 }
11122
11123 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11124 if (!ordered && NR > 0) {
11125 // If we are not serializing this broadcast, then send the
11126 // registered receivers separately so they don't wait for the
11127 // components to be launched.
11128 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11129 callerPackage, callingPid, callingUid, requiredPermission,
11130 registeredReceivers, resultTo, resultCode, resultData, map,
11131 ordered);
11132 if (DEBUG_BROADCAST) Log.v(
11133 TAG, "Enqueueing parallel broadcast " + r
11134 + ": prev had " + mParallelBroadcasts.size());
11135 mParallelBroadcasts.add(r);
11136 scheduleBroadcastsLocked();
11137 registeredReceivers = null;
11138 NR = 0;
11139 }
11140
11141 // Merge into one list.
11142 int ir = 0;
11143 if (receivers != null) {
11144 // A special case for PACKAGE_ADDED: do not allow the package
11145 // being added to see this broadcast. This prevents them from
11146 // using this as a back door to get run as soon as they are
11147 // installed. Maybe in the future we want to have a special install
11148 // broadcast or such for apps, but we'd like to deliberately make
11149 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011150 boolean skip = false;
11151 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011152 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011153 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11154 skip = true;
11155 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11156 skip = true;
11157 }
11158 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011159 ? intent.getData().getSchemeSpecificPart()
11160 : null;
11161 if (skipPackage != null && receivers != null) {
11162 int NT = receivers.size();
11163 for (int it=0; it<NT; it++) {
11164 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11165 if (curt.activityInfo.packageName.equals(skipPackage)) {
11166 receivers.remove(it);
11167 it--;
11168 NT--;
11169 }
11170 }
11171 }
11172
11173 int NT = receivers != null ? receivers.size() : 0;
11174 int it = 0;
11175 ResolveInfo curt = null;
11176 BroadcastFilter curr = null;
11177 while (it < NT && ir < NR) {
11178 if (curt == null) {
11179 curt = (ResolveInfo)receivers.get(it);
11180 }
11181 if (curr == null) {
11182 curr = registeredReceivers.get(ir);
11183 }
11184 if (curr.getPriority() >= curt.priority) {
11185 // Insert this broadcast record into the final list.
11186 receivers.add(it, curr);
11187 ir++;
11188 curr = null;
11189 it++;
11190 NT++;
11191 } else {
11192 // Skip to the next ResolveInfo in the final list.
11193 it++;
11194 curt = null;
11195 }
11196 }
11197 }
11198 while (ir < NR) {
11199 if (receivers == null) {
11200 receivers = new ArrayList();
11201 }
11202 receivers.add(registeredReceivers.get(ir));
11203 ir++;
11204 }
11205
11206 if ((receivers != null && receivers.size() > 0)
11207 || resultTo != null) {
11208 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11209 callerPackage, callingPid, callingUid, requiredPermission,
11210 receivers, resultTo, resultCode, resultData, map, ordered);
11211 if (DEBUG_BROADCAST) Log.v(
11212 TAG, "Enqueueing ordered broadcast " + r
11213 + ": prev had " + mOrderedBroadcasts.size());
11214 if (DEBUG_BROADCAST) {
11215 int seq = r.intent.getIntExtra("seq", -1);
11216 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11217 }
11218 mOrderedBroadcasts.add(r);
11219 scheduleBroadcastsLocked();
11220 }
11221
11222 return BROADCAST_SUCCESS;
11223 }
11224
11225 public final int broadcastIntent(IApplicationThread caller,
11226 Intent intent, String resolvedType, IIntentReceiver resultTo,
11227 int resultCode, String resultData, Bundle map,
11228 String requiredPermission, boolean serialized, boolean sticky) {
11229 // Refuse possible leaked file descriptors
11230 if (intent != null && intent.hasFileDescriptors() == true) {
11231 throw new IllegalArgumentException("File descriptors passed in Intent");
11232 }
11233
11234 synchronized(this) {
11235 if (!mSystemReady) {
11236 // if the caller really truly claims to know what they're doing, go
11237 // ahead and allow the broadcast without launching any receivers
11238 int flags = intent.getFlags();
11239 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11240 intent = new Intent(intent);
11241 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11242 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11243 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11244 + " before boot completion");
11245 throw new IllegalStateException("Cannot broadcast before boot completed");
11246 }
11247 }
11248
11249 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11250 final int callingPid = Binder.getCallingPid();
11251 final int callingUid = Binder.getCallingUid();
11252 final long origId = Binder.clearCallingIdentity();
11253 int res = broadcastIntentLocked(callerApp,
11254 callerApp != null ? callerApp.info.packageName : null,
11255 intent, resolvedType, resultTo,
11256 resultCode, resultData, map, requiredPermission, serialized,
11257 sticky, callingPid, callingUid);
11258 Binder.restoreCallingIdentity(origId);
11259 return res;
11260 }
11261 }
11262
11263 int broadcastIntentInPackage(String packageName, int uid,
11264 Intent intent, String resolvedType, IIntentReceiver resultTo,
11265 int resultCode, String resultData, Bundle map,
11266 String requiredPermission, boolean serialized, boolean sticky) {
11267 synchronized(this) {
11268 final long origId = Binder.clearCallingIdentity();
11269 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11270 resultTo, resultCode, resultData, map, requiredPermission,
11271 serialized, sticky, -1, uid);
11272 Binder.restoreCallingIdentity(origId);
11273 return res;
11274 }
11275 }
11276
11277 public final void unbroadcastIntent(IApplicationThread caller,
11278 Intent intent) {
11279 // Refuse possible leaked file descriptors
11280 if (intent != null && intent.hasFileDescriptors() == true) {
11281 throw new IllegalArgumentException("File descriptors passed in Intent");
11282 }
11283
11284 synchronized(this) {
11285 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11286 != PackageManager.PERMISSION_GRANTED) {
11287 String msg = "Permission Denial: unbroadcastIntent() from pid="
11288 + Binder.getCallingPid()
11289 + ", uid=" + Binder.getCallingUid()
11290 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11291 Log.w(TAG, msg);
11292 throw new SecurityException(msg);
11293 }
11294 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11295 if (list != null) {
11296 int N = list.size();
11297 int i;
11298 for (i=0; i<N; i++) {
11299 if (intent.filterEquals(list.get(i))) {
11300 list.remove(i);
11301 break;
11302 }
11303 }
11304 }
11305 }
11306 }
11307
11308 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11309 String resultData, Bundle resultExtras, boolean resultAbort,
11310 boolean explicit) {
11311 if (mOrderedBroadcasts.size() == 0) {
11312 if (explicit) {
11313 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11314 }
11315 return false;
11316 }
11317 BroadcastRecord r = mOrderedBroadcasts.get(0);
11318 if (r.receiver == null) {
11319 if (explicit) {
11320 Log.w(TAG, "finishReceiver called but none active");
11321 }
11322 return false;
11323 }
11324 if (r.receiver != receiver) {
11325 Log.w(TAG, "finishReceiver called but active receiver is different");
11326 return false;
11327 }
11328 int state = r.state;
11329 r.state = r.IDLE;
11330 if (state == r.IDLE) {
11331 if (explicit) {
11332 Log.w(TAG, "finishReceiver called but state is IDLE");
11333 }
11334 }
11335 r.receiver = null;
11336 r.intent.setComponent(null);
11337 if (r.curApp != null) {
11338 r.curApp.curReceiver = null;
11339 }
11340 if (r.curFilter != null) {
11341 r.curFilter.receiverList.curBroadcast = null;
11342 }
11343 r.curFilter = null;
11344 r.curApp = null;
11345 r.curComponent = null;
11346 r.curReceiver = null;
11347 mPendingBroadcast = null;
11348
11349 r.resultCode = resultCode;
11350 r.resultData = resultData;
11351 r.resultExtras = resultExtras;
11352 r.resultAbort = resultAbort;
11353
11354 // We will process the next receiver right now if this is finishing
11355 // an app receiver (which is always asynchronous) or after we have
11356 // come back from calling a receiver.
11357 return state == BroadcastRecord.APP_RECEIVE
11358 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11359 }
11360
11361 public void finishReceiver(IBinder who, int resultCode, String resultData,
11362 Bundle resultExtras, boolean resultAbort) {
11363 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11364
11365 // Refuse possible leaked file descriptors
11366 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11367 throw new IllegalArgumentException("File descriptors passed in Bundle");
11368 }
11369
11370 boolean doNext;
11371
11372 final long origId = Binder.clearCallingIdentity();
11373
11374 synchronized(this) {
11375 doNext = finishReceiverLocked(
11376 who, resultCode, resultData, resultExtras, resultAbort, true);
11377 }
11378
11379 if (doNext) {
11380 processNextBroadcast(false);
11381 }
11382 trimApplications();
11383
11384 Binder.restoreCallingIdentity(origId);
11385 }
11386
11387 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11388 if (r.nextReceiver > 0) {
11389 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11390 if (curReceiver instanceof BroadcastFilter) {
11391 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11392 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11393 System.identityHashCode(r),
11394 r.intent.getAction(),
11395 r.nextReceiver - 1,
11396 System.identityHashCode(bf));
11397 } else {
11398 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11399 System.identityHashCode(r),
11400 r.intent.getAction(),
11401 r.nextReceiver - 1,
11402 ((ResolveInfo)curReceiver).toString());
11403 }
11404 } else {
11405 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11406 + r);
11407 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11408 System.identityHashCode(r),
11409 r.intent.getAction(),
11410 r.nextReceiver,
11411 "NONE");
11412 }
11413 }
11414
11415 private final void broadcastTimeout() {
11416 synchronized (this) {
11417 if (mOrderedBroadcasts.size() == 0) {
11418 return;
11419 }
11420 long now = SystemClock.uptimeMillis();
11421 BroadcastRecord r = mOrderedBroadcasts.get(0);
11422 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11423 if (DEBUG_BROADCAST) Log.v(TAG,
11424 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11425 + (r.startTime + BROADCAST_TIMEOUT));
11426 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11427 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11428 return;
11429 }
11430
11431 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11432 r.startTime = now;
11433 r.anrCount++;
11434
11435 // Current receiver has passed its expiration date.
11436 if (r.nextReceiver <= 0) {
11437 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11438 return;
11439 }
11440
11441 ProcessRecord app = null;
11442
11443 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11444 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11445 logBroadcastReceiverDiscard(r);
11446 if (curReceiver instanceof BroadcastFilter) {
11447 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11448 if (bf.receiverList.pid != 0
11449 && bf.receiverList.pid != MY_PID) {
11450 synchronized (this.mPidsSelfLocked) {
11451 app = this.mPidsSelfLocked.get(
11452 bf.receiverList.pid);
11453 }
11454 }
11455 } else {
11456 app = r.curApp;
11457 }
11458
11459 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011460 appNotRespondingLocked(app, null, null,
11461 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011462 }
11463
11464 if (mPendingBroadcast == r) {
11465 mPendingBroadcast = null;
11466 }
11467
11468 // Move on to the next receiver.
11469 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11470 r.resultExtras, r.resultAbort, true);
11471 scheduleBroadcastsLocked();
11472 }
11473 }
11474
11475 private final void processCurBroadcastLocked(BroadcastRecord r,
11476 ProcessRecord app) throws RemoteException {
11477 if (app.thread == null) {
11478 throw new RemoteException();
11479 }
11480 r.receiver = app.thread.asBinder();
11481 r.curApp = app;
11482 app.curReceiver = r;
11483 updateLRUListLocked(app, true);
11484
11485 // Tell the application to launch this receiver.
11486 r.intent.setComponent(r.curComponent);
11487
11488 boolean started = false;
11489 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011490 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011491 "Delivering to component " + r.curComponent
11492 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011493 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011494 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11495 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11496 started = true;
11497 } finally {
11498 if (!started) {
11499 r.receiver = null;
11500 r.curApp = null;
11501 app.curReceiver = null;
11502 }
11503 }
11504
11505 }
11506
11507 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11508 Intent intent, int resultCode, String data,
11509 Bundle extras, boolean ordered) throws RemoteException {
11510 if (app != null && app.thread != null) {
11511 // If we have an app thread, do the call through that so it is
11512 // correctly ordered with other one-way calls.
11513 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11514 data, extras, ordered);
11515 } else {
11516 receiver.performReceive(intent, resultCode, data, extras, ordered);
11517 }
11518 }
11519
11520 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11521 BroadcastFilter filter, boolean ordered) {
11522 boolean skip = false;
11523 if (filter.requiredPermission != null) {
11524 int perm = checkComponentPermission(filter.requiredPermission,
11525 r.callingPid, r.callingUid, -1);
11526 if (perm != PackageManager.PERMISSION_GRANTED) {
11527 Log.w(TAG, "Permission Denial: broadcasting "
11528 + r.intent.toString()
11529 + " from " + r.callerPackage + " (pid="
11530 + r.callingPid + ", uid=" + r.callingUid + ")"
11531 + " requires " + filter.requiredPermission
11532 + " due to registered receiver " + filter);
11533 skip = true;
11534 }
11535 }
11536 if (r.requiredPermission != null) {
11537 int perm = checkComponentPermission(r.requiredPermission,
11538 filter.receiverList.pid, filter.receiverList.uid, -1);
11539 if (perm != PackageManager.PERMISSION_GRANTED) {
11540 Log.w(TAG, "Permission Denial: receiving "
11541 + r.intent.toString()
11542 + " to " + filter.receiverList.app
11543 + " (pid=" + filter.receiverList.pid
11544 + ", uid=" + filter.receiverList.uid + ")"
11545 + " requires " + r.requiredPermission
11546 + " due to sender " + r.callerPackage
11547 + " (uid " + r.callingUid + ")");
11548 skip = true;
11549 }
11550 }
11551
11552 if (!skip) {
11553 // If this is not being sent as an ordered broadcast, then we
11554 // don't want to touch the fields that keep track of the current
11555 // state of ordered broadcasts.
11556 if (ordered) {
11557 r.receiver = filter.receiverList.receiver.asBinder();
11558 r.curFilter = filter;
11559 filter.receiverList.curBroadcast = r;
11560 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011561 if (filter.receiverList.app != null) {
11562 // Bump hosting application to no longer be in background
11563 // scheduling class. Note that we can't do that if there
11564 // isn't an app... but we can only be in that case for
11565 // things that directly call the IActivityManager API, which
11566 // are already core system stuff so don't matter for this.
11567 r.curApp = filter.receiverList.app;
11568 filter.receiverList.app.curReceiver = r;
11569 updateOomAdjLocked();
11570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011571 }
11572 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011573 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011574 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011575 Log.i(TAG, "Delivering to " + filter.receiverList.app
11576 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011577 }
11578 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11579 new Intent(r.intent), r.resultCode,
11580 r.resultData, r.resultExtras, r.ordered);
11581 if (ordered) {
11582 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11583 }
11584 } catch (RemoteException e) {
11585 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11586 if (ordered) {
11587 r.receiver = null;
11588 r.curFilter = null;
11589 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011590 if (filter.receiverList.app != null) {
11591 filter.receiverList.app.curReceiver = null;
11592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011593 }
11594 }
11595 }
11596 }
11597
11598 private final void processNextBroadcast(boolean fromMsg) {
11599 synchronized(this) {
11600 BroadcastRecord r;
11601
11602 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11603 + mParallelBroadcasts.size() + " broadcasts, "
11604 + mOrderedBroadcasts.size() + " serialized broadcasts");
11605
11606 updateCpuStats();
11607
11608 if (fromMsg) {
11609 mBroadcastsScheduled = false;
11610 }
11611
11612 // First, deliver any non-serialized broadcasts right away.
11613 while (mParallelBroadcasts.size() > 0) {
11614 r = mParallelBroadcasts.remove(0);
11615 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011616 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11617 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011618 for (int i=0; i<N; i++) {
11619 Object target = r.receivers.get(i);
11620 if (DEBUG_BROADCAST) Log.v(TAG,
11621 "Delivering non-serialized to registered "
11622 + target + ": " + r);
11623 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11624 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011625 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11626 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011627 }
11628
11629 // Now take care of the next serialized one...
11630
11631 // If we are waiting for a process to come up to handle the next
11632 // broadcast, then do nothing at this point. Just in case, we
11633 // check that the process we're waiting for still exists.
11634 if (mPendingBroadcast != null) {
11635 Log.i(TAG, "processNextBroadcast: waiting for "
11636 + mPendingBroadcast.curApp);
11637
11638 boolean isDead;
11639 synchronized (mPidsSelfLocked) {
11640 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11641 }
11642 if (!isDead) {
11643 // It's still alive, so keep waiting
11644 return;
11645 } else {
11646 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11647 + " died before responding to broadcast");
11648 mPendingBroadcast = null;
11649 }
11650 }
11651
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011652 boolean looped = false;
11653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011654 do {
11655 if (mOrderedBroadcasts.size() == 0) {
11656 // No more broadcasts pending, so all done!
11657 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011658 if (looped) {
11659 // If we had finished the last ordered broadcast, then
11660 // make sure all processes have correct oom and sched
11661 // adjustments.
11662 updateOomAdjLocked();
11663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011664 return;
11665 }
11666 r = mOrderedBroadcasts.get(0);
11667 boolean forceReceive = false;
11668
11669 // Ensure that even if something goes awry with the timeout
11670 // detection, we catch "hung" broadcasts here, discard them,
11671 // and continue to make progress.
11672 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11673 long now = SystemClock.uptimeMillis();
11674 if (r.dispatchTime > 0) {
11675 if ((numReceivers > 0) &&
11676 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11677 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11678 + " now=" + now
11679 + " dispatchTime=" + r.dispatchTime
11680 + " startTime=" + r.startTime
11681 + " intent=" + r.intent
11682 + " numReceivers=" + numReceivers
11683 + " nextReceiver=" + r.nextReceiver
11684 + " state=" + r.state);
11685 broadcastTimeout(); // forcibly finish this broadcast
11686 forceReceive = true;
11687 r.state = BroadcastRecord.IDLE;
11688 }
11689 }
11690
11691 if (r.state != BroadcastRecord.IDLE) {
11692 if (DEBUG_BROADCAST) Log.d(TAG,
11693 "processNextBroadcast() called when not idle (state="
11694 + r.state + ")");
11695 return;
11696 }
11697
11698 if (r.receivers == null || r.nextReceiver >= numReceivers
11699 || r.resultAbort || forceReceive) {
11700 // No more receivers for this broadcast! Send the final
11701 // result if requested...
11702 if (r.resultTo != null) {
11703 try {
11704 if (DEBUG_BROADCAST) {
11705 int seq = r.intent.getIntExtra("seq", -1);
11706 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11707 + " seq=" + seq + " app=" + r.callerApp);
11708 }
11709 performReceive(r.callerApp, r.resultTo,
11710 new Intent(r.intent), r.resultCode,
11711 r.resultData, r.resultExtras, false);
11712 } catch (RemoteException e) {
11713 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11714 }
11715 }
11716
11717 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11718 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11719
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011720 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11721 + r);
11722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011723 // ... and on to the next...
11724 mOrderedBroadcasts.remove(0);
11725 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011726 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011727 continue;
11728 }
11729 } while (r == null);
11730
11731 // Get the next receiver...
11732 int recIdx = r.nextReceiver++;
11733
11734 // Keep track of when this receiver started, and make sure there
11735 // is a timeout message pending to kill it if need be.
11736 r.startTime = SystemClock.uptimeMillis();
11737 if (recIdx == 0) {
11738 r.dispatchTime = r.startTime;
11739
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011740 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11741 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011742 if (DEBUG_BROADCAST) Log.v(TAG,
11743 "Submitting BROADCAST_TIMEOUT_MSG for "
11744 + (r.startTime + BROADCAST_TIMEOUT));
11745 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11746 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11747 }
11748
11749 Object nextReceiver = r.receivers.get(recIdx);
11750 if (nextReceiver instanceof BroadcastFilter) {
11751 // Simple case: this is a registered receiver who gets
11752 // a direct call.
11753 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11754 if (DEBUG_BROADCAST) Log.v(TAG,
11755 "Delivering serialized to registered "
11756 + filter + ": " + r);
11757 deliverToRegisteredReceiver(r, filter, r.ordered);
11758 if (r.receiver == null || !r.ordered) {
11759 // The receiver has already finished, so schedule to
11760 // process the next one.
11761 r.state = BroadcastRecord.IDLE;
11762 scheduleBroadcastsLocked();
11763 }
11764 return;
11765 }
11766
11767 // Hard case: need to instantiate the receiver, possibly
11768 // starting its application process to host it.
11769
11770 ResolveInfo info =
11771 (ResolveInfo)nextReceiver;
11772
11773 boolean skip = false;
11774 int perm = checkComponentPermission(info.activityInfo.permission,
11775 r.callingPid, r.callingUid,
11776 info.activityInfo.exported
11777 ? -1 : info.activityInfo.applicationInfo.uid);
11778 if (perm != PackageManager.PERMISSION_GRANTED) {
11779 Log.w(TAG, "Permission Denial: broadcasting "
11780 + r.intent.toString()
11781 + " from " + r.callerPackage + " (pid=" + r.callingPid
11782 + ", uid=" + r.callingUid + ")"
11783 + " requires " + info.activityInfo.permission
11784 + " due to receiver " + info.activityInfo.packageName
11785 + "/" + info.activityInfo.name);
11786 skip = true;
11787 }
11788 if (r.callingUid != Process.SYSTEM_UID &&
11789 r.requiredPermission != null) {
11790 try {
11791 perm = ActivityThread.getPackageManager().
11792 checkPermission(r.requiredPermission,
11793 info.activityInfo.applicationInfo.packageName);
11794 } catch (RemoteException e) {
11795 perm = PackageManager.PERMISSION_DENIED;
11796 }
11797 if (perm != PackageManager.PERMISSION_GRANTED) {
11798 Log.w(TAG, "Permission Denial: receiving "
11799 + r.intent + " to "
11800 + info.activityInfo.applicationInfo.packageName
11801 + " requires " + r.requiredPermission
11802 + " due to sender " + r.callerPackage
11803 + " (uid " + r.callingUid + ")");
11804 skip = true;
11805 }
11806 }
11807 if (r.curApp != null && r.curApp.crashing) {
11808 // If the target process is crashing, just skip it.
11809 skip = true;
11810 }
11811
11812 if (skip) {
11813 r.receiver = null;
11814 r.curFilter = null;
11815 r.state = BroadcastRecord.IDLE;
11816 scheduleBroadcastsLocked();
11817 return;
11818 }
11819
11820 r.state = BroadcastRecord.APP_RECEIVE;
11821 String targetProcess = info.activityInfo.processName;
11822 r.curComponent = new ComponentName(
11823 info.activityInfo.applicationInfo.packageName,
11824 info.activityInfo.name);
11825 r.curReceiver = info.activityInfo;
11826
11827 // Is this receiver's application already running?
11828 ProcessRecord app = getProcessRecordLocked(targetProcess,
11829 info.activityInfo.applicationInfo.uid);
11830 if (app != null && app.thread != null) {
11831 try {
11832 processCurBroadcastLocked(r, app);
11833 return;
11834 } catch (RemoteException e) {
11835 Log.w(TAG, "Exception when sending broadcast to "
11836 + r.curComponent, e);
11837 }
11838
11839 // If a dead object exception was thrown -- fall through to
11840 // restart the application.
11841 }
11842
11843 // Not running -- get it started, and enqueue this history record
11844 // to be executed when the app comes up.
11845 if ((r.curApp=startProcessLocked(targetProcess,
11846 info.activityInfo.applicationInfo, true,
11847 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11848 "broadcast", r.curComponent)) == null) {
11849 // Ah, this recipient is unavailable. Finish it if necessary,
11850 // and mark the broadcast record as ready for the next.
11851 Log.w(TAG, "Unable to launch app "
11852 + info.activityInfo.applicationInfo.packageName + "/"
11853 + info.activityInfo.applicationInfo.uid + " for broadcast "
11854 + r.intent + ": process is bad");
11855 logBroadcastReceiverDiscard(r);
11856 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11857 r.resultExtras, r.resultAbort, true);
11858 scheduleBroadcastsLocked();
11859 r.state = BroadcastRecord.IDLE;
11860 return;
11861 }
11862
11863 mPendingBroadcast = r;
11864 }
11865 }
11866
11867 // =========================================================
11868 // INSTRUMENTATION
11869 // =========================================================
11870
11871 public boolean startInstrumentation(ComponentName className,
11872 String profileFile, int flags, Bundle arguments,
11873 IInstrumentationWatcher watcher) {
11874 // Refuse possible leaked file descriptors
11875 if (arguments != null && arguments.hasFileDescriptors()) {
11876 throw new IllegalArgumentException("File descriptors passed in Bundle");
11877 }
11878
11879 synchronized(this) {
11880 InstrumentationInfo ii = null;
11881 ApplicationInfo ai = null;
11882 try {
11883 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011884 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011885 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011886 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011887 } catch (PackageManager.NameNotFoundException e) {
11888 }
11889 if (ii == null) {
11890 reportStartInstrumentationFailure(watcher, className,
11891 "Unable to find instrumentation info for: " + className);
11892 return false;
11893 }
11894 if (ai == null) {
11895 reportStartInstrumentationFailure(watcher, className,
11896 "Unable to find instrumentation target package: " + ii.targetPackage);
11897 return false;
11898 }
11899
11900 int match = mContext.getPackageManager().checkSignatures(
11901 ii.targetPackage, ii.packageName);
11902 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11903 String msg = "Permission Denial: starting instrumentation "
11904 + className + " from pid="
11905 + Binder.getCallingPid()
11906 + ", uid=" + Binder.getCallingPid()
11907 + " not allowed because package " + ii.packageName
11908 + " does not have a signature matching the target "
11909 + ii.targetPackage;
11910 reportStartInstrumentationFailure(watcher, className, msg);
11911 throw new SecurityException(msg);
11912 }
11913
11914 final long origId = Binder.clearCallingIdentity();
11915 uninstallPackageLocked(ii.targetPackage, -1, true);
11916 ProcessRecord app = addAppLocked(ai);
11917 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011918 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011919 app.instrumentationProfileFile = profileFile;
11920 app.instrumentationArguments = arguments;
11921 app.instrumentationWatcher = watcher;
11922 app.instrumentationResultClass = className;
11923 Binder.restoreCallingIdentity(origId);
11924 }
11925
11926 return true;
11927 }
11928
11929 /**
11930 * Report errors that occur while attempting to start Instrumentation. Always writes the
11931 * error to the logs, but if somebody is watching, send the report there too. This enables
11932 * the "am" command to report errors with more information.
11933 *
11934 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11935 * @param cn The component name of the instrumentation.
11936 * @param report The error report.
11937 */
11938 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11939 ComponentName cn, String report) {
11940 Log.w(TAG, report);
11941 try {
11942 if (watcher != null) {
11943 Bundle results = new Bundle();
11944 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11945 results.putString("Error", report);
11946 watcher.instrumentationStatus(cn, -1, results);
11947 }
11948 } catch (RemoteException e) {
11949 Log.w(TAG, e);
11950 }
11951 }
11952
11953 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11954 if (app.instrumentationWatcher != null) {
11955 try {
11956 // NOTE: IInstrumentationWatcher *must* be oneway here
11957 app.instrumentationWatcher.instrumentationFinished(
11958 app.instrumentationClass,
11959 resultCode,
11960 results);
11961 } catch (RemoteException e) {
11962 }
11963 }
11964 app.instrumentationWatcher = null;
11965 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011966 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011967 app.instrumentationProfileFile = null;
11968 app.instrumentationArguments = null;
11969
11970 uninstallPackageLocked(app.processName, -1, false);
11971 }
11972
11973 public void finishInstrumentation(IApplicationThread target,
11974 int resultCode, Bundle results) {
11975 // Refuse possible leaked file descriptors
11976 if (results != null && results.hasFileDescriptors()) {
11977 throw new IllegalArgumentException("File descriptors passed in Intent");
11978 }
11979
11980 synchronized(this) {
11981 ProcessRecord app = getRecordForAppLocked(target);
11982 if (app == null) {
11983 Log.w(TAG, "finishInstrumentation: no app for " + target);
11984 return;
11985 }
11986 final long origId = Binder.clearCallingIdentity();
11987 finishInstrumentationLocked(app, resultCode, results);
11988 Binder.restoreCallingIdentity(origId);
11989 }
11990 }
11991
11992 // =========================================================
11993 // CONFIGURATION
11994 // =========================================================
11995
11996 public ConfigurationInfo getDeviceConfigurationInfo() {
11997 ConfigurationInfo config = new ConfigurationInfo();
11998 synchronized (this) {
11999 config.reqTouchScreen = mConfiguration.touchscreen;
12000 config.reqKeyboardType = mConfiguration.keyboard;
12001 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012002 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12003 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012004 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12005 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012006 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12007 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012008 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12009 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012010 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012011 }
12012 return config;
12013 }
12014
12015 public Configuration getConfiguration() {
12016 Configuration ci;
12017 synchronized(this) {
12018 ci = new Configuration(mConfiguration);
12019 }
12020 return ci;
12021 }
12022
12023 public void updateConfiguration(Configuration values) {
12024 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12025 "updateConfiguration()");
12026
12027 synchronized(this) {
12028 if (values == null && mWindowManager != null) {
12029 // sentinel: fetch the current configuration from the window manager
12030 values = mWindowManager.computeNewConfiguration();
12031 }
12032
12033 final long origId = Binder.clearCallingIdentity();
12034 updateConfigurationLocked(values, null);
12035 Binder.restoreCallingIdentity(origId);
12036 }
12037 }
12038
12039 /**
12040 * Do either or both things: (1) change the current configuration, and (2)
12041 * make sure the given activity is running with the (now) current
12042 * configuration. Returns true if the activity has been left running, or
12043 * false if <var>starting</var> is being destroyed to match the new
12044 * configuration.
12045 */
12046 public boolean updateConfigurationLocked(Configuration values,
12047 HistoryRecord starting) {
12048 int changes = 0;
12049
12050 boolean kept = true;
12051
12052 if (values != null) {
12053 Configuration newConfig = new Configuration(mConfiguration);
12054 changes = newConfig.updateFrom(values);
12055 if (changes != 0) {
12056 if (DEBUG_SWITCH) {
12057 Log.i(TAG, "Updating configuration to: " + values);
12058 }
12059
12060 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12061
12062 if (values.locale != null) {
12063 saveLocaleLocked(values.locale,
12064 !values.locale.equals(mConfiguration.locale),
12065 values.userSetLocale);
12066 }
12067
12068 mConfiguration = newConfig;
12069
12070 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12071 msg.obj = new Configuration(mConfiguration);
12072 mHandler.sendMessage(msg);
12073
12074 final int N = mLRUProcesses.size();
12075 for (int i=0; i<N; i++) {
12076 ProcessRecord app = mLRUProcesses.get(i);
12077 try {
12078 if (app.thread != null) {
12079 app.thread.scheduleConfigurationChanged(mConfiguration);
12080 }
12081 } catch (Exception e) {
12082 }
12083 }
12084 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12085 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12086 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012087
12088 AttributeCache ac = AttributeCache.instance();
12089 if (ac != null) {
12090 ac.updateConfiguration(mConfiguration);
12091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012092 }
12093 }
12094
12095 if (changes != 0 && starting == null) {
12096 // If the configuration changed, and the caller is not already
12097 // in the process of starting an activity, then find the top
12098 // activity to check if its configuration needs to change.
12099 starting = topRunningActivityLocked(null);
12100 }
12101
12102 if (starting != null) {
12103 kept = ensureActivityConfigurationLocked(starting, changes);
12104 if (kept) {
12105 // If this didn't result in the starting activity being
12106 // destroyed, then we need to make sure at this point that all
12107 // other activities are made visible.
12108 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12109 + ", ensuring others are correct.");
12110 ensureActivitiesVisibleLocked(starting, changes);
12111 }
12112 }
12113
12114 return kept;
12115 }
12116
12117 private final boolean relaunchActivityLocked(HistoryRecord r,
12118 int changes, boolean andResume) {
12119 List<ResultInfo> results = null;
12120 List<Intent> newIntents = null;
12121 if (andResume) {
12122 results = r.results;
12123 newIntents = r.newIntents;
12124 }
12125 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12126 + " with results=" + results + " newIntents=" + newIntents
12127 + " andResume=" + andResume);
12128 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12129 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12130 r.task.taskId, r.shortComponentName);
12131
12132 r.startFreezingScreenLocked(r.app, 0);
12133
12134 try {
12135 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12136 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12137 changes, !andResume);
12138 // Note: don't need to call pauseIfSleepingLocked() here, because
12139 // the caller will only pass in 'andResume' if this activity is
12140 // currently resumed, which implies we aren't sleeping.
12141 } catch (RemoteException e) {
12142 return false;
12143 }
12144
12145 if (andResume) {
12146 r.results = null;
12147 r.newIntents = null;
12148 }
12149
12150 return true;
12151 }
12152
12153 /**
12154 * Make sure the given activity matches the current configuration. Returns
12155 * false if the activity had to be destroyed. Returns true if the
12156 * configuration is the same, or the activity will remain running as-is
12157 * for whatever reason. Ensures the HistoryRecord is updated with the
12158 * correct configuration and all other bookkeeping is handled.
12159 */
12160 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12161 int globalChanges) {
12162 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12163
12164 // Short circuit: if the two configurations are the exact same
12165 // object (the common case), then there is nothing to do.
12166 Configuration newConfig = mConfiguration;
12167 if (r.configuration == newConfig) {
12168 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12169 return true;
12170 }
12171
12172 // We don't worry about activities that are finishing.
12173 if (r.finishing) {
12174 if (DEBUG_SWITCH) Log.i(TAG,
12175 "Configuration doesn't matter in finishing " + r);
12176 r.stopFreezingScreenLocked(false);
12177 return true;
12178 }
12179
12180 // Okay we now are going to make this activity have the new config.
12181 // But then we need to figure out how it needs to deal with that.
12182 Configuration oldConfig = r.configuration;
12183 r.configuration = newConfig;
12184
12185 // If the activity isn't currently running, just leave the new
12186 // configuration and it will pick that up next time it starts.
12187 if (r.app == null || r.app.thread == null) {
12188 if (DEBUG_SWITCH) Log.i(TAG,
12189 "Configuration doesn't matter not running " + r);
12190 r.stopFreezingScreenLocked(false);
12191 return true;
12192 }
12193
12194 // If the activity isn't persistent, there is a chance we will
12195 // need to restart it.
12196 if (!r.persistent) {
12197
12198 // Figure out what has changed between the two configurations.
12199 int changes = oldConfig.diff(newConfig);
12200 if (DEBUG_SWITCH) {
12201 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12202 + Integer.toHexString(changes) + ", handles=0x"
12203 + Integer.toHexString(r.info.configChanges));
12204 }
12205 if ((changes&(~r.info.configChanges)) != 0) {
12206 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12207 r.configChangeFlags |= changes;
12208 r.startFreezingScreenLocked(r.app, globalChanges);
12209 if (r.app == null || r.app.thread == null) {
12210 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12211 destroyActivityLocked(r, true);
12212 } else if (r.state == ActivityState.PAUSING) {
12213 // A little annoying: we are waiting for this activity to
12214 // finish pausing. Let's not do anything now, but just
12215 // flag that it needs to be restarted when done pausing.
12216 r.configDestroy = true;
12217 return true;
12218 } else if (r.state == ActivityState.RESUMED) {
12219 // Try to optimize this case: the configuration is changing
12220 // and we need to restart the top, resumed activity.
12221 // Instead of doing the normal handshaking, just say
12222 // "restart!".
12223 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12224 relaunchActivityLocked(r, r.configChangeFlags, true);
12225 r.configChangeFlags = 0;
12226 } else {
12227 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12228 relaunchActivityLocked(r, r.configChangeFlags, false);
12229 r.configChangeFlags = 0;
12230 }
12231
12232 // All done... tell the caller we weren't able to keep this
12233 // activity around.
12234 return false;
12235 }
12236 }
12237
12238 // Default case: the activity can handle this new configuration, so
12239 // hand it over. Note that we don't need to give it the new
12240 // configuration, since we always send configuration changes to all
12241 // process when they happen so it can just use whatever configuration
12242 // it last got.
12243 if (r.app != null && r.app.thread != null) {
12244 try {
12245 r.app.thread.scheduleActivityConfigurationChanged(r);
12246 } catch (RemoteException e) {
12247 // If process died, whatever.
12248 }
12249 }
12250 r.stopFreezingScreenLocked(false);
12251
12252 return true;
12253 }
12254
12255 /**
12256 * Save the locale. You must be inside a synchronized (this) block.
12257 */
12258 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12259 if(isDiff) {
12260 SystemProperties.set("user.language", l.getLanguage());
12261 SystemProperties.set("user.region", l.getCountry());
12262 }
12263
12264 if(isPersist) {
12265 SystemProperties.set("persist.sys.language", l.getLanguage());
12266 SystemProperties.set("persist.sys.country", l.getCountry());
12267 SystemProperties.set("persist.sys.localevar", l.getVariant());
12268 }
12269 }
12270
12271 // =========================================================
12272 // LIFETIME MANAGEMENT
12273 // =========================================================
12274
12275 private final int computeOomAdjLocked(
12276 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12277 if (mAdjSeq == app.adjSeq) {
12278 // This adjustment has already been computed.
12279 return app.curAdj;
12280 }
12281
12282 if (app.thread == null) {
12283 app.adjSeq = mAdjSeq;
12284 return (app.curAdj=EMPTY_APP_ADJ);
12285 }
12286
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012287 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12288 // The max adjustment doesn't allow this app to be anything
12289 // below foreground, so it is not worth doing work for it.
12290 app.adjType = "fixed";
12291 app.adjSeq = mAdjSeq;
12292 app.curRawAdj = app.maxAdj;
12293 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12294 return (app.curAdj=app.maxAdj);
12295 }
12296
12297 app.adjSource = null;
12298 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012299
The Android Open Source Project4df24232009-03-05 14:34:35 -080012300 // Determine the importance of the process, starting with most
12301 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012302 int adj;
12303 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012304 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012305 // The last app on the list is the foreground app.
12306 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012307 app.adjType = "top";
12308 } else if (app.instrumentationClass != null) {
12309 // Don't want to kill running instrumentation.
12310 adj = FOREGROUND_APP_ADJ;
12311 app.adjType = "instr";
12312 } else if (app.persistentActivities > 0) {
12313 // Special persistent activities... shouldn't be used these days.
12314 adj = FOREGROUND_APP_ADJ;
12315 app.adjType = "pers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012316 } else if (app.curReceiver != null ||
12317 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12318 // An app that is currently receiving a broadcast also
12319 // counts as being in the foreground.
12320 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012321 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012322 } else if (app.executingServices.size() > 0) {
12323 // An app that is currently executing a service callback also
12324 // counts as being in the foreground.
12325 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012326 app.adjType = "exec-service";
12327 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012328 // The user is aware of this app, so make it visible.
12329 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012330 app.adjType = "foreground-service";
12331 } else if (app.forcingToForeground != null) {
12332 // The user is aware of this app, so make it visible.
12333 adj = VISIBLE_APP_ADJ;
12334 app.adjType = "force-foreground";
12335 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012336 } else if (app == mHomeProcess) {
12337 // This process is hosting what we currently consider to be the
12338 // home app, so we don't want to let it go into the background.
12339 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012340 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012341 } else if ((N=app.activities.size()) != 0) {
12342 // This app is in the background with paused activities.
12343 adj = hiddenAdj;
12344 for (int j=0; j<N; j++) {
12345 if (((HistoryRecord)app.activities.get(j)).visible) {
12346 // This app has a visible activity!
12347 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012348 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012349 break;
12350 }
12351 }
12352 } else {
12353 // A very not-needed process.
12354 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012355 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012356 }
12357
The Android Open Source Project4df24232009-03-05 14:34:35 -080012358 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012359 // there are applications dependent on our services or providers, but
12360 // this gives us a baseline and makes sure we don't get into an
12361 // infinite recursion.
12362 app.adjSeq = mAdjSeq;
12363 app.curRawAdj = adj;
12364 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12365
Christopher Tate6fa95972009-06-05 18:43:55 -070012366 if (mBackupTarget != null && app == mBackupTarget.app) {
12367 // If possible we want to avoid killing apps while they're being backed up
12368 if (adj > BACKUP_APP_ADJ) {
12369 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12370 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012371 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012372 }
12373 }
12374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012375 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12376 // If this process has active services running in it, we would
12377 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012378 // application from running. By default we put the process in
12379 // with the rest of the background processes; as we scan through
12380 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012381 if (adj > hiddenAdj) {
12382 adj = hiddenAdj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012383 app.adjType = "services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012384 }
12385 final long now = SystemClock.uptimeMillis();
12386 // This process is more important if the top activity is
12387 // bound to the service.
12388 Iterator jt = app.services.iterator();
12389 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12390 ServiceRecord s = (ServiceRecord)jt.next();
12391 if (s.startRequested) {
12392 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12393 // This service has seen some activity within
12394 // recent memory, so we will keep its process ahead
12395 // of the background processes.
12396 if (adj > SECONDARY_SERVER_ADJ) {
12397 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012398 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012399 }
12400 }
12401 }
12402 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12403 Iterator<ConnectionRecord> kt
12404 = s.connections.values().iterator();
12405 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12406 // XXX should compute this based on the max of
12407 // all connected clients.
12408 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012409 if (cr.binding.client == app) {
12410 // Binding to ourself is not interesting.
12411 continue;
12412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012413 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12414 ProcessRecord client = cr.binding.client;
12415 int myHiddenAdj = hiddenAdj;
12416 if (myHiddenAdj > client.hiddenAdj) {
12417 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12418 myHiddenAdj = client.hiddenAdj;
12419 } else {
12420 myHiddenAdj = VISIBLE_APP_ADJ;
12421 }
12422 }
12423 int clientAdj = computeOomAdjLocked(
12424 client, myHiddenAdj, TOP_APP);
12425 if (adj > clientAdj) {
12426 adj = clientAdj > VISIBLE_APP_ADJ
12427 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012428 app.adjType = "service";
12429 app.adjSource = cr.binding.client;
12430 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012431 }
12432 }
12433 HistoryRecord a = cr.activity;
12434 //if (a != null) {
12435 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12436 //}
12437 if (a != null && adj > FOREGROUND_APP_ADJ &&
12438 (a.state == ActivityState.RESUMED
12439 || a.state == ActivityState.PAUSING)) {
12440 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012441 app.adjType = "service";
12442 app.adjSource = a;
12443 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012444 }
12445 }
12446 }
12447 }
12448 }
12449
12450 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12451 // If this process has published any content providers, then
12452 // its adjustment makes it at least as important as any of the
12453 // processes using those providers, and no less important than
12454 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12455 if (adj > CONTENT_PROVIDER_ADJ) {
12456 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012457 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012458 }
12459 Iterator jt = app.pubProviders.values().iterator();
12460 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12461 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12462 if (cpr.clients.size() != 0) {
12463 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12464 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12465 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012466 if (client == app) {
12467 // Being our own client is not interesting.
12468 continue;
12469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012470 int myHiddenAdj = hiddenAdj;
12471 if (myHiddenAdj > client.hiddenAdj) {
12472 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12473 myHiddenAdj = client.hiddenAdj;
12474 } else {
12475 myHiddenAdj = FOREGROUND_APP_ADJ;
12476 }
12477 }
12478 int clientAdj = computeOomAdjLocked(
12479 client, myHiddenAdj, TOP_APP);
12480 if (adj > clientAdj) {
12481 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012482 ? clientAdj : FOREGROUND_APP_ADJ;
12483 app.adjType = "provider";
12484 app.adjSource = client;
12485 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012486 }
12487 }
12488 }
12489 // If the provider has external (non-framework) process
12490 // dependencies, ensure that its adjustment is at least
12491 // FOREGROUND_APP_ADJ.
12492 if (cpr.externals != 0) {
12493 if (adj > FOREGROUND_APP_ADJ) {
12494 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012495 app.adjType = "provider";
12496 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012497 }
12498 }
12499 }
12500 }
12501
12502 app.curRawAdj = adj;
12503
12504 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12505 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12506 if (adj > app.maxAdj) {
12507 adj = app.maxAdj;
12508 }
12509
12510 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012511 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012512 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12513 : Process.THREAD_GROUP_DEFAULT;
12514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012515 return adj;
12516 }
12517
12518 /**
12519 * Ask a given process to GC right now.
12520 */
12521 final void performAppGcLocked(ProcessRecord app) {
12522 try {
12523 app.lastRequestedGc = SystemClock.uptimeMillis();
12524 if (app.thread != null) {
12525 app.thread.processInBackground();
12526 }
12527 } catch (Exception e) {
12528 // whatever.
12529 }
12530 }
12531
12532 /**
12533 * Returns true if things are idle enough to perform GCs.
12534 */
12535 private final boolean canGcNow() {
12536 return mParallelBroadcasts.size() == 0
12537 && mOrderedBroadcasts.size() == 0
12538 && (mSleeping || (mResumedActivity != null &&
12539 mResumedActivity.idle));
12540 }
12541
12542 /**
12543 * Perform GCs on all processes that are waiting for it, but only
12544 * if things are idle.
12545 */
12546 final void performAppGcsLocked() {
12547 final int N = mProcessesToGc.size();
12548 if (N <= 0) {
12549 return;
12550 }
12551 if (canGcNow()) {
12552 while (mProcessesToGc.size() > 0) {
12553 ProcessRecord proc = mProcessesToGc.remove(0);
12554 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12555 // To avoid spamming the system, we will GC processes one
12556 // at a time, waiting a few seconds between each.
12557 performAppGcLocked(proc);
12558 scheduleAppGcsLocked();
12559 return;
12560 }
12561 }
12562 }
12563 }
12564
12565 /**
12566 * If all looks good, perform GCs on all processes waiting for them.
12567 */
12568 final void performAppGcsIfAppropriateLocked() {
12569 if (canGcNow()) {
12570 performAppGcsLocked();
12571 return;
12572 }
12573 // Still not idle, wait some more.
12574 scheduleAppGcsLocked();
12575 }
12576
12577 /**
12578 * Schedule the execution of all pending app GCs.
12579 */
12580 final void scheduleAppGcsLocked() {
12581 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12582 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12583 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12584 }
12585
12586 /**
12587 * Set up to ask a process to GC itself. This will either do it
12588 * immediately, or put it on the list of processes to gc the next
12589 * time things are idle.
12590 */
12591 final void scheduleAppGcLocked(ProcessRecord app) {
12592 long now = SystemClock.uptimeMillis();
12593 if ((app.lastRequestedGc+5000) > now) {
12594 return;
12595 }
12596 if (!mProcessesToGc.contains(app)) {
12597 mProcessesToGc.add(app);
12598 scheduleAppGcsLocked();
12599 }
12600 }
12601
12602 private final boolean updateOomAdjLocked(
12603 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12604 app.hiddenAdj = hiddenAdj;
12605
12606 if (app.thread == null) {
12607 return true;
12608 }
12609
12610 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012612 if (app.pid != 0 && app.pid != MY_PID) {
12613 if (app.curRawAdj != app.setRawAdj) {
12614 if (app.curRawAdj > FOREGROUND_APP_ADJ
12615 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12616 // If this app is transitioning from foreground to
12617 // non-foreground, have it do a gc.
12618 scheduleAppGcLocked(app);
12619 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12620 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12621 // Likewise do a gc when an app is moving in to the
12622 // background (such as a service stopping).
12623 scheduleAppGcLocked(app);
12624 }
12625 app.setRawAdj = app.curRawAdj;
12626 }
12627 if (adj != app.setAdj) {
12628 if (Process.setOomAdj(app.pid, adj)) {
12629 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12630 TAG, "Set app " + app.processName +
12631 " oom adj to " + adj);
12632 app.setAdj = adj;
12633 } else {
12634 return false;
12635 }
12636 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012637 if (app.setSchedGroup != app.curSchedGroup) {
12638 app.setSchedGroup = app.curSchedGroup;
12639 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12640 "Setting process group of " + app.processName
12641 + " to " + app.curSchedGroup);
12642 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012643 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012644 try {
12645 Process.setProcessGroup(app.pid, app.curSchedGroup);
12646 } catch (Exception e) {
12647 Log.w(TAG, "Failed setting process group of " + app.pid
12648 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012649 e.printStackTrace();
12650 } finally {
12651 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012652 }
12653 }
12654 if (false) {
12655 if (app.thread != null) {
12656 try {
12657 app.thread.setSchedulingGroup(app.curSchedGroup);
12658 } catch (RemoteException e) {
12659 }
12660 }
12661 }
12662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012663 }
12664
12665 return true;
12666 }
12667
12668 private final HistoryRecord resumedAppLocked() {
12669 HistoryRecord resumedActivity = mResumedActivity;
12670 if (resumedActivity == null || resumedActivity.app == null) {
12671 resumedActivity = mPausingActivity;
12672 if (resumedActivity == null || resumedActivity.app == null) {
12673 resumedActivity = topRunningActivityLocked(null);
12674 }
12675 }
12676 return resumedActivity;
12677 }
12678
12679 private final boolean updateOomAdjLocked(ProcessRecord app) {
12680 final HistoryRecord TOP_ACT = resumedAppLocked();
12681 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12682 int curAdj = app.curAdj;
12683 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12684 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12685
12686 mAdjSeq++;
12687
12688 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12689 if (res) {
12690 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12691 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12692 if (nowHidden != wasHidden) {
12693 // Changed to/from hidden state, so apps after it in the LRU
12694 // list may also be changed.
12695 updateOomAdjLocked();
12696 }
12697 }
12698 return res;
12699 }
12700
12701 private final boolean updateOomAdjLocked() {
12702 boolean didOomAdj = true;
12703 final HistoryRecord TOP_ACT = resumedAppLocked();
12704 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12705
12706 if (false) {
12707 RuntimeException e = new RuntimeException();
12708 e.fillInStackTrace();
12709 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12710 }
12711
12712 mAdjSeq++;
12713
12714 // First try updating the OOM adjustment for each of the
12715 // application processes based on their current state.
12716 int i = mLRUProcesses.size();
12717 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12718 while (i > 0) {
12719 i--;
12720 ProcessRecord app = mLRUProcesses.get(i);
12721 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12722 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12723 && app.curAdj == curHiddenAdj) {
12724 curHiddenAdj++;
12725 }
12726 } else {
12727 didOomAdj = false;
12728 }
12729 }
12730
12731 // todo: for now pretend like OOM ADJ didn't work, because things
12732 // aren't behaving as expected on Linux -- it's not killing processes.
12733 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12734 }
12735
12736 private final void trimApplications() {
12737 synchronized (this) {
12738 int i;
12739
12740 // First remove any unused application processes whose package
12741 // has been removed.
12742 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12743 final ProcessRecord app = mRemovedProcesses.get(i);
12744 if (app.activities.size() == 0
12745 && app.curReceiver == null && app.services.size() == 0) {
12746 Log.i(
12747 TAG, "Exiting empty application process "
12748 + app.processName + " ("
12749 + (app.thread != null ? app.thread.asBinder() : null)
12750 + ")\n");
12751 if (app.pid > 0 && app.pid != MY_PID) {
12752 Process.killProcess(app.pid);
12753 } else {
12754 try {
12755 app.thread.scheduleExit();
12756 } catch (Exception e) {
12757 // Ignore exceptions.
12758 }
12759 }
12760 cleanUpApplicationRecordLocked(app, false, -1);
12761 mRemovedProcesses.remove(i);
12762
12763 if (app.persistent) {
12764 if (app.persistent) {
12765 addAppLocked(app.info);
12766 }
12767 }
12768 }
12769 }
12770
12771 // Now try updating the OOM adjustment for each of the
12772 // application processes based on their current state.
12773 // If the setOomAdj() API is not supported, then go with our
12774 // back-up plan...
12775 if (!updateOomAdjLocked()) {
12776
12777 // Count how many processes are running services.
12778 int numServiceProcs = 0;
12779 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12780 final ProcessRecord app = mLRUProcesses.get(i);
12781
12782 if (app.persistent || app.services.size() != 0
12783 || app.curReceiver != null
12784 || app.persistentActivities > 0) {
12785 // Don't count processes holding services against our
12786 // maximum process count.
12787 if (localLOGV) Log.v(
12788 TAG, "Not trimming app " + app + " with services: "
12789 + app.services);
12790 numServiceProcs++;
12791 }
12792 }
12793
12794 int curMaxProcs = mProcessLimit;
12795 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12796 if (mAlwaysFinishActivities) {
12797 curMaxProcs = 1;
12798 }
12799 curMaxProcs += numServiceProcs;
12800
12801 // Quit as many processes as we can to get down to the desired
12802 // process count. First remove any processes that no longer
12803 // have activites running in them.
12804 for ( i=0;
12805 i<mLRUProcesses.size()
12806 && mLRUProcesses.size() > curMaxProcs;
12807 i++) {
12808 final ProcessRecord app = mLRUProcesses.get(i);
12809 // Quit an application only if it is not currently
12810 // running any activities.
12811 if (!app.persistent && app.activities.size() == 0
12812 && app.curReceiver == null && app.services.size() == 0) {
12813 Log.i(
12814 TAG, "Exiting empty application process "
12815 + app.processName + " ("
12816 + (app.thread != null ? app.thread.asBinder() : null)
12817 + ")\n");
12818 if (app.pid > 0 && app.pid != MY_PID) {
12819 Process.killProcess(app.pid);
12820 } else {
12821 try {
12822 app.thread.scheduleExit();
12823 } catch (Exception e) {
12824 // Ignore exceptions.
12825 }
12826 }
12827 // todo: For now we assume the application is not buggy
12828 // or evil, and will quit as a result of our request.
12829 // Eventually we need to drive this off of the death
12830 // notification, and kill the process if it takes too long.
12831 cleanUpApplicationRecordLocked(app, false, i);
12832 i--;
12833 }
12834 }
12835
12836 // If we still have too many processes, now from the least
12837 // recently used process we start finishing activities.
12838 if (Config.LOGV) Log.v(
12839 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12840 " of " + curMaxProcs + " processes");
12841 for ( i=0;
12842 i<mLRUProcesses.size()
12843 && mLRUProcesses.size() > curMaxProcs;
12844 i++) {
12845 final ProcessRecord app = mLRUProcesses.get(i);
12846 // Quit the application only if we have a state saved for
12847 // all of its activities.
12848 boolean canQuit = !app.persistent && app.curReceiver == null
12849 && app.services.size() == 0
12850 && app.persistentActivities == 0;
12851 int NUMA = app.activities.size();
12852 int j;
12853 if (Config.LOGV) Log.v(
12854 TAG, "Looking to quit " + app.processName);
12855 for (j=0; j<NUMA && canQuit; j++) {
12856 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12857 if (Config.LOGV) Log.v(
12858 TAG, " " + r.intent.getComponent().flattenToShortString()
12859 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12860 canQuit = (r.haveState || !r.stateNotNeeded)
12861 && !r.visible && r.stopped;
12862 }
12863 if (canQuit) {
12864 // Finish all of the activities, and then the app itself.
12865 for (j=0; j<NUMA; j++) {
12866 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12867 if (!r.finishing) {
12868 destroyActivityLocked(r, false);
12869 }
12870 r.resultTo = null;
12871 }
12872 Log.i(TAG, "Exiting application process "
12873 + app.processName + " ("
12874 + (app.thread != null ? app.thread.asBinder() : null)
12875 + ")\n");
12876 if (app.pid > 0 && app.pid != MY_PID) {
12877 Process.killProcess(app.pid);
12878 } else {
12879 try {
12880 app.thread.scheduleExit();
12881 } catch (Exception e) {
12882 // Ignore exceptions.
12883 }
12884 }
12885 // todo: For now we assume the application is not buggy
12886 // or evil, and will quit as a result of our request.
12887 // Eventually we need to drive this off of the death
12888 // notification, and kill the process if it takes too long.
12889 cleanUpApplicationRecordLocked(app, false, i);
12890 i--;
12891 //dump();
12892 }
12893 }
12894
12895 }
12896
12897 int curMaxActivities = MAX_ACTIVITIES;
12898 if (mAlwaysFinishActivities) {
12899 curMaxActivities = 1;
12900 }
12901
12902 // Finally, if there are too many activities now running, try to
12903 // finish as many as we can to get back down to the limit.
12904 for ( i=0;
12905 i<mLRUActivities.size()
12906 && mLRUActivities.size() > curMaxActivities;
12907 i++) {
12908 final HistoryRecord r
12909 = (HistoryRecord)mLRUActivities.get(i);
12910
12911 // We can finish this one if we have its icicle saved and
12912 // it is not persistent.
12913 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12914 && r.stopped && !r.persistent && !r.finishing) {
12915 final int origSize = mLRUActivities.size();
12916 destroyActivityLocked(r, true);
12917
12918 // This will remove it from the LRU list, so keep
12919 // our index at the same value. Note that this check to
12920 // see if the size changes is just paranoia -- if
12921 // something unexpected happens, we don't want to end up
12922 // in an infinite loop.
12923 if (origSize > mLRUActivities.size()) {
12924 i--;
12925 }
12926 }
12927 }
12928 }
12929 }
12930
12931 /** This method sends the specified signal to each of the persistent apps */
12932 public void signalPersistentProcesses(int sig) throws RemoteException {
12933 if (sig != Process.SIGNAL_USR1) {
12934 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12935 }
12936
12937 synchronized (this) {
12938 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12939 != PackageManager.PERMISSION_GRANTED) {
12940 throw new SecurityException("Requires permission "
12941 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12942 }
12943
12944 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12945 ProcessRecord r = mLRUProcesses.get(i);
12946 if (r.thread != null && r.persistent) {
12947 Process.sendSignal(r.pid, sig);
12948 }
12949 }
12950 }
12951 }
12952
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012953 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012954 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012955
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012956 try {
12957 synchronized (this) {
12958 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12959 // its own permission.
12960 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12961 != PackageManager.PERMISSION_GRANTED) {
12962 throw new SecurityException("Requires permission "
12963 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012964 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012965
12966 if (start && fd == null) {
12967 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012968 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012969
12970 ProcessRecord proc = null;
12971 try {
12972 int pid = Integer.parseInt(process);
12973 synchronized (mPidsSelfLocked) {
12974 proc = mPidsSelfLocked.get(pid);
12975 }
12976 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012977 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012978
12979 if (proc == null) {
12980 HashMap<String, SparseArray<ProcessRecord>> all
12981 = mProcessNames.getMap();
12982 SparseArray<ProcessRecord> procs = all.get(process);
12983 if (procs != null && procs.size() > 0) {
12984 proc = procs.valueAt(0);
12985 }
12986 }
12987
12988 if (proc == null || proc.thread == null) {
12989 throw new IllegalArgumentException("Unknown process: " + process);
12990 }
12991
12992 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12993 if (isSecure) {
12994 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12995 throw new SecurityException("Process not debuggable: " + proc);
12996 }
12997 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012998
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012999 proc.thread.profilerControl(start, path, fd);
13000 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013001 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013002 }
13003 } catch (RemoteException e) {
13004 throw new IllegalStateException("Process disappeared");
13005 } finally {
13006 if (fd != null) {
13007 try {
13008 fd.close();
13009 } catch (IOException e) {
13010 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013011 }
13012 }
13013 }
13014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013015 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13016 public void monitor() {
13017 synchronized (this) { }
13018 }
13019}