blob: 2795c2a1348414220e757c5a8fc6d79d153a968b [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;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070045import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020046import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.content.ComponentName;
48import android.content.ContentResolver;
49import android.content.Context;
50import android.content.Intent;
51import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070052import android.content.IIntentReceiver;
53import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.content.pm.ActivityInfo;
55import android.content.pm.ApplicationInfo;
56import android.content.pm.ConfigurationInfo;
57import android.content.pm.IPackageDataObserver;
58import android.content.pm.IPackageManager;
59import android.content.pm.InstrumentationInfo;
60import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070061import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.content.pm.ProviderInfo;
63import android.content.pm.ResolveInfo;
64import android.content.pm.ServiceInfo;
65import android.content.res.Configuration;
66import android.graphics.Bitmap;
67import android.net.Uri;
68import android.os.Binder;
69import android.os.Bundle;
70import android.os.Environment;
71import android.os.FileUtils;
72import android.os.Handler;
73import android.os.IBinder;
74import android.os.IPermissionController;
75import android.os.Looper;
76import android.os.Message;
77import android.os.Parcel;
78import android.os.ParcelFileDescriptor;
79import android.os.PowerManager;
80import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070081import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.os.RemoteException;
83import android.os.ServiceManager;
84import android.os.SystemClock;
85import android.os.SystemProperties;
86import android.provider.Checkin;
87import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020088import android.server.data.CrashData;
89import android.server.data.StackTraceElementData;
90import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.text.TextUtils;
92import android.util.Config;
93import android.util.EventLog;
94import android.util.Log;
95import android.util.PrintWriterPrinter;
96import android.util.SparseArray;
97import android.view.Gravity;
98import android.view.LayoutInflater;
99import android.view.View;
100import android.view.WindowManager;
101import android.view.WindowManagerPolicy;
102
103import dalvik.system.Zygote;
104
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200105import java.io.ByteArrayInputStream;
106import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.io.File;
108import java.io.FileDescriptor;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200111import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112import java.io.PrintWriter;
113import java.lang.IllegalStateException;
114import java.lang.ref.WeakReference;
115import java.util.ArrayList;
116import java.util.HashMap;
117import java.util.HashSet;
118import java.util.Iterator;
119import java.util.List;
120import java.util.Locale;
121import java.util.Map;
122
123public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
124 static final String TAG = "ActivityManager";
125 static final boolean DEBUG = false;
126 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
127 static final boolean DEBUG_SWITCH = localLOGV || false;
128 static final boolean DEBUG_TASKS = localLOGV || false;
129 static final boolean DEBUG_PAUSE = localLOGV || false;
130 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
131 static final boolean DEBUG_TRANSITION = localLOGV || false;
132 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700133 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 static final boolean DEBUG_SERVICE = localLOGV || false;
135 static final boolean DEBUG_VISBILITY = localLOGV || false;
136 static final boolean DEBUG_PROCESSES = localLOGV || false;
137 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700138 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700139 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 static final boolean VALIDATE_TOKENS = false;
141 static final boolean SHOW_ACTIVITY_START_TIME = true;
142
143 // Control over CPU and battery monitoring.
144 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
145 static final boolean MONITOR_CPU_USAGE = true;
146 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
147 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
148 static final boolean MONITOR_THREAD_CPU_USAGE = false;
149
150 // Event log tags
151 static final int LOG_CONFIGURATION_CHANGED = 2719;
152 static final int LOG_CPU = 2721;
153 static final int LOG_AM_FINISH_ACTIVITY = 30001;
154 static final int LOG_TASK_TO_FRONT = 30002;
155 static final int LOG_AM_NEW_INTENT = 30003;
156 static final int LOG_AM_CREATE_TASK = 30004;
157 static final int LOG_AM_CREATE_ACTIVITY = 30005;
158 static final int LOG_AM_RESTART_ACTIVITY = 30006;
159 static final int LOG_AM_RESUME_ACTIVITY = 30007;
160 static final int LOG_ANR = 30008;
161 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
162 static final int LOG_AM_PROCESS_BOUND = 30010;
163 static final int LOG_AM_PROCESS_DIED = 30011;
164 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
165 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
166 static final int LOG_AM_PROCESS_START = 30014;
167 static final int LOG_AM_PROCESS_BAD = 30015;
168 static final int LOG_AM_PROCESS_GOOD = 30016;
169 static final int LOG_AM_LOW_MEMORY = 30017;
170 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
171 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
172 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
173 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
174 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
175 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
176 static final int LOG_AM_CREATE_SERVICE = 30030;
177 static final int LOG_AM_DESTROY_SERVICE = 30031;
178 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
179 static final int LOG_AM_DROP_PROCESS = 30033;
180 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
181 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
182 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
183
184 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
185 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
186
Dianne Hackborn1655be42009-05-08 14:29:01 -0700187 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700188 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 private static final String SYSTEM_SECURE = "ro.secure";
191
192 // This is the maximum number of application processes we would like
193 // to have running. Due to the asynchronous nature of things, we can
194 // temporarily go beyond this limit.
195 static final int MAX_PROCESSES = 2;
196
197 // Set to false to leave processes running indefinitely, relying on
198 // the kernel killing them as resources are required.
199 static final boolean ENFORCE_PROCESS_LIMIT = false;
200
201 // This is the maximum number of activities that we would like to have
202 // running at a given time.
203 static final int MAX_ACTIVITIES = 20;
204
205 // Maximum number of recent tasks that we can remember.
206 static final int MAX_RECENT_TASKS = 20;
207
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700208 // Amount of time after a call to stopAppSwitches() during which we will
209 // prevent further untrusted switches from happening.
210 static final long APP_SWITCH_DELAY_TIME = 5*1000;
211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 // How long until we reset a task when the user returns to it. Currently
213 // 30 minutes.
214 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
215
216 // Set to true to disable the icon that is shown while a new activity
217 // is being started.
218 static final boolean SHOW_APP_STARTING_ICON = true;
219
220 // How long we wait until giving up on the last activity to pause. This
221 // is short because it directly impacts the responsiveness of starting the
222 // next activity.
223 static final int PAUSE_TIMEOUT = 500;
224
225 /**
226 * How long we can hold the launch wake lock before giving up.
227 */
228 static final int LAUNCH_TIMEOUT = 10*1000;
229
230 // How long we wait for a launched process to attach to the activity manager
231 // before we decide it's never going to come up for real.
232 static final int PROC_START_TIMEOUT = 10*1000;
233
234 // How long we wait until giving up on the last activity telling us it
235 // is idle.
236 static final int IDLE_TIMEOUT = 10*1000;
237
238 // How long to wait after going idle before forcing apps to GC.
239 static final int GC_TIMEOUT = 5*1000;
240
241 // How long we wait until giving up on an activity telling us it has
242 // finished destroying itself.
243 static final int DESTROY_TIMEOUT = 10*1000;
244
245 // How long we allow a receiver to run before giving up on it.
246 static final int BROADCAST_TIMEOUT = 10*1000;
247
248 // How long we wait for a service to finish executing.
249 static final int SERVICE_TIMEOUT = 20*1000;
250
251 // How long a service needs to be running until restarting its process
252 // is no longer considered to be a relaunch of the service.
253 static final int SERVICE_RESTART_DURATION = 5*1000;
254
255 // Maximum amount of time for there to be no activity on a service before
256 // we consider it non-essential and allow its process to go on the
257 // LRU background list.
258 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
259
260 // How long we wait until we timeout on key dispatching.
261 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
262
263 // The minimum time we allow between crashes, for us to consider this
264 // application to be bad and stop and its services and reject broadcasts.
265 static final int MIN_CRASH_INTERVAL = 60*1000;
266
267 // How long we wait until we timeout on key dispatching during instrumentation.
268 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
269
270 // OOM adjustments for processes in various states:
271
272 // This is a process without anything currently running in it. Definitely
273 // the first to go! Value set in system/rootdir/init.rc on startup.
274 // This value is initalized in the constructor, careful when refering to
275 // this static variable externally.
276 static int EMPTY_APP_ADJ;
277
278 // This is a process with a content provider that does not have any clients
279 // attached to it. If it did have any clients, its adjustment would be the
280 // one for the highest-priority of those processes.
281 static int CONTENT_PROVIDER_ADJ;
282
283 // This is a process only hosting activities that are not visible,
284 // so it can be killed without any disruption. Value set in
285 // system/rootdir/init.rc on startup.
286 final int HIDDEN_APP_MAX_ADJ;
287 static int HIDDEN_APP_MIN_ADJ;
288
The Android Open Source Project4df24232009-03-05 14:34:35 -0800289 // This is a process holding the home application -- we want to try
290 // avoiding killing it, even if it would normally be in the background,
291 // because the user interacts with it so much.
292 final int HOME_APP_ADJ;
293
Christopher Tate6fa95972009-06-05 18:43:55 -0700294 // This is a process currently hosting a backup operation. Killing it
295 // is not entirely fatal but is generally a bad idea.
296 final int BACKUP_APP_ADJ;
297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 // This is a process holding a secondary server -- killing it will not
299 // have much of an impact as far as the user is concerned. Value set in
300 // system/rootdir/init.rc on startup.
301 final int SECONDARY_SERVER_ADJ;
302
303 // This is a process only hosting activities that are visible to the
304 // user, so we'd prefer they don't disappear. Value set in
305 // system/rootdir/init.rc on startup.
306 final int VISIBLE_APP_ADJ;
307
308 // This is the process running the current foreground app. We'd really
309 // rather not kill it! Value set in system/rootdir/init.rc on startup.
310 final int FOREGROUND_APP_ADJ;
311
312 // This is a process running a core server, such as telephony. Definitely
313 // don't want to kill it, but doing so is not completely fatal.
314 static final int CORE_SERVER_ADJ = -12;
315
316 // The system process runs at the default adjustment.
317 static final int SYSTEM_ADJ = -16;
318
319 // Memory pages are 4K.
320 static final int PAGE_SIZE = 4*1024;
321
Jacek Surazski82a73df2009-06-17 14:33:18 +0200322 // System property defining error report receiver for system apps
323 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
324
325 // System property defining default error report receiver
326 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 // Corresponding memory levels for above adjustments.
329 final int EMPTY_APP_MEM;
330 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800331 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700332 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 final int SECONDARY_SERVER_MEM;
334 final int VISIBLE_APP_MEM;
335 final int FOREGROUND_APP_MEM;
336
337 final int MY_PID;
338
339 static final String[] EMPTY_STRING_ARRAY = new String[0];
340
341 enum ActivityState {
342 INITIALIZING,
343 RESUMED,
344 PAUSING,
345 PAUSED,
346 STOPPING,
347 STOPPED,
348 FINISHING,
349 DESTROYING,
350 DESTROYED
351 }
352
353 /**
354 * The back history of all previous (and possibly still
355 * running) activities. It contains HistoryRecord objects.
356 */
357 final ArrayList mHistory = new ArrayList();
358
359 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700360 * Description of a request to start a new activity, which has been held
361 * due to app switches being disabled.
362 */
363 class PendingActivityLaunch {
364 HistoryRecord r;
365 HistoryRecord sourceRecord;
366 Uri[] grantedUriPermissions;
367 int grantedMode;
368 boolean onlyIfNeeded;
369 }
370
371 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
372 = new ArrayList<PendingActivityLaunch>();
373
374 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 * List of all active broadcasts that are to be executed immediately
376 * (without waiting for another broadcast to finish). Currently this only
377 * contains broadcasts to registered receivers, to avoid spinning up
378 * a bunch of processes to execute IntentReceiver components.
379 */
380 final ArrayList<BroadcastRecord> mParallelBroadcasts
381 = new ArrayList<BroadcastRecord>();
382
383 /**
384 * List of all active broadcasts that are to be executed one at a time.
385 * The object at the top of the list is the currently activity broadcasts;
386 * those after it are waiting for the top to finish..
387 */
388 final ArrayList<BroadcastRecord> mOrderedBroadcasts
389 = new ArrayList<BroadcastRecord>();
390
391 /**
392 * Set when we current have a BROADCAST_INTENT_MSG in flight.
393 */
394 boolean mBroadcastsScheduled = false;
395
396 /**
397 * Set to indicate whether to issue an onUserLeaving callback when a
398 * newly launched activity is being brought in front of us.
399 */
400 boolean mUserLeaving = false;
401
402 /**
403 * When we are in the process of pausing an activity, before starting the
404 * next one, this variable holds the activity that is currently being paused.
405 */
406 HistoryRecord mPausingActivity = null;
407
408 /**
409 * Current activity that is resumed, or null if there is none.
410 */
411 HistoryRecord mResumedActivity = null;
412
413 /**
414 * Activity we have told the window manager to have key focus.
415 */
416 HistoryRecord mFocusedActivity = null;
417
418 /**
419 * This is the last activity that we put into the paused state. This is
420 * used to determine if we need to do an activity transition while sleeping,
421 * when we normally hold the top activity paused.
422 */
423 HistoryRecord mLastPausedActivity = null;
424
425 /**
426 * List of activities that are waiting for a new activity
427 * to become visible before completing whatever operation they are
428 * supposed to do.
429 */
430 final ArrayList mWaitingVisibleActivities = new ArrayList();
431
432 /**
433 * List of activities that are ready to be stopped, but waiting
434 * for the next activity to settle down before doing so. It contains
435 * HistoryRecord objects.
436 */
437 final ArrayList<HistoryRecord> mStoppingActivities
438 = new ArrayList<HistoryRecord>();
439
440 /**
441 * List of intents that were used to start the most recent tasks.
442 */
443 final ArrayList<TaskRecord> mRecentTasks
444 = new ArrayList<TaskRecord>();
445
446 /**
447 * List of activities that are ready to be finished, but waiting
448 * for the previous activity to settle down before doing so. It contains
449 * HistoryRecord objects.
450 */
451 final ArrayList mFinishingActivities = new ArrayList();
452
453 /**
454 * All of the applications we currently have running organized by name.
455 * The keys are strings of the application package name (as
456 * returned by the package manager), and the keys are ApplicationRecord
457 * objects.
458 */
459 final ProcessMap<ProcessRecord> mProcessNames
460 = new ProcessMap<ProcessRecord>();
461
462 /**
463 * The last time that various processes have crashed.
464 */
465 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
466
467 /**
468 * Set of applications that we consider to be bad, and will reject
469 * incoming broadcasts from (which the user has no control over).
470 * Processes are added to this set when they have crashed twice within
471 * a minimum amount of time; they are removed from it when they are
472 * later restarted (hopefully due to some user action). The value is the
473 * time it was added to the list.
474 */
475 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
476
477 /**
478 * All of the processes we currently have running organized by pid.
479 * The keys are the pid running the application.
480 *
481 * <p>NOTE: This object is protected by its own lock, NOT the global
482 * activity manager lock!
483 */
484 final SparseArray<ProcessRecord> mPidsSelfLocked
485 = new SparseArray<ProcessRecord>();
486
487 /**
488 * All of the processes that have been forced to be foreground. The key
489 * is the pid of the caller who requested it (we hold a death
490 * link on it).
491 */
492 abstract class ForegroundToken implements IBinder.DeathRecipient {
493 int pid;
494 IBinder token;
495 }
496 final SparseArray<ForegroundToken> mForegroundProcesses
497 = new SparseArray<ForegroundToken>();
498
499 /**
500 * List of records for processes that someone had tried to start before the
501 * system was ready. We don't start them at that point, but ensure they
502 * are started by the time booting is complete.
503 */
504 final ArrayList<ProcessRecord> mProcessesOnHold
505 = new ArrayList<ProcessRecord>();
506
507 /**
508 * List of records for processes that we have started and are waiting
509 * for them to call back. This is really only needed when running in
510 * single processes mode, in which case we do not have a unique pid for
511 * each process.
512 */
513 final ArrayList<ProcessRecord> mStartingProcesses
514 = new ArrayList<ProcessRecord>();
515
516 /**
517 * List of persistent applications that are in the process
518 * of being started.
519 */
520 final ArrayList<ProcessRecord> mPersistentStartingProcesses
521 = new ArrayList<ProcessRecord>();
522
523 /**
524 * Processes that are being forcibly torn down.
525 */
526 final ArrayList<ProcessRecord> mRemovedProcesses
527 = new ArrayList<ProcessRecord>();
528
529 /**
530 * List of running applications, sorted by recent usage.
531 * The first entry in the list is the least recently used.
532 * It contains ApplicationRecord objects. This list does NOT include
533 * any persistent application records (since we never want to exit them).
534 */
535 final ArrayList<ProcessRecord> mLRUProcesses
536 = new ArrayList<ProcessRecord>();
537
538 /**
539 * List of processes that should gc as soon as things are idle.
540 */
541 final ArrayList<ProcessRecord> mProcessesToGc
542 = new ArrayList<ProcessRecord>();
543
544 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800545 * This is the process holding what we currently consider to be
546 * the "home" activity.
547 */
548 private ProcessRecord mHomeProcess;
549
550 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 * List of running activities, sorted by recent usage.
552 * The first entry in the list is the least recently used.
553 * It contains HistoryRecord objects.
554 */
555 private final ArrayList mLRUActivities = new ArrayList();
556
557 /**
558 * Set of PendingResultRecord objects that are currently active.
559 */
560 final HashSet mPendingResultRecords = new HashSet();
561
562 /**
563 * Set of IntentSenderRecord objects that are currently active.
564 */
565 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
566 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
567
568 /**
569 * Intent broadcast that we have tried to start, but are
570 * waiting for its application's process to be created. We only
571 * need one (instead of a list) because we always process broadcasts
572 * one at a time, so no others can be started while waiting for this
573 * one.
574 */
575 BroadcastRecord mPendingBroadcast = null;
576
577 /**
578 * Keeps track of all IIntentReceivers that have been registered for
579 * broadcasts. Hash keys are the receiver IBinder, hash value is
580 * a ReceiverList.
581 */
582 final HashMap mRegisteredReceivers = new HashMap();
583
584 /**
585 * Resolver for broadcast intents to registered receivers.
586 * Holds BroadcastFilter (subclass of IntentFilter).
587 */
588 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
589 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
590 @Override
591 protected boolean allowFilterResult(
592 BroadcastFilter filter, List<BroadcastFilter> dest) {
593 IBinder target = filter.receiverList.receiver.asBinder();
594 for (int i=dest.size()-1; i>=0; i--) {
595 if (dest.get(i).receiverList.receiver.asBinder() == target) {
596 return false;
597 }
598 }
599 return true;
600 }
601 };
602
603 /**
604 * State of all active sticky broadcasts. Keys are the action of the
605 * sticky Intent, values are an ArrayList of all broadcasted intents with
606 * that action (which should usually be one).
607 */
608 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
609 new HashMap<String, ArrayList<Intent>>();
610
611 /**
612 * All currently running services.
613 */
614 final HashMap<ComponentName, ServiceRecord> mServices =
615 new HashMap<ComponentName, ServiceRecord>();
616
617 /**
618 * All currently running services indexed by the Intent used to start them.
619 */
620 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
621 new HashMap<Intent.FilterComparison, ServiceRecord>();
622
623 /**
624 * All currently bound service connections. Keys are the IBinder of
625 * the client's IServiceConnection.
626 */
627 final HashMap<IBinder, ConnectionRecord> mServiceConnections
628 = new HashMap<IBinder, ConnectionRecord>();
629
630 /**
631 * List of services that we have been asked to start,
632 * but haven't yet been able to. It is used to hold start requests
633 * while waiting for their corresponding application thread to get
634 * going.
635 */
636 final ArrayList<ServiceRecord> mPendingServices
637 = new ArrayList<ServiceRecord>();
638
639 /**
640 * List of services that are scheduled to restart following a crash.
641 */
642 final ArrayList<ServiceRecord> mRestartingServices
643 = new ArrayList<ServiceRecord>();
644
645 /**
646 * List of services that are in the process of being stopped.
647 */
648 final ArrayList<ServiceRecord> mStoppingServices
649 = new ArrayList<ServiceRecord>();
650
651 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700652 * Backup/restore process management
653 */
654 String mBackupAppName = null;
655 BackupRecord mBackupTarget = null;
656
657 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 * List of PendingThumbnailsRecord objects of clients who are still
659 * waiting to receive all of the thumbnails for a task.
660 */
661 final ArrayList mPendingThumbnails = new ArrayList();
662
663 /**
664 * List of HistoryRecord objects that have been finished and must
665 * still report back to a pending thumbnail receiver.
666 */
667 final ArrayList mCancelledThumbnails = new ArrayList();
668
669 /**
670 * All of the currently running global content providers. Keys are a
671 * string containing the provider name and values are a
672 * ContentProviderRecord object containing the data about it. Note
673 * that a single provider may be published under multiple names, so
674 * there may be multiple entries here for a single one in mProvidersByClass.
675 */
676 final HashMap mProvidersByName = new HashMap();
677
678 /**
679 * All of the currently running global content providers. Keys are a
680 * string containing the provider's implementation class and values are a
681 * ContentProviderRecord object containing the data about it.
682 */
683 final HashMap mProvidersByClass = new HashMap();
684
685 /**
686 * List of content providers who have clients waiting for them. The
687 * application is currently being launched and the provider will be
688 * removed from this list once it is published.
689 */
690 final ArrayList mLaunchingProviders = new ArrayList();
691
692 /**
693 * Global set of specific Uri permissions that have been granted.
694 */
695 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
696 = new SparseArray<HashMap<Uri, UriPermission>>();
697
698 /**
699 * Thread-local storage used to carry caller permissions over through
700 * indirect content-provider access.
701 * @see #ActivityManagerService.openContentUri()
702 */
703 private class Identity {
704 public int pid;
705 public int uid;
706
707 Identity(int _pid, int _uid) {
708 pid = _pid;
709 uid = _uid;
710 }
711 }
712 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
713
714 /**
715 * All information we have collected about the runtime performance of
716 * any user id that can impact battery performance.
717 */
718 final BatteryStatsService mBatteryStatsService;
719
720 /**
721 * information about component usage
722 */
723 final UsageStatsService mUsageStatsService;
724
725 /**
726 * Current configuration information. HistoryRecord objects are given
727 * a reference to this object to indicate which configuration they are
728 * currently running in, so this object must be kept immutable.
729 */
730 Configuration mConfiguration = new Configuration();
731
732 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700733 * Hardware-reported OpenGLES version.
734 */
735 final int GL_ES_VERSION;
736
737 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 * List of initialization arguments to pass to all processes when binding applications to them.
739 * For example, references to the commonly used services.
740 */
741 HashMap<String, IBinder> mAppBindArgs;
742
743 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700744 * Temporary to avoid allocations. Protected by main lock.
745 */
746 final StringBuilder mStringBuilder = new StringBuilder(256);
747
748 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 * Used to control how we initialize the service.
750 */
751 boolean mStartRunning = false;
752 ComponentName mTopComponent;
753 String mTopAction;
754 String mTopData;
755 boolean mSystemReady = false;
756 boolean mBooting = false;
757
758 Context mContext;
759
760 int mFactoryTest;
761
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700762 boolean mCheckedForSetup;
763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700765 * The time at which we will allow normal application switches again,
766 * after a call to {@link #stopAppSwitches()}.
767 */
768 long mAppSwitchesAllowedTime;
769
770 /**
771 * This is set to true after the first switch after mAppSwitchesAllowedTime
772 * is set; any switches after that will clear the time.
773 */
774 boolean mDidAppSwitch;
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Set while we are wanting to sleep, to prevent any
778 * activities from being started/resumed.
779 */
780 boolean mSleeping = false;
781
782 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700783 * Set if we are shutting down the system, similar to sleeping.
784 */
785 boolean mShuttingDown = false;
786
787 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 * Set when the system is going to sleep, until we have
789 * successfully paused the current activity and released our wake lock.
790 * At that point the system is allowed to actually sleep.
791 */
792 PowerManager.WakeLock mGoingToSleep;
793
794 /**
795 * We don't want to allow the device to go to sleep while in the process
796 * of launching an activity. This is primarily to allow alarm intent
797 * receivers to launch an activity and get that to run before the device
798 * goes back to sleep.
799 */
800 PowerManager.WakeLock mLaunchingActivity;
801
802 /**
803 * Task identifier that activities are currently being started
804 * in. Incremented each time a new task is created.
805 * todo: Replace this with a TokenSpace class that generates non-repeating
806 * integers that won't wrap.
807 */
808 int mCurTask = 1;
809
810 /**
811 * Current sequence id for oom_adj computation traversal.
812 */
813 int mAdjSeq = 0;
814
815 /**
816 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
817 * is set, indicating the user wants processes started in such a way
818 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
819 * running in each process (thus no pre-initialized process, etc).
820 */
821 boolean mSimpleProcessManagement = false;
822
823 /**
824 * System monitoring: number of processes that died since the last
825 * N procs were started.
826 */
827 int[] mProcDeaths = new int[20];
828
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700829 /**
830 * This is set if we had to do a delayed dexopt of an app before launching
831 * it, to increasing the ANR timeouts in that case.
832 */
833 boolean mDidDexOpt;
834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 String mDebugApp = null;
836 boolean mWaitForDebugger = false;
837 boolean mDebugTransient = false;
838 String mOrigDebugApp = null;
839 boolean mOrigWaitForDebugger = false;
840 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700841 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700843 final RemoteCallbackList<IActivityWatcher> mWatchers
844 = new RemoteCallbackList<IActivityWatcher>();
845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 /**
847 * Callback of last caller to {@link #requestPss}.
848 */
849 Runnable mRequestPssCallback;
850
851 /**
852 * Remaining processes for which we are waiting results from the last
853 * call to {@link #requestPss}.
854 */
855 final ArrayList<ProcessRecord> mRequestPssList
856 = new ArrayList<ProcessRecord>();
857
858 /**
859 * Runtime statistics collection thread. This object's lock is used to
860 * protect all related state.
861 */
862 final Thread mProcessStatsThread;
863
864 /**
865 * Used to collect process stats when showing not responding dialog.
866 * Protected by mProcessStatsThread.
867 */
868 final ProcessStats mProcessStats = new ProcessStats(
869 MONITOR_THREAD_CPU_USAGE);
870 long mLastCpuTime = 0;
871 long mLastWriteTime = 0;
872
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700873 long mInitialStartTime = 0;
874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 /**
876 * Set to true after the system has finished booting.
877 */
878 boolean mBooted = false;
879
880 int mProcessLimit = 0;
881
882 WindowManagerService mWindowManager;
883
884 static ActivityManagerService mSelf;
885 static ActivityThread mSystemThread;
886
887 private final class AppDeathRecipient implements IBinder.DeathRecipient {
888 final ProcessRecord mApp;
889 final int mPid;
890 final IApplicationThread mAppThread;
891
892 AppDeathRecipient(ProcessRecord app, int pid,
893 IApplicationThread thread) {
894 if (localLOGV) Log.v(
895 TAG, "New death recipient " + this
896 + " for thread " + thread.asBinder());
897 mApp = app;
898 mPid = pid;
899 mAppThread = thread;
900 }
901
902 public void binderDied() {
903 if (localLOGV) Log.v(
904 TAG, "Death received in " + this
905 + " for thread " + mAppThread.asBinder());
906 removeRequestedPss(mApp);
907 synchronized(ActivityManagerService.this) {
908 appDiedLocked(mApp, mPid, mAppThread);
909 }
910 }
911 }
912
913 static final int SHOW_ERROR_MSG = 1;
914 static final int SHOW_NOT_RESPONDING_MSG = 2;
915 static final int SHOW_FACTORY_ERROR_MSG = 3;
916 static final int UPDATE_CONFIGURATION_MSG = 4;
917 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
918 static final int WAIT_FOR_DEBUGGER_MSG = 6;
919 static final int BROADCAST_INTENT_MSG = 7;
920 static final int BROADCAST_TIMEOUT_MSG = 8;
921 static final int PAUSE_TIMEOUT_MSG = 9;
922 static final int IDLE_TIMEOUT_MSG = 10;
923 static final int IDLE_NOW_MSG = 11;
924 static final int SERVICE_TIMEOUT_MSG = 12;
925 static final int UPDATE_TIME_ZONE = 13;
926 static final int SHOW_UID_ERROR_MSG = 14;
927 static final int IM_FEELING_LUCKY_MSG = 15;
928 static final int LAUNCH_TIMEOUT_MSG = 16;
929 static final int DESTROY_TIMEOUT_MSG = 17;
930 static final int SERVICE_ERROR_MSG = 18;
931 static final int RESUME_TOP_ACTIVITY_MSG = 19;
932 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700933 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700934 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935
936 AlertDialog mUidAlert;
937
938 final Handler mHandler = new Handler() {
939 //public Handler() {
940 // if (localLOGV) Log.v(TAG, "Handler started!");
941 //}
942
943 public void handleMessage(Message msg) {
944 switch (msg.what) {
945 case SHOW_ERROR_MSG: {
946 HashMap data = (HashMap) msg.obj;
947 byte[] crashData = (byte[])data.get("crashData");
948 if (crashData != null) {
949 // This needs to be *un*synchronized to avoid deadlock.
950 ContentResolver resolver = mContext.getContentResolver();
951 Checkin.reportCrash(resolver, crashData);
952 }
953 synchronized (ActivityManagerService.this) {
954 ProcessRecord proc = (ProcessRecord)data.get("app");
955 if (proc != null && proc.crashDialog != null) {
956 Log.e(TAG, "App already has crash dialog: " + proc);
957 return;
958 }
959 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700960 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 Dialog d = new AppErrorDialog(
962 mContext, res, proc,
963 (Integer)data.get("flags"),
964 (String)data.get("shortMsg"),
965 (String)data.get("longMsg"));
966 d.show();
967 proc.crashDialog = d;
968 } else {
969 // The device is asleep, so just pretend that the user
970 // saw a crash dialog and hit "force quit".
971 res.set(0);
972 }
973 }
974 } break;
975 case SHOW_NOT_RESPONDING_MSG: {
976 synchronized (ActivityManagerService.this) {
977 HashMap data = (HashMap) msg.obj;
978 ProcessRecord proc = (ProcessRecord)data.get("app");
979 if (proc != null && proc.anrDialog != null) {
980 Log.e(TAG, "App already has anr dialog: " + proc);
981 return;
982 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800983
984 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
985 null, null, 0, null, null, null,
986 false, false, MY_PID, Process.SYSTEM_UID);
987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
989 mContext, proc, (HistoryRecord)data.get("activity"));
990 d.show();
991 proc.anrDialog = d;
992 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700993
994 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 } break;
996 case SHOW_FACTORY_ERROR_MSG: {
997 Dialog d = new FactoryErrorDialog(
998 mContext, msg.getData().getCharSequence("msg"));
999 d.show();
1000 enableScreenAfterBoot();
1001 } break;
1002 case UPDATE_CONFIGURATION_MSG: {
1003 final ContentResolver resolver = mContext.getContentResolver();
1004 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1005 } break;
1006 case GC_BACKGROUND_PROCESSES_MSG: {
1007 synchronized (ActivityManagerService.this) {
1008 performAppGcsIfAppropriateLocked();
1009 }
1010 } break;
1011 case WAIT_FOR_DEBUGGER_MSG: {
1012 synchronized (ActivityManagerService.this) {
1013 ProcessRecord app = (ProcessRecord)msg.obj;
1014 if (msg.arg1 != 0) {
1015 if (!app.waitedForDebugger) {
1016 Dialog d = new AppWaitingForDebuggerDialog(
1017 ActivityManagerService.this,
1018 mContext, app);
1019 app.waitDialog = d;
1020 app.waitedForDebugger = true;
1021 d.show();
1022 }
1023 } else {
1024 if (app.waitDialog != null) {
1025 app.waitDialog.dismiss();
1026 app.waitDialog = null;
1027 }
1028 }
1029 }
1030 } break;
1031 case BROADCAST_INTENT_MSG: {
1032 if (DEBUG_BROADCAST) Log.v(
1033 TAG, "Received BROADCAST_INTENT_MSG");
1034 processNextBroadcast(true);
1035 } break;
1036 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001037 if (mDidDexOpt) {
1038 mDidDexOpt = false;
1039 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1040 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1041 return;
1042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 broadcastTimeout();
1044 } break;
1045 case PAUSE_TIMEOUT_MSG: {
1046 IBinder token = (IBinder)msg.obj;
1047 // We don't at this point know if the activity is fullscreen,
1048 // so we need to be conservative and assume it isn't.
1049 Log.w(TAG, "Activity pause timeout for " + token);
1050 activityPaused(token, null, true);
1051 } break;
1052 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001053 if (mDidDexOpt) {
1054 mDidDexOpt = false;
1055 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1056 nmsg.obj = msg.obj;
1057 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1058 return;
1059 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 // We don't at this point know if the activity is fullscreen,
1061 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001062 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 Log.w(TAG, "Activity idle timeout for " + token);
1064 activityIdleInternal(token, true);
1065 } break;
1066 case DESTROY_TIMEOUT_MSG: {
1067 IBinder token = (IBinder)msg.obj;
1068 // We don't at this point know if the activity is fullscreen,
1069 // so we need to be conservative and assume it isn't.
1070 Log.w(TAG, "Activity destroy timeout for " + token);
1071 activityDestroyed(token);
1072 } break;
1073 case IDLE_NOW_MSG: {
1074 IBinder token = (IBinder)msg.obj;
1075 activityIdle(token);
1076 } break;
1077 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001078 if (mDidDexOpt) {
1079 mDidDexOpt = false;
1080 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1081 nmsg.obj = msg.obj;
1082 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1083 return;
1084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 serviceTimeout((ProcessRecord)msg.obj);
1086 } break;
1087 case UPDATE_TIME_ZONE: {
1088 synchronized (ActivityManagerService.this) {
1089 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1090 ProcessRecord r = mLRUProcesses.get(i);
1091 if (r.thread != null) {
1092 try {
1093 r.thread.updateTimeZone();
1094 } catch (RemoteException ex) {
1095 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1096 }
1097 }
1098 }
1099 }
1100 break;
1101 }
1102 case SHOW_UID_ERROR_MSG: {
1103 // XXX This is a temporary dialog, no need to localize.
1104 AlertDialog d = new BaseErrorDialog(mContext);
1105 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1106 d.setCancelable(false);
1107 d.setTitle("System UIDs Inconsistent");
1108 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1109 d.setButton("I'm Feeling Lucky",
1110 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1111 mUidAlert = d;
1112 d.show();
1113 } break;
1114 case IM_FEELING_LUCKY_MSG: {
1115 if (mUidAlert != null) {
1116 mUidAlert.dismiss();
1117 mUidAlert = null;
1118 }
1119 } break;
1120 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001121 if (mDidDexOpt) {
1122 mDidDexOpt = false;
1123 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1124 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1125 return;
1126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 synchronized (ActivityManagerService.this) {
1128 if (mLaunchingActivity.isHeld()) {
1129 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1130 mLaunchingActivity.release();
1131 }
1132 }
1133 } break;
1134 case SERVICE_ERROR_MSG: {
1135 ServiceRecord srv = (ServiceRecord)msg.obj;
1136 // This needs to be *un*synchronized to avoid deadlock.
1137 Checkin.logEvent(mContext.getContentResolver(),
1138 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1139 srv.name.toShortString());
1140 } break;
1141 case RESUME_TOP_ACTIVITY_MSG: {
1142 synchronized (ActivityManagerService.this) {
1143 resumeTopActivityLocked(null);
1144 }
1145 }
1146 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001147 if (mDidDexOpt) {
1148 mDidDexOpt = false;
1149 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1150 nmsg.obj = msg.obj;
1151 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1152 return;
1153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 ProcessRecord app = (ProcessRecord)msg.obj;
1155 synchronized (ActivityManagerService.this) {
1156 processStartTimedOutLocked(app);
1157 }
1158 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001159 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1160 synchronized (ActivityManagerService.this) {
1161 doPendingActivityLaunchesLocked(true);
1162 }
1163 }
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001164 case KILL_APPLICATION_MSG: {
1165 synchronized (ActivityManagerService.this) {
1166 int uid = msg.arg1;
1167 boolean restart = (msg.arg2 == 1);
1168 String pkg = (String) msg.obj;
1169 uninstallPackageLocked(pkg, uid, restart);
1170 }
1171 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 }
1173 }
1174 };
1175
1176 public static void setSystemProcess() {
1177 try {
1178 ActivityManagerService m = mSelf;
1179
1180 ServiceManager.addService("activity", m);
1181 ServiceManager.addService("meminfo", new MemBinder(m));
1182 if (MONITOR_CPU_USAGE) {
1183 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1184 }
1185 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1186 ServiceManager.addService("activity.services", new ServicesBinder(m));
1187 ServiceManager.addService("activity.senders", new SendersBinder(m));
1188 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1189 ServiceManager.addService("permission", new PermissionController(m));
1190
1191 ApplicationInfo info =
1192 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001193 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 synchronized (mSelf) {
1195 ProcessRecord app = mSelf.newProcessRecordLocked(
1196 mSystemThread.getApplicationThread(), info,
1197 info.processName);
1198 app.persistent = true;
1199 app.pid = Process.myPid();
1200 app.maxAdj = SYSTEM_ADJ;
1201 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1202 synchronized (mSelf.mPidsSelfLocked) {
1203 mSelf.mPidsSelfLocked.put(app.pid, app);
1204 }
1205 mSelf.updateLRUListLocked(app, true);
1206 }
1207 } catch (PackageManager.NameNotFoundException e) {
1208 throw new RuntimeException(
1209 "Unable to find android system package", e);
1210 }
1211 }
1212
1213 public void setWindowManager(WindowManagerService wm) {
1214 mWindowManager = wm;
1215 }
1216
1217 public static final Context main(int factoryTest) {
1218 AThread thr = new AThread();
1219 thr.start();
1220
1221 synchronized (thr) {
1222 while (thr.mService == null) {
1223 try {
1224 thr.wait();
1225 } catch (InterruptedException e) {
1226 }
1227 }
1228 }
1229
1230 ActivityManagerService m = thr.mService;
1231 mSelf = m;
1232 ActivityThread at = ActivityThread.systemMain();
1233 mSystemThread = at;
1234 Context context = at.getSystemContext();
1235 m.mContext = context;
1236 m.mFactoryTest = factoryTest;
1237 PowerManager pm =
1238 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1239 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1240 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1241 m.mLaunchingActivity.setReferenceCounted(false);
1242
1243 m.mBatteryStatsService.publish(context);
1244 m.mUsageStatsService.publish(context);
1245
1246 synchronized (thr) {
1247 thr.mReady = true;
1248 thr.notifyAll();
1249 }
1250
1251 m.startRunning(null, null, null, null);
1252
1253 return context;
1254 }
1255
1256 public static ActivityManagerService self() {
1257 return mSelf;
1258 }
1259
1260 static class AThread extends Thread {
1261 ActivityManagerService mService;
1262 boolean mReady = false;
1263
1264 public AThread() {
1265 super("ActivityManager");
1266 }
1267
1268 public void run() {
1269 Looper.prepare();
1270
1271 android.os.Process.setThreadPriority(
1272 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1273
1274 ActivityManagerService m = new ActivityManagerService();
1275
1276 synchronized (this) {
1277 mService = m;
1278 notifyAll();
1279 }
1280
1281 synchronized (this) {
1282 while (!mReady) {
1283 try {
1284 wait();
1285 } catch (InterruptedException e) {
1286 }
1287 }
1288 }
1289
1290 Looper.loop();
1291 }
1292 }
1293
1294 static class BroadcastsBinder extends Binder {
1295 ActivityManagerService mActivityManagerService;
1296 BroadcastsBinder(ActivityManagerService activityManagerService) {
1297 mActivityManagerService = activityManagerService;
1298 }
1299
1300 @Override
1301 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1302 mActivityManagerService.dumpBroadcasts(pw);
1303 }
1304 }
1305
1306 static class ServicesBinder extends Binder {
1307 ActivityManagerService mActivityManagerService;
1308 ServicesBinder(ActivityManagerService activityManagerService) {
1309 mActivityManagerService = activityManagerService;
1310 }
1311
1312 @Override
1313 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1314 mActivityManagerService.dumpServices(pw);
1315 }
1316 }
1317
1318 static class SendersBinder extends Binder {
1319 ActivityManagerService mActivityManagerService;
1320 SendersBinder(ActivityManagerService activityManagerService) {
1321 mActivityManagerService = activityManagerService;
1322 }
1323
1324 @Override
1325 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1326 mActivityManagerService.dumpSenders(pw);
1327 }
1328 }
1329
1330 static class ProvidersBinder extends Binder {
1331 ActivityManagerService mActivityManagerService;
1332 ProvidersBinder(ActivityManagerService activityManagerService) {
1333 mActivityManagerService = activityManagerService;
1334 }
1335
1336 @Override
1337 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1338 mActivityManagerService.dumpProviders(pw);
1339 }
1340 }
1341
1342 static class MemBinder extends Binder {
1343 ActivityManagerService mActivityManagerService;
1344 MemBinder(ActivityManagerService activityManagerService) {
1345 mActivityManagerService = activityManagerService;
1346 }
1347
1348 @Override
1349 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1350 ActivityManagerService service = mActivityManagerService;
1351 ArrayList<ProcessRecord> procs;
1352 synchronized (mActivityManagerService) {
1353 if (args != null && args.length > 0
1354 && args[0].charAt(0) != '-') {
1355 procs = new ArrayList<ProcessRecord>();
1356 int pid = -1;
1357 try {
1358 pid = Integer.parseInt(args[0]);
1359 } catch (NumberFormatException e) {
1360
1361 }
1362 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1363 ProcessRecord proc = service.mLRUProcesses.get(i);
1364 if (proc.pid == pid) {
1365 procs.add(proc);
1366 } else if (proc.processName.equals(args[0])) {
1367 procs.add(proc);
1368 }
1369 }
1370 if (procs.size() <= 0) {
1371 pw.println("No process found for: " + args[0]);
1372 return;
1373 }
1374 } else {
1375 procs = service.mLRUProcesses;
1376 }
1377 }
1378 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1379 }
1380 }
1381
1382 static class CpuBinder extends Binder {
1383 ActivityManagerService mActivityManagerService;
1384 CpuBinder(ActivityManagerService activityManagerService) {
1385 mActivityManagerService = activityManagerService;
1386 }
1387
1388 @Override
1389 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1390 synchronized (mActivityManagerService.mProcessStatsThread) {
1391 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1392 }
1393 }
1394 }
1395
1396 private ActivityManagerService() {
1397 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1398 if (v != null && Integer.getInteger(v) != 0) {
1399 mSimpleProcessManagement = true;
1400 }
1401 v = System.getenv("ANDROID_DEBUG_APP");
1402 if (v != null) {
1403 mSimpleProcessManagement = true;
1404 }
1405
1406 MY_PID = Process.myPid();
1407
1408 File dataDir = Environment.getDataDirectory();
1409 File systemDir = new File(dataDir, "system");
1410 systemDir.mkdirs();
1411 mBatteryStatsService = new BatteryStatsService(new File(
1412 systemDir, "batterystats.bin").toString());
1413 mBatteryStatsService.getActiveStatistics().readLocked();
1414 mBatteryStatsService.getActiveStatistics().writeLocked();
1415
1416 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001417 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418
Jack Palevichb90d28c2009-07-22 15:35:24 -07001419 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1420 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 mConfiguration.makeDefault();
1423 mProcessStats.init();
1424
1425 // Add ourself to the Watchdog monitors.
1426 Watchdog.getInstance().addMonitor(this);
1427
1428 // These values are set in system/rootdir/init.rc on startup.
1429 FOREGROUND_APP_ADJ =
1430 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1431 VISIBLE_APP_ADJ =
1432 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1433 SECONDARY_SERVER_ADJ =
1434 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001435 BACKUP_APP_ADJ =
1436 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001437 HOME_APP_ADJ =
1438 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 HIDDEN_APP_MIN_ADJ =
1440 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1441 CONTENT_PROVIDER_ADJ =
1442 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1443 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1444 EMPTY_APP_ADJ =
1445 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1446 FOREGROUND_APP_MEM =
1447 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1448 VISIBLE_APP_MEM =
1449 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1450 SECONDARY_SERVER_MEM =
1451 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001452 BACKUP_APP_MEM =
1453 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001454 HOME_APP_MEM =
1455 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 HIDDEN_APP_MEM =
1457 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1458 EMPTY_APP_MEM =
1459 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1460
1461 mProcessStatsThread = new Thread("ProcessStats") {
1462 public void run() {
1463 while (true) {
1464 try {
1465 try {
1466 synchronized(this) {
1467 final long now = SystemClock.uptimeMillis();
1468 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1469 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1470 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1471 // + ", write delay=" + nextWriteDelay);
1472 if (nextWriteDelay < nextCpuDelay) {
1473 nextCpuDelay = nextWriteDelay;
1474 }
1475 if (nextCpuDelay > 0) {
1476 this.wait(nextCpuDelay);
1477 }
1478 }
1479 } catch (InterruptedException e) {
1480 }
1481
1482 updateCpuStatsNow();
1483 } catch (Exception e) {
1484 Log.e(TAG, "Unexpected exception collecting process stats", e);
1485 }
1486 }
1487 }
1488 };
1489 mProcessStatsThread.start();
1490 }
1491
1492 @Override
1493 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1494 throws RemoteException {
1495 try {
1496 return super.onTransact(code, data, reply, flags);
1497 } catch (RuntimeException e) {
1498 // The activity manager only throws security exceptions, so let's
1499 // log all others.
1500 if (!(e instanceof SecurityException)) {
1501 Log.e(TAG, "Activity Manager Crash", e);
1502 }
1503 throw e;
1504 }
1505 }
1506
1507 void updateCpuStats() {
1508 synchronized (mProcessStatsThread) {
1509 final long now = SystemClock.uptimeMillis();
1510 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1511 mProcessStatsThread.notify();
1512 }
1513 }
1514 }
1515
1516 void updateCpuStatsNow() {
1517 synchronized (mProcessStatsThread) {
1518 final long now = SystemClock.uptimeMillis();
1519 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 if (MONITOR_CPU_USAGE &&
1522 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1523 mLastCpuTime = now;
1524 haveNewCpuStats = true;
1525 mProcessStats.update();
1526 //Log.i(TAG, mProcessStats.printCurrentState());
1527 //Log.i(TAG, "Total CPU usage: "
1528 // + mProcessStats.getTotalCpuPercent() + "%");
1529
1530 // Log the cpu usage if the property is set.
1531 if ("true".equals(SystemProperties.get("events.cpu"))) {
1532 int user = mProcessStats.getLastUserTime();
1533 int system = mProcessStats.getLastSystemTime();
1534 int iowait = mProcessStats.getLastIoWaitTime();
1535 int irq = mProcessStats.getLastIrqTime();
1536 int softIrq = mProcessStats.getLastSoftIrqTime();
1537 int idle = mProcessStats.getLastIdleTime();
1538
1539 int total = user + system + iowait + irq + softIrq + idle;
1540 if (total == 0) total = 1;
1541
1542 EventLog.writeEvent(LOG_CPU,
1543 ((user+system+iowait+irq+softIrq) * 100) / total,
1544 (user * 100) / total,
1545 (system * 100) / total,
1546 (iowait * 100) / total,
1547 (irq * 100) / total,
1548 (softIrq * 100) / total);
1549 }
1550 }
1551
Amith Yamasani819f9282009-06-24 23:18:15 -07001552 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001553 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 synchronized(mPidsSelfLocked) {
1555 if (haveNewCpuStats) {
1556 if (mBatteryStatsService.isOnBattery()) {
1557 final int N = mProcessStats.countWorkingStats();
1558 for (int i=0; i<N; i++) {
1559 ProcessStats.Stats st
1560 = mProcessStats.getWorkingStats(i);
1561 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1562 if (pr != null) {
1563 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1564 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001565 } else {
1566 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001567 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001568 if (ps != null) {
1569 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 }
1572 }
1573 }
1574 }
1575 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1578 mLastWriteTime = now;
1579 mBatteryStatsService.getActiveStatistics().writeLocked();
1580 }
1581 }
1582 }
1583 }
1584
1585 /**
1586 * Initialize the application bind args. These are passed to each
1587 * process when the bindApplication() IPC is sent to the process. They're
1588 * lazily setup to make sure the services are running when they're asked for.
1589 */
1590 private HashMap<String, IBinder> getCommonServicesLocked() {
1591 if (mAppBindArgs == null) {
1592 mAppBindArgs = new HashMap<String, IBinder>();
1593
1594 // Setup the application init args
1595 mAppBindArgs.put("package", ServiceManager.getService("package"));
1596 mAppBindArgs.put("window", ServiceManager.getService("window"));
1597 mAppBindArgs.put(Context.ALARM_SERVICE,
1598 ServiceManager.getService(Context.ALARM_SERVICE));
1599 }
1600 return mAppBindArgs;
1601 }
1602
1603 private final void setFocusedActivityLocked(HistoryRecord r) {
1604 if (mFocusedActivity != r) {
1605 mFocusedActivity = r;
1606 mWindowManager.setFocusedApp(r, true);
1607 }
1608 }
1609
1610 private final void updateLRUListLocked(ProcessRecord app,
1611 boolean oomAdj) {
1612 // put it on the LRU to keep track of when it should be exited.
1613 int lrui = mLRUProcesses.indexOf(app);
1614 if (lrui >= 0) mLRUProcesses.remove(lrui);
1615 mLRUProcesses.add(app);
1616 //Log.i(TAG, "Putting proc to front: " + app.processName);
1617 if (oomAdj) {
1618 updateOomAdjLocked();
1619 }
1620 }
1621
1622 private final boolean updateLRUListLocked(HistoryRecord r) {
1623 final boolean hadit = mLRUActivities.remove(r);
1624 mLRUActivities.add(r);
1625 return hadit;
1626 }
1627
1628 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1629 int i = mHistory.size()-1;
1630 while (i >= 0) {
1631 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1632 if (!r.finishing && r != notTop) {
1633 return r;
1634 }
1635 i--;
1636 }
1637 return null;
1638 }
1639
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001640 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1641 int i = mHistory.size()-1;
1642 while (i >= 0) {
1643 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1644 if (!r.finishing && !r.delayedResume && r != notTop) {
1645 return r;
1646 }
1647 i--;
1648 }
1649 return null;
1650 }
1651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 /**
1653 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001654 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 *
1656 * @param token If non-null, any history records matching this token will be skipped.
1657 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1658 *
1659 * @return Returns the HistoryRecord of the next activity on the stack.
1660 */
1661 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1662 int i = mHistory.size()-1;
1663 while (i >= 0) {
1664 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1665 // Note: the taskId check depends on real taskId fields being non-zero
1666 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1667 return r;
1668 }
1669 i--;
1670 }
1671 return null;
1672 }
1673
1674 private final ProcessRecord getProcessRecordLocked(
1675 String processName, int uid) {
1676 if (uid == Process.SYSTEM_UID) {
1677 // The system gets to run in any process. If there are multiple
1678 // processes with the same uid, just pick the first (this
1679 // should never happen).
1680 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1681 processName);
1682 return procs != null ? procs.valueAt(0) : null;
1683 }
1684 ProcessRecord proc = mProcessNames.get(processName, uid);
1685 return proc;
1686 }
1687
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001688 private void ensurePackageDexOpt(String packageName) {
1689 IPackageManager pm = ActivityThread.getPackageManager();
1690 try {
1691 if (pm.performDexOpt(packageName)) {
1692 mDidDexOpt = true;
1693 }
1694 } catch (RemoteException e) {
1695 }
1696 }
1697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 private boolean isNextTransitionForward() {
1699 int transit = mWindowManager.getPendingAppTransition();
1700 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1701 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1702 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1703 }
1704
1705 private final boolean realStartActivityLocked(HistoryRecord r,
1706 ProcessRecord app, boolean andResume, boolean checkConfig)
1707 throws RemoteException {
1708
1709 r.startFreezingScreenLocked(app, 0);
1710 mWindowManager.setAppVisibility(r, true);
1711
1712 // Have the window manager re-evaluate the orientation of
1713 // the screen based on the new activity order. Note that
1714 // as a result of this, it can call back into the activity
1715 // manager with a new orientation. We don't care about that,
1716 // because the activity is not currently running so we are
1717 // just restarting it anyway.
1718 if (checkConfig) {
1719 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001720 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 r.mayFreezeScreenLocked(app) ? r : null);
1722 updateConfigurationLocked(config, r);
1723 }
1724
1725 r.app = app;
1726
1727 if (localLOGV) Log.v(TAG, "Launching: " + r);
1728
1729 int idx = app.activities.indexOf(r);
1730 if (idx < 0) {
1731 app.activities.add(r);
1732 }
1733 updateLRUListLocked(app, true);
1734
1735 try {
1736 if (app.thread == null) {
1737 throw new RemoteException();
1738 }
1739 List<ResultInfo> results = null;
1740 List<Intent> newIntents = null;
1741 if (andResume) {
1742 results = r.results;
1743 newIntents = r.newIntents;
1744 }
1745 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1746 + " icicle=" + r.icicle
1747 + " with results=" + results + " newIntents=" + newIntents
1748 + " andResume=" + andResume);
1749 if (andResume) {
1750 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1751 System.identityHashCode(r),
1752 r.task.taskId, r.shortComponentName);
1753 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001754 if (r.isHomeActivity) {
1755 mHomeProcess = app;
1756 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001757 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001758 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001759 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001760 r.info, r.icicle, results, newIntents, !andResume,
1761 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 } catch (RemoteException e) {
1763 if (r.launchFailed) {
1764 // This is the second time we failed -- finish activity
1765 // and give up.
1766 Log.e(TAG, "Second failure launching "
1767 + r.intent.getComponent().flattenToShortString()
1768 + ", giving up", e);
1769 appDiedLocked(app, app.pid, app.thread);
1770 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1771 "2nd-crash");
1772 return false;
1773 }
1774
1775 // This is the first time we failed -- restart process and
1776 // retry.
1777 app.activities.remove(r);
1778 throw e;
1779 }
1780
1781 r.launchFailed = false;
1782 if (updateLRUListLocked(r)) {
1783 Log.w(TAG, "Activity " + r
1784 + " being launched, but already in LRU list");
1785 }
1786
1787 if (andResume) {
1788 // As part of the process of launching, ActivityThread also performs
1789 // a resume.
1790 r.state = ActivityState.RESUMED;
1791 r.icicle = null;
1792 r.haveState = false;
1793 r.stopped = false;
1794 mResumedActivity = r;
1795 r.task.touchActiveTime();
1796 completeResumeLocked(r);
1797 pauseIfSleepingLocked();
1798 } else {
1799 // This activity is not starting in the resumed state... which
1800 // should look like we asked it to pause+stop (but remain visible),
1801 // and it has done so and reported back the current icicle and
1802 // other state.
1803 r.state = ActivityState.STOPPED;
1804 r.stopped = true;
1805 }
1806
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001807 // Launch the new version setup screen if needed. We do this -after-
1808 // launching the initial activity (that is, home), so that it can have
1809 // a chance to initialize itself while in the background, making the
1810 // switch back to it faster and look better.
1811 startSetupActivityLocked();
1812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 return true;
1814 }
1815
1816 private final void startSpecificActivityLocked(HistoryRecord r,
1817 boolean andResume, boolean checkConfig) {
1818 // Is this activity's application already running?
1819 ProcessRecord app = getProcessRecordLocked(r.processName,
1820 r.info.applicationInfo.uid);
1821
1822 if (r.startTime == 0) {
1823 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001824 if (mInitialStartTime == 0) {
1825 mInitialStartTime = r.startTime;
1826 }
1827 } else if (mInitialStartTime == 0) {
1828 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 }
1830
1831 if (app != null && app.thread != null) {
1832 try {
1833 realStartActivityLocked(r, app, andResume, checkConfig);
1834 return;
1835 } catch (RemoteException e) {
1836 Log.w(TAG, "Exception when starting activity "
1837 + r.intent.getComponent().flattenToShortString(), e);
1838 }
1839
1840 // If a dead object exception was thrown -- fall through to
1841 // restart the application.
1842 }
1843
1844 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1845 "activity", r.intent.getComponent());
1846 }
1847
1848 private final ProcessRecord startProcessLocked(String processName,
1849 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1850 String hostingType, ComponentName hostingName) {
1851 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1852 // We don't have to do anything more if:
1853 // (1) There is an existing application record; and
1854 // (2) The caller doesn't think it is dead, OR there is no thread
1855 // object attached to it so we know it couldn't have crashed; and
1856 // (3) There is a pid assigned to it, so it is either starting or
1857 // already running.
1858 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1859 + " app=" + app + " knownToBeDead=" + knownToBeDead
1860 + " thread=" + (app != null ? app.thread : null)
1861 + " pid=" + (app != null ? app.pid : -1));
1862 if (app != null &&
1863 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1864 return app;
1865 }
1866
1867 String hostingNameStr = hostingName != null
1868 ? hostingName.flattenToShortString() : null;
1869
1870 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1871 // If we are in the background, then check to see if this process
1872 // is bad. If so, we will just silently fail.
1873 if (mBadProcesses.get(info.processName, info.uid) != null) {
1874 return null;
1875 }
1876 } else {
1877 // When the user is explicitly starting a process, then clear its
1878 // crash count so that we won't make it bad until they see at
1879 // least one crash dialog again, and make the process good again
1880 // if it had been bad.
1881 mProcessCrashTimes.remove(info.processName, info.uid);
1882 if (mBadProcesses.get(info.processName, info.uid) != null) {
1883 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1884 info.processName);
1885 mBadProcesses.remove(info.processName, info.uid);
1886 if (app != null) {
1887 app.bad = false;
1888 }
1889 }
1890 }
1891
1892 if (app == null) {
1893 app = newProcessRecordLocked(null, info, processName);
1894 mProcessNames.put(processName, info.uid, app);
1895 } else {
1896 // If this is a new package in the process, add the package to the list
1897 app.addPackage(info.packageName);
1898 }
1899
1900 // If the system is not ready yet, then hold off on starting this
1901 // process until it is.
1902 if (!mSystemReady
1903 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1904 if (!mProcessesOnHold.contains(app)) {
1905 mProcessesOnHold.add(app);
1906 }
1907 return app;
1908 }
1909
1910 startProcessLocked(app, hostingType, hostingNameStr);
1911 return (app.pid != 0) ? app : null;
1912 }
1913
1914 private final void startProcessLocked(ProcessRecord app,
1915 String hostingType, String hostingNameStr) {
1916 if (app.pid > 0 && app.pid != MY_PID) {
1917 synchronized (mPidsSelfLocked) {
1918 mPidsSelfLocked.remove(app.pid);
1919 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1920 }
1921 app.pid = 0;
1922 }
1923
1924 mProcessesOnHold.remove(app);
1925
1926 updateCpuStats();
1927
1928 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1929 mProcDeaths[0] = 0;
1930
1931 try {
1932 int uid = app.info.uid;
1933 int[] gids = null;
1934 try {
1935 gids = mContext.getPackageManager().getPackageGids(
1936 app.info.packageName);
1937 } catch (PackageManager.NameNotFoundException e) {
1938 Log.w(TAG, "Unable to retrieve gids", e);
1939 }
1940 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1941 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1942 && mTopComponent != null
1943 && app.processName.equals(mTopComponent.getPackageName())) {
1944 uid = 0;
1945 }
1946 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1947 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1948 uid = 0;
1949 }
1950 }
1951 int debugFlags = 0;
1952 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1953 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1954 }
1955 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1956 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1957 }
1958 if ("1".equals(SystemProperties.get("debug.assert"))) {
1959 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1960 }
1961 int pid = Process.start("android.app.ActivityThread",
1962 mSimpleProcessManagement ? app.processName : null, uid, uid,
1963 gids, debugFlags, null);
1964 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1965 synchronized (bs) {
1966 if (bs.isOnBattery()) {
1967 app.batteryStats.incStartsLocked();
1968 }
1969 }
1970
1971 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1972 app.processName, hostingType,
1973 hostingNameStr != null ? hostingNameStr : "");
1974
1975 if (app.persistent) {
1976 Watchdog.getInstance().processStarted(app, app.processName, pid);
1977 }
1978
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001979 StringBuilder buf = mStringBuilder;
1980 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 buf.append("Start proc ");
1982 buf.append(app.processName);
1983 buf.append(" for ");
1984 buf.append(hostingType);
1985 if (hostingNameStr != null) {
1986 buf.append(" ");
1987 buf.append(hostingNameStr);
1988 }
1989 buf.append(": pid=");
1990 buf.append(pid);
1991 buf.append(" uid=");
1992 buf.append(uid);
1993 buf.append(" gids={");
1994 if (gids != null) {
1995 for (int gi=0; gi<gids.length; gi++) {
1996 if (gi != 0) buf.append(", ");
1997 buf.append(gids[gi]);
1998
1999 }
2000 }
2001 buf.append("}");
2002 Log.i(TAG, buf.toString());
2003 if (pid == 0 || pid == MY_PID) {
2004 // Processes are being emulated with threads.
2005 app.pid = MY_PID;
2006 app.removed = false;
2007 mStartingProcesses.add(app);
2008 } else if (pid > 0) {
2009 app.pid = pid;
2010 app.removed = false;
2011 synchronized (mPidsSelfLocked) {
2012 this.mPidsSelfLocked.put(pid, app);
2013 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2014 msg.obj = app;
2015 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2016 }
2017 } else {
2018 app.pid = 0;
2019 RuntimeException e = new RuntimeException(
2020 "Failure starting process " + app.processName
2021 + ": returned pid=" + pid);
2022 Log.e(TAG, e.getMessage(), e);
2023 }
2024 } catch (RuntimeException e) {
2025 // XXX do better error recovery.
2026 app.pid = 0;
2027 Log.e(TAG, "Failure starting process " + app.processName, e);
2028 }
2029 }
2030
2031 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2032 if (mPausingActivity != null) {
2033 RuntimeException e = new RuntimeException();
2034 Log.e(TAG, "Trying to pause when pause is already pending for "
2035 + mPausingActivity, e);
2036 }
2037 HistoryRecord prev = mResumedActivity;
2038 if (prev == null) {
2039 RuntimeException e = new RuntimeException();
2040 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2041 resumeTopActivityLocked(null);
2042 return;
2043 }
2044 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2045 mResumedActivity = null;
2046 mPausingActivity = prev;
2047 mLastPausedActivity = prev;
2048 prev.state = ActivityState.PAUSING;
2049 prev.task.touchActiveTime();
2050
2051 updateCpuStats();
2052
2053 if (prev.app != null && prev.app.thread != null) {
2054 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2055 try {
2056 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2057 System.identityHashCode(prev),
2058 prev.shortComponentName);
2059 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2060 prev.configChangeFlags);
2061 updateUsageStats(prev, false);
2062 } catch (Exception e) {
2063 // Ignore exception, if process died other code will cleanup.
2064 Log.w(TAG, "Exception thrown during pause", e);
2065 mPausingActivity = null;
2066 mLastPausedActivity = null;
2067 }
2068 } else {
2069 mPausingActivity = null;
2070 mLastPausedActivity = null;
2071 }
2072
2073 // If we are not going to sleep, we want to ensure the device is
2074 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002075 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002076 mLaunchingActivity.acquire();
2077 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2078 // To be safe, don't allow the wake lock to be held for too long.
2079 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2080 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2081 }
2082 }
2083
2084
2085 if (mPausingActivity != null) {
2086 // Have the window manager pause its key dispatching until the new
2087 // activity has started. If we're pausing the activity just because
2088 // the screen is being turned off and the UI is sleeping, don't interrupt
2089 // key dispatch; the same activity will pick it up again on wakeup.
2090 if (!uiSleeping) {
2091 prev.pauseKeyDispatchingLocked();
2092 } else {
2093 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2094 }
2095
2096 // Schedule a pause timeout in case the app doesn't respond.
2097 // We don't give it much time because this directly impacts the
2098 // responsiveness seen by the user.
2099 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2100 msg.obj = prev;
2101 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2102 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2103 } else {
2104 // This activity failed to schedule the
2105 // pause, so just treat it as being paused now.
2106 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2107 resumeTopActivityLocked(null);
2108 }
2109 }
2110
2111 private final void completePauseLocked() {
2112 HistoryRecord prev = mPausingActivity;
2113 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2114
2115 if (prev != null) {
2116 if (prev.finishing) {
2117 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2118 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2119 } else if (prev.app != null) {
2120 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2121 if (prev.waitingVisible) {
2122 prev.waitingVisible = false;
2123 mWaitingVisibleActivities.remove(prev);
2124 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2125 TAG, "Complete pause, no longer waiting: " + prev);
2126 }
2127 if (prev.configDestroy) {
2128 // The previous is being paused because the configuration
2129 // is changing, which means it is actually stopping...
2130 // To juggle the fact that we are also starting a new
2131 // instance right now, we need to first completely stop
2132 // the current instance before starting the new one.
2133 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2134 destroyActivityLocked(prev, true);
2135 } else {
2136 mStoppingActivities.add(prev);
2137 if (mStoppingActivities.size() > 3) {
2138 // If we already have a few activities waiting to stop,
2139 // then give up on things going idle and start clearing
2140 // them out.
2141 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2142 Message msg = Message.obtain();
2143 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2144 mHandler.sendMessage(msg);
2145 }
2146 }
2147 } else {
2148 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2149 prev = null;
2150 }
2151 mPausingActivity = null;
2152 }
2153
Dianne Hackborn55280a92009-05-07 15:53:46 -07002154 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 resumeTopActivityLocked(prev);
2156 } else {
2157 if (mGoingToSleep.isHeld()) {
2158 mGoingToSleep.release();
2159 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002160 if (mShuttingDown) {
2161 notifyAll();
2162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 }
2164
2165 if (prev != null) {
2166 prev.resumeKeyDispatchingLocked();
2167 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002168
2169 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2170 long diff = 0;
2171 synchronized (mProcessStatsThread) {
2172 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2173 }
2174 if (diff > 0) {
2175 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2176 synchronized (bsi) {
2177 BatteryStatsImpl.Uid.Proc ps =
2178 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2179 prev.info.packageName);
2180 if (ps != null) {
2181 ps.addForegroundTimeLocked(diff);
2182 }
2183 }
2184 }
2185 }
2186 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 }
2188
2189 /**
2190 * Once we know that we have asked an application to put an activity in
2191 * the resumed state (either by launching it or explicitly telling it),
2192 * this function updates the rest of our state to match that fact.
2193 */
2194 private final void completeResumeLocked(HistoryRecord next) {
2195 next.idle = false;
2196 next.results = null;
2197 next.newIntents = null;
2198
2199 // schedule an idle timeout in case the app doesn't do it for us.
2200 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2201 msg.obj = next;
2202 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2203
2204 if (false) {
2205 // The activity was never told to pause, so just keep
2206 // things going as-is. To maintain our own state,
2207 // we need to emulate it coming back and saying it is
2208 // idle.
2209 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2210 msg.obj = next;
2211 mHandler.sendMessage(msg);
2212 }
2213
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002214 reportResumedActivity(next);
2215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 next.thumbnail = null;
2217 setFocusedActivityLocked(next);
2218 next.resumeKeyDispatchingLocked();
2219 ensureActivitiesVisibleLocked(null, 0);
2220 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002221
2222 // Mark the point when the activity is resuming
2223 // TODO: To be more accurate, the mark should be before the onCreate,
2224 // not after the onResume. But for subsequent starts, onResume is fine.
2225 if (next.app != null) {
2226 synchronized (mProcessStatsThread) {
2227 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2228 }
2229 } else {
2230 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232 }
2233
2234 /**
2235 * Make sure that all activities that need to be visible (that is, they
2236 * currently can be seen by the user) actually are.
2237 */
2238 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2239 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2240 if (DEBUG_VISBILITY) Log.v(
2241 TAG, "ensureActivitiesVisible behind " + top
2242 + " configChanges=0x" + Integer.toHexString(configChanges));
2243
2244 // If the top activity is not fullscreen, then we need to
2245 // make sure any activities under it are now visible.
2246 final int count = mHistory.size();
2247 int i = count-1;
2248 while (mHistory.get(i) != top) {
2249 i--;
2250 }
2251 HistoryRecord r;
2252 boolean behindFullscreen = false;
2253 for (; i>=0; i--) {
2254 r = (HistoryRecord)mHistory.get(i);
2255 if (DEBUG_VISBILITY) Log.v(
2256 TAG, "Make visible? " + r + " finishing=" + r.finishing
2257 + " state=" + r.state);
2258 if (r.finishing) {
2259 continue;
2260 }
2261
2262 final boolean doThisProcess = onlyThisProcess == null
2263 || onlyThisProcess.equals(r.processName);
2264
2265 // First: if this is not the current activity being started, make
2266 // sure it matches the current configuration.
2267 if (r != starting && doThisProcess) {
2268 ensureActivityConfigurationLocked(r, 0);
2269 }
2270
2271 if (r.app == null || r.app.thread == null) {
2272 if (onlyThisProcess == null
2273 || onlyThisProcess.equals(r.processName)) {
2274 // This activity needs to be visible, but isn't even
2275 // running... get it started, but don't resume it
2276 // at this point.
2277 if (DEBUG_VISBILITY) Log.v(
2278 TAG, "Start and freeze screen for " + r);
2279 if (r != starting) {
2280 r.startFreezingScreenLocked(r.app, configChanges);
2281 }
2282 if (!r.visible) {
2283 if (DEBUG_VISBILITY) Log.v(
2284 TAG, "Starting and making visible: " + r);
2285 mWindowManager.setAppVisibility(r, true);
2286 }
2287 if (r != starting) {
2288 startSpecificActivityLocked(r, false, false);
2289 }
2290 }
2291
2292 } else if (r.visible) {
2293 // If this activity is already visible, then there is nothing
2294 // else to do here.
2295 if (DEBUG_VISBILITY) Log.v(
2296 TAG, "Skipping: already visible at " + r);
2297 r.stopFreezingScreenLocked(false);
2298
2299 } else if (onlyThisProcess == null) {
2300 // This activity is not currently visible, but is running.
2301 // Tell it to become visible.
2302 r.visible = true;
2303 if (r.state != ActivityState.RESUMED && r != starting) {
2304 // If this activity is paused, tell it
2305 // to now show its window.
2306 if (DEBUG_VISBILITY) Log.v(
2307 TAG, "Making visible and scheduling visibility: " + r);
2308 try {
2309 mWindowManager.setAppVisibility(r, true);
2310 r.app.thread.scheduleWindowVisibility(r, true);
2311 r.stopFreezingScreenLocked(false);
2312 } catch (Exception e) {
2313 // Just skip on any failure; we'll make it
2314 // visible when it next restarts.
2315 Log.w(TAG, "Exception thrown making visibile: "
2316 + r.intent.getComponent(), e);
2317 }
2318 }
2319 }
2320
2321 // Aggregate current change flags.
2322 configChanges |= r.configChangeFlags;
2323
2324 if (r.fullscreen) {
2325 // At this point, nothing else needs to be shown
2326 if (DEBUG_VISBILITY) Log.v(
2327 TAG, "Stopping: fullscreen at " + r);
2328 behindFullscreen = true;
2329 i--;
2330 break;
2331 }
2332 }
2333
2334 // Now for any activities that aren't visible to the user, make
2335 // sure they no longer are keeping the screen frozen.
2336 while (i >= 0) {
2337 r = (HistoryRecord)mHistory.get(i);
2338 if (DEBUG_VISBILITY) Log.v(
2339 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2340 + " state=" + r.state
2341 + " behindFullscreen=" + behindFullscreen);
2342 if (!r.finishing) {
2343 if (behindFullscreen) {
2344 if (r.visible) {
2345 if (DEBUG_VISBILITY) Log.v(
2346 TAG, "Making invisible: " + r);
2347 r.visible = false;
2348 try {
2349 mWindowManager.setAppVisibility(r, false);
2350 if ((r.state == ActivityState.STOPPING
2351 || r.state == ActivityState.STOPPED)
2352 && r.app != null && r.app.thread != null) {
2353 if (DEBUG_VISBILITY) Log.v(
2354 TAG, "Scheduling invisibility: " + r);
2355 r.app.thread.scheduleWindowVisibility(r, false);
2356 }
2357 } catch (Exception e) {
2358 // Just skip on any failure; we'll make it
2359 // visible when it next restarts.
2360 Log.w(TAG, "Exception thrown making hidden: "
2361 + r.intent.getComponent(), e);
2362 }
2363 } else {
2364 if (DEBUG_VISBILITY) Log.v(
2365 TAG, "Already invisible: " + r);
2366 }
2367 } else if (r.fullscreen) {
2368 if (DEBUG_VISBILITY) Log.v(
2369 TAG, "Now behindFullscreen: " + r);
2370 behindFullscreen = true;
2371 }
2372 }
2373 i--;
2374 }
2375 }
2376
2377 /**
2378 * Version of ensureActivitiesVisible that can easily be called anywhere.
2379 */
2380 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2381 int configChanges) {
2382 HistoryRecord r = topRunningActivityLocked(null);
2383 if (r != null) {
2384 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2385 }
2386 }
2387
2388 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2389 if (resumed) {
2390 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2391 } else {
2392 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2393 }
2394 }
2395
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002396 private boolean startHomeActivityLocked() {
2397 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2398 && mTopAction == null) {
2399 // We are running in factory test mode, but unable to find
2400 // the factory test app, so just sit around displaying the
2401 // error message and don't try to start anything.
2402 return false;
2403 }
2404 Intent intent = new Intent(
2405 mTopAction,
2406 mTopData != null ? Uri.parse(mTopData) : null);
2407 intent.setComponent(mTopComponent);
2408 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2409 intent.addCategory(Intent.CATEGORY_HOME);
2410 }
2411 ActivityInfo aInfo =
2412 intent.resolveActivityInfo(mContext.getPackageManager(),
2413 STOCK_PM_FLAGS);
2414 if (aInfo != null) {
2415 intent.setComponent(new ComponentName(
2416 aInfo.applicationInfo.packageName, aInfo.name));
2417 // Don't do this if the home app is currently being
2418 // instrumented.
2419 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2420 aInfo.applicationInfo.uid);
2421 if (app == null || app.instrumentationClass == null) {
2422 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2423 startActivityLocked(null, intent, null, null, 0, aInfo,
2424 null, null, 0, 0, 0, false, false);
2425 }
2426 }
2427
2428
2429 return true;
2430 }
2431
2432 /**
2433 * Starts the "new version setup screen" if appropriate.
2434 */
2435 private void startSetupActivityLocked() {
2436 // Only do this once per boot.
2437 if (mCheckedForSetup) {
2438 return;
2439 }
2440
2441 // We will show this screen if the current one is a different
2442 // version than the last one shown, and we are not running in
2443 // low-level factory test mode.
2444 final ContentResolver resolver = mContext.getContentResolver();
2445 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2446 Settings.Secure.getInt(resolver,
2447 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2448 mCheckedForSetup = true;
2449
2450 // See if we should be showing the platform update setup UI.
2451 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2452 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2453 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2454
2455 // We don't allow third party apps to replace this.
2456 ResolveInfo ri = null;
2457 for (int i=0; ris != null && i<ris.size(); i++) {
2458 if ((ris.get(i).activityInfo.applicationInfo.flags
2459 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2460 ri = ris.get(i);
2461 break;
2462 }
2463 }
2464
2465 if (ri != null) {
2466 String vers = ri.activityInfo.metaData != null
2467 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2468 : null;
2469 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2470 vers = ri.activityInfo.applicationInfo.metaData.getString(
2471 Intent.METADATA_SETUP_VERSION);
2472 }
2473 String lastVers = Settings.Secure.getString(
2474 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2475 if (vers != null && !vers.equals(lastVers)) {
2476 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2477 intent.setComponent(new ComponentName(
2478 ri.activityInfo.packageName, ri.activityInfo.name));
2479 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2480 null, null, 0, 0, 0, false, false);
2481 }
2482 }
2483 }
2484 }
2485
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002486 private void reportResumedActivity(HistoryRecord r) {
2487 //Log.i(TAG, "**** REPORT RESUME: " + r);
2488
2489 final int identHash = System.identityHashCode(r);
2490 updateUsageStats(r, true);
2491
2492 int i = mWatchers.beginBroadcast();
2493 while (i > 0) {
2494 i--;
2495 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2496 if (w != null) {
2497 try {
2498 w.activityResuming(identHash);
2499 } catch (RemoteException e) {
2500 }
2501 }
2502 }
2503 mWatchers.finishBroadcast();
2504 }
2505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002506 /**
2507 * Ensure that the top activity in the stack is resumed.
2508 *
2509 * @param prev The previously resumed activity, for when in the process
2510 * of pausing; can be null to call from elsewhere.
2511 *
2512 * @return Returns true if something is being resumed, or false if
2513 * nothing happened.
2514 */
2515 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2516 // Find the first activity that is not finishing.
2517 HistoryRecord next = topRunningActivityLocked(null);
2518
2519 // Remember how we'll process this pause/resume situation, and ensure
2520 // that the state is reset however we wind up proceeding.
2521 final boolean userLeaving = mUserLeaving;
2522 mUserLeaving = false;
2523
2524 if (next == null) {
2525 // There are no more activities! Let's just start up the
2526 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002527 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002528 }
2529
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002530 next.delayedResume = false;
2531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532 // If the top activity is the resumed one, nothing to do.
2533 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2534 // Make sure we have executed any pending transitions, since there
2535 // should be nothing left to do at this point.
2536 mWindowManager.executeAppTransition();
2537 return false;
2538 }
2539
2540 // If we are sleeping, and there is no resumed activity, and the top
2541 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002542 if ((mSleeping || mShuttingDown)
2543 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002544 // Make sure we have executed any pending transitions, since there
2545 // should be nothing left to do at this point.
2546 mWindowManager.executeAppTransition();
2547 return false;
2548 }
2549
2550 // The activity may be waiting for stop, but that is no longer
2551 // appropriate for it.
2552 mStoppingActivities.remove(next);
2553 mWaitingVisibleActivities.remove(next);
2554
2555 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2556
2557 // If we are currently pausing an activity, then don't do anything
2558 // until that is done.
2559 if (mPausingActivity != null) {
2560 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2561 return false;
2562 }
2563
2564 // We need to start pausing the current activity so the top one
2565 // can be resumed...
2566 if (mResumedActivity != null) {
2567 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2568 startPausingLocked(userLeaving, false);
2569 return true;
2570 }
2571
2572 if (prev != null && prev != next) {
2573 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2574 prev.waitingVisible = true;
2575 mWaitingVisibleActivities.add(prev);
2576 if (DEBUG_SWITCH) Log.v(
2577 TAG, "Resuming top, waiting visible to hide: " + prev);
2578 } else {
2579 // The next activity is already visible, so hide the previous
2580 // activity's windows right now so we can show the new one ASAP.
2581 // We only do this if the previous is finishing, which should mean
2582 // it is on top of the one being resumed so hiding it quickly
2583 // is good. Otherwise, we want to do the normal route of allowing
2584 // the resumed activity to be shown so we can decide if the
2585 // previous should actually be hidden depending on whether the
2586 // new one is found to be full-screen or not.
2587 if (prev.finishing) {
2588 mWindowManager.setAppVisibility(prev, false);
2589 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2590 + prev + ", waitingVisible="
2591 + (prev != null ? prev.waitingVisible : null)
2592 + ", nowVisible=" + next.nowVisible);
2593 } else {
2594 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2595 + prev + ", waitingVisible="
2596 + (prev != null ? prev.waitingVisible : null)
2597 + ", nowVisible=" + next.nowVisible);
2598 }
2599 }
2600 }
2601
2602 // We are starting up the next activity, so tell the window manager
2603 // that the previous one will be hidden soon. This way it can know
2604 // to ignore it when computing the desired screen orientation.
2605 if (prev != null) {
2606 if (prev.finishing) {
2607 if (DEBUG_TRANSITION) Log.v(TAG,
2608 "Prepare close transition: prev=" + prev);
2609 mWindowManager.prepareAppTransition(prev.task == next.task
2610 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2611 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2612 mWindowManager.setAppWillBeHidden(prev);
2613 mWindowManager.setAppVisibility(prev, false);
2614 } else {
2615 if (DEBUG_TRANSITION) Log.v(TAG,
2616 "Prepare open transition: prev=" + prev);
2617 mWindowManager.prepareAppTransition(prev.task == next.task
2618 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2619 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2620 }
2621 if (false) {
2622 mWindowManager.setAppWillBeHidden(prev);
2623 mWindowManager.setAppVisibility(prev, false);
2624 }
2625 } else if (mHistory.size() > 1) {
2626 if (DEBUG_TRANSITION) Log.v(TAG,
2627 "Prepare open transition: no previous");
2628 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2629 }
2630
2631 if (next.app != null && next.app.thread != null) {
2632 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2633
2634 // This activity is now becoming visible.
2635 mWindowManager.setAppVisibility(next, true);
2636
2637 HistoryRecord lastResumedActivity = mResumedActivity;
2638 ActivityState lastState = next.state;
2639
2640 updateCpuStats();
2641
2642 next.state = ActivityState.RESUMED;
2643 mResumedActivity = next;
2644 next.task.touchActiveTime();
2645 updateLRUListLocked(next.app, true);
2646 updateLRUListLocked(next);
2647
2648 // Have the window manager re-evaluate the orientation of
2649 // the screen based on the new activity order.
2650 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002651 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 next.mayFreezeScreenLocked(next.app) ? next : null);
2653 if (config != null) {
2654 next.frozenBeforeDestroy = true;
2655 }
2656 if (!updateConfigurationLocked(config, next)) {
2657 // The configuration update wasn't able to keep the existing
2658 // instance of the activity, and instead started a new one.
2659 // We should be all done, but let's just make sure our activity
2660 // is still at the top and schedule another run if something
2661 // weird happened.
2662 HistoryRecord nextNext = topRunningActivityLocked(null);
2663 if (DEBUG_SWITCH) Log.i(TAG,
2664 "Activity config changed during resume: " + next
2665 + ", new next: " + nextNext);
2666 if (nextNext != next) {
2667 // Do over!
2668 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2669 }
2670 mWindowManager.executeAppTransition();
2671 return true;
2672 }
2673
2674 try {
2675 // Deliver all pending results.
2676 ArrayList a = next.results;
2677 if (a != null) {
2678 final int N = a.size();
2679 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002680 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002681 TAG, "Delivering results to " + next
2682 + ": " + a);
2683 next.app.thread.scheduleSendResult(next, a);
2684 }
2685 }
2686
2687 if (next.newIntents != null) {
2688 next.app.thread.scheduleNewIntent(next.newIntents, next);
2689 }
2690
2691 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2692 System.identityHashCode(next),
2693 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002694
2695 next.app.thread.scheduleResumeActivity(next,
2696 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002697
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002698 pauseIfSleepingLocked();
2699
2700 } catch (Exception e) {
2701 // Whoops, need to restart this activity!
2702 next.state = lastState;
2703 mResumedActivity = lastResumedActivity;
2704 if (Config.LOGD) Log.d(TAG,
2705 "Restarting because process died: " + next);
2706 if (!next.hasBeenLaunched) {
2707 next.hasBeenLaunched = true;
2708 } else {
2709 if (SHOW_APP_STARTING_ICON) {
2710 mWindowManager.setAppStartingWindow(
2711 next, next.packageName, next.theme,
2712 next.nonLocalizedLabel,
2713 next.labelRes, next.icon, null, true);
2714 }
2715 }
2716 startSpecificActivityLocked(next, true, false);
2717 return true;
2718 }
2719
2720 // From this point on, if something goes wrong there is no way
2721 // to recover the activity.
2722 try {
2723 next.visible = true;
2724 completeResumeLocked(next);
2725 } catch (Exception e) {
2726 // If any exception gets thrown, toss away this
2727 // activity and try the next one.
2728 Log.w(TAG, "Exception thrown during resume of " + next, e);
2729 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2730 "resume-exception");
2731 return true;
2732 }
2733
2734 // Didn't need to use the icicle, and it is now out of date.
2735 next.icicle = null;
2736 next.haveState = false;
2737 next.stopped = false;
2738
2739 } else {
2740 // Whoops, need to restart this activity!
2741 if (!next.hasBeenLaunched) {
2742 next.hasBeenLaunched = true;
2743 } else {
2744 if (SHOW_APP_STARTING_ICON) {
2745 mWindowManager.setAppStartingWindow(
2746 next, next.packageName, next.theme,
2747 next.nonLocalizedLabel,
2748 next.labelRes, next.icon, null, true);
2749 }
2750 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2751 }
2752 startSpecificActivityLocked(next, true, true);
2753 }
2754
2755 return true;
2756 }
2757
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002758 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2759 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002760 final int NH = mHistory.size();
2761
2762 int addPos = -1;
2763
2764 if (!newTask) {
2765 // If starting in an existing task, find where that is...
2766 HistoryRecord next = null;
2767 boolean startIt = true;
2768 for (int i = NH-1; i >= 0; i--) {
2769 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2770 if (p.finishing) {
2771 continue;
2772 }
2773 if (p.task == r.task) {
2774 // Here it is! Now, if this is not yet visible to the
2775 // user, then just add it without starting; it will
2776 // get started when the user navigates back to it.
2777 addPos = i+1;
2778 if (!startIt) {
2779 mHistory.add(addPos, r);
2780 r.inHistory = true;
2781 r.task.numActivities++;
2782 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2783 r.info.screenOrientation, r.fullscreen);
2784 if (VALIDATE_TOKENS) {
2785 mWindowManager.validateAppTokens(mHistory);
2786 }
2787 return;
2788 }
2789 break;
2790 }
2791 if (p.fullscreen) {
2792 startIt = false;
2793 }
2794 next = p;
2795 }
2796 }
2797
2798 // Place a new activity at top of stack, so it is next to interact
2799 // with the user.
2800 if (addPos < 0) {
2801 addPos = mHistory.size();
2802 }
2803
2804 // If we are not placing the new activity frontmost, we do not want
2805 // to deliver the onUserLeaving callback to the actual frontmost
2806 // activity
2807 if (addPos < NH) {
2808 mUserLeaving = false;
2809 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2810 }
2811
2812 // Slot the activity into the history stack and proceed
2813 mHistory.add(addPos, r);
2814 r.inHistory = true;
2815 r.frontOfTask = newTask;
2816 r.task.numActivities++;
2817 if (NH > 0) {
2818 // We want to show the starting preview window if we are
2819 // switching to a new task, or the next activity's process is
2820 // not currently running.
2821 boolean showStartingIcon = newTask;
2822 ProcessRecord proc = r.app;
2823 if (proc == null) {
2824 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2825 }
2826 if (proc == null || proc.thread == null) {
2827 showStartingIcon = true;
2828 }
2829 if (DEBUG_TRANSITION) Log.v(TAG,
2830 "Prepare open transition: starting " + r);
2831 mWindowManager.prepareAppTransition(newTask
2832 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2833 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2834 mWindowManager.addAppToken(
2835 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2836 boolean doShow = true;
2837 if (newTask) {
2838 // Even though this activity is starting fresh, we still need
2839 // to reset it to make sure we apply affinities to move any
2840 // existing activities from other tasks in to it.
2841 // If the caller has requested that the target task be
2842 // reset, then do so.
2843 if ((r.intent.getFlags()
2844 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2845 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002846 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002847 }
2848 }
2849 if (SHOW_APP_STARTING_ICON && doShow) {
2850 // Figure out if we are transitioning from another activity that is
2851 // "has the same starting icon" as the next one. This allows the
2852 // window manager to keep the previous window it had previously
2853 // created, if it still had one.
2854 HistoryRecord prev = mResumedActivity;
2855 if (prev != null) {
2856 // We don't want to reuse the previous starting preview if:
2857 // (1) The current activity is in a different task.
2858 if (prev.task != r.task) prev = null;
2859 // (2) The current activity is already displayed.
2860 else if (prev.nowVisible) prev = null;
2861 }
2862 mWindowManager.setAppStartingWindow(
2863 r, r.packageName, r.theme, r.nonLocalizedLabel,
2864 r.labelRes, r.icon, prev, showStartingIcon);
2865 }
2866 } else {
2867 // If this is the first activity, don't do any fancy animations,
2868 // because there is nothing for it to animate on top of.
2869 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2870 r.info.screenOrientation, r.fullscreen);
2871 }
2872 if (VALIDATE_TOKENS) {
2873 mWindowManager.validateAppTokens(mHistory);
2874 }
2875
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002876 if (doResume) {
2877 resumeTopActivityLocked(null);
2878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 }
2880
2881 /**
2882 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002883 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2884 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002885 * an instance of that activity in the stack and, if found, finish all
2886 * activities on top of it and return the instance.
2887 *
2888 * @param newR Description of the new activity being started.
2889 * @return Returns the old activity that should be continue to be used,
2890 * or null if none was found.
2891 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002892 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002893 HistoryRecord newR, boolean doClear) {
2894 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002895
2896 // First find the requested task.
2897 while (i > 0) {
2898 i--;
2899 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2900 if (r.task.taskId == taskId) {
2901 i++;
2902 break;
2903 }
2904 }
2905
2906 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002907 while (i > 0) {
2908 i--;
2909 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2910 if (r.finishing) {
2911 continue;
2912 }
2913 if (r.task.taskId != taskId) {
2914 return null;
2915 }
2916 if (r.realActivity.equals(newR.realActivity)) {
2917 // Here it is! Now finish everything in front...
2918 HistoryRecord ret = r;
2919 if (doClear) {
2920 while (i < (mHistory.size()-1)) {
2921 i++;
2922 r = (HistoryRecord)mHistory.get(i);
2923 if (r.finishing) {
2924 continue;
2925 }
2926 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2927 null, "clear")) {
2928 i--;
2929 }
2930 }
2931 }
2932
2933 // Finally, if this is a normal launch mode (that is, not
2934 // expecting onNewIntent()), then we will finish the current
2935 // instance of the activity so a new fresh one can be started.
2936 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2937 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002938 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939 if (index >= 0) {
2940 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2941 null, "clear");
2942 }
2943 return null;
2944 }
2945 }
2946
2947 return ret;
2948 }
2949 }
2950
2951 return null;
2952 }
2953
2954 /**
2955 * Find the activity in the history stack within the given task. Returns
2956 * the index within the history at which it's found, or < 0 if not found.
2957 */
2958 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2959 int i = mHistory.size();
2960 while (i > 0) {
2961 i--;
2962 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2963 if (candidate.task.taskId != task) {
2964 break;
2965 }
2966 if (candidate.realActivity.equals(r.realActivity)) {
2967 return i;
2968 }
2969 }
2970
2971 return -1;
2972 }
2973
2974 /**
2975 * Reorder the history stack so that the activity at the given index is
2976 * brought to the front.
2977 */
2978 private final HistoryRecord moveActivityToFrontLocked(int where) {
2979 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2980 int top = mHistory.size();
2981 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2982 mHistory.add(top, newTop);
2983 oldTop.frontOfTask = false;
2984 newTop.frontOfTask = true;
2985 return newTop;
2986 }
2987
2988 /**
2989 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2990 * method will be called at the proper time.
2991 */
2992 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2993 boolean sent = false;
2994 if (r.state == ActivityState.RESUMED
2995 && r.app != null && r.app.thread != null) {
2996 try {
2997 ArrayList<Intent> ar = new ArrayList<Intent>();
2998 ar.add(new Intent(intent));
2999 r.app.thread.scheduleNewIntent(ar, r);
3000 sent = true;
3001 } catch (Exception e) {
3002 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3003 }
3004 }
3005 if (!sent) {
3006 r.addNewIntentLocked(new Intent(intent));
3007 }
3008 }
3009
3010 private final void logStartActivity(int tag, HistoryRecord r,
3011 TaskRecord task) {
3012 EventLog.writeEvent(tag,
3013 System.identityHashCode(r), task.taskId,
3014 r.shortComponentName, r.intent.getAction(),
3015 r.intent.getType(), r.intent.getDataString(),
3016 r.intent.getFlags());
3017 }
3018
3019 private final int startActivityLocked(IApplicationThread caller,
3020 Intent intent, String resolvedType,
3021 Uri[] grantedUriPermissions,
3022 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3023 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003024 int callingPid, int callingUid, boolean onlyIfNeeded,
3025 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003026 Log.i(TAG, "Starting activity: " + intent);
3027
3028 HistoryRecord sourceRecord = null;
3029 HistoryRecord resultRecord = null;
3030 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003031 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003032 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003033 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3034 if (index >= 0) {
3035 sourceRecord = (HistoryRecord)mHistory.get(index);
3036 if (requestCode >= 0 && !sourceRecord.finishing) {
3037 resultRecord = sourceRecord;
3038 }
3039 }
3040 }
3041
3042 int launchFlags = intent.getFlags();
3043
3044 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3045 && sourceRecord != null) {
3046 // Transfer the result target from the source activity to the new
3047 // one being started, including any failures.
3048 if (requestCode >= 0) {
3049 return START_FORWARD_AND_REQUEST_CONFLICT;
3050 }
3051 resultRecord = sourceRecord.resultTo;
3052 resultWho = sourceRecord.resultWho;
3053 requestCode = sourceRecord.requestCode;
3054 sourceRecord.resultTo = null;
3055 if (resultRecord != null) {
3056 resultRecord.removeResultsLocked(
3057 sourceRecord, resultWho, requestCode);
3058 }
3059 }
3060
3061 int err = START_SUCCESS;
3062
3063 if (intent.getComponent() == null) {
3064 // We couldn't find a class that can handle the given Intent.
3065 // That's the end of that!
3066 err = START_INTENT_NOT_RESOLVED;
3067 }
3068
3069 if (err == START_SUCCESS && aInfo == null) {
3070 // We couldn't find the specific class specified in the Intent.
3071 // Also the end of the line.
3072 err = START_CLASS_NOT_FOUND;
3073 }
3074
3075 ProcessRecord callerApp = null;
3076 if (err == START_SUCCESS && caller != null) {
3077 callerApp = getRecordForAppLocked(caller);
3078 if (callerApp != null) {
3079 callingPid = callerApp.pid;
3080 callingUid = callerApp.info.uid;
3081 } else {
3082 Log.w(TAG, "Unable to find app for caller " + caller
3083 + " (pid=" + callingPid + ") when starting: "
3084 + intent.toString());
3085 err = START_PERMISSION_DENIED;
3086 }
3087 }
3088
3089 if (err != START_SUCCESS) {
3090 if (resultRecord != null) {
3091 sendActivityResultLocked(-1,
3092 resultRecord, resultWho, requestCode,
3093 Activity.RESULT_CANCELED, null);
3094 }
3095 return err;
3096 }
3097
3098 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3099 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3100 if (perm != PackageManager.PERMISSION_GRANTED) {
3101 if (resultRecord != null) {
3102 sendActivityResultLocked(-1,
3103 resultRecord, resultWho, requestCode,
3104 Activity.RESULT_CANCELED, null);
3105 }
3106 String msg = "Permission Denial: starting " + intent.toString()
3107 + " from " + callerApp + " (pid=" + callingPid
3108 + ", uid=" + callingUid + ")"
3109 + " requires " + aInfo.permission;
3110 Log.w(TAG, msg);
3111 throw new SecurityException(msg);
3112 }
3113
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003114 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003115 boolean abort = false;
3116 try {
3117 // The Intent we give to the watcher has the extra data
3118 // stripped off, since it can contain private information.
3119 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003120 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003121 aInfo.applicationInfo.packageName);
3122 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003123 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124 }
3125
3126 if (abort) {
3127 if (resultRecord != null) {
3128 sendActivityResultLocked(-1,
3129 resultRecord, resultWho, requestCode,
3130 Activity.RESULT_CANCELED, null);
3131 }
3132 // We pretend to the caller that it was really started, but
3133 // they will just get a cancel result.
3134 return START_SUCCESS;
3135 }
3136 }
3137
3138 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3139 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003140 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003142 if (mResumedActivity == null
3143 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3144 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3145 PendingActivityLaunch pal = new PendingActivityLaunch();
3146 pal.r = r;
3147 pal.sourceRecord = sourceRecord;
3148 pal.grantedUriPermissions = grantedUriPermissions;
3149 pal.grantedMode = grantedMode;
3150 pal.onlyIfNeeded = onlyIfNeeded;
3151 mPendingActivityLaunches.add(pal);
3152 return START_SWITCHES_CANCELED;
3153 }
3154 }
3155
3156 if (mDidAppSwitch) {
3157 // This is the second allowed switch since we stopped switches,
3158 // so now just generally allow switches. Use case: user presses
3159 // home (switches disabled, switch to home, mDidAppSwitch now true);
3160 // user taps a home icon (coming from home so allowed, we hit here
3161 // and now allow anyone to switch again).
3162 mAppSwitchesAllowedTime = 0;
3163 } else {
3164 mDidAppSwitch = true;
3165 }
3166
3167 doPendingActivityLaunchesLocked(false);
3168
3169 return startActivityUncheckedLocked(r, sourceRecord,
3170 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3171 }
3172
3173 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3174 final int N = mPendingActivityLaunches.size();
3175 if (N <= 0) {
3176 return;
3177 }
3178 for (int i=0; i<N; i++) {
3179 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3180 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3181 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3182 doResume && i == (N-1));
3183 }
3184 mPendingActivityLaunches.clear();
3185 }
3186
3187 private final int startActivityUncheckedLocked(HistoryRecord r,
3188 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3189 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3190 final Intent intent = r.intent;
3191 final int callingUid = r.launchedFromUid;
3192
3193 int launchFlags = intent.getFlags();
3194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 // We'll invoke onUserLeaving before onPause only if the launching
3196 // activity did not explicitly state that this is an automated launch.
3197 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3198 if (DEBUG_USER_LEAVING) Log.v(TAG,
3199 "startActivity() => mUserLeaving=" + mUserLeaving);
3200
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003201 // If the caller has asked not to resume at this point, we make note
3202 // of this in the record so that we can skip it when trying to find
3203 // the top running activity.
3204 if (!doResume) {
3205 r.delayedResume = true;
3206 }
3207
3208 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3209 != 0 ? r : null;
3210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003211 // If the onlyIfNeeded flag is set, then we can do this if the activity
3212 // being launched is the same as the one making the call... or, as
3213 // a special case, if we do not know the caller then we count the
3214 // current top activity as the caller.
3215 if (onlyIfNeeded) {
3216 HistoryRecord checkedCaller = sourceRecord;
3217 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003218 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 }
3220 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3221 // Caller is not the same as launcher, so always needed.
3222 onlyIfNeeded = false;
3223 }
3224 }
3225
3226 if (grantedUriPermissions != null && callingUid > 0) {
3227 for (int i=0; i<grantedUriPermissions.length; i++) {
3228 grantUriPermissionLocked(callingUid, r.packageName,
3229 grantedUriPermissions[i], grantedMode, r);
3230 }
3231 }
3232
3233 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3234 intent, r);
3235
3236 if (sourceRecord == null) {
3237 // This activity is not being started from another... in this
3238 // case we -always- start a new task.
3239 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3240 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3241 + intent);
3242 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3243 }
3244 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3245 // The original activity who is starting us is running as a single
3246 // instance... this new activity it is starting must go on its
3247 // own task.
3248 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3249 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3250 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3251 // The activity being started is a single instance... it always
3252 // gets launched into its own task.
3253 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3254 }
3255
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003256 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003257 // For whatever reason this activity is being launched into a new
3258 // task... yet the caller has requested a result back. Well, that
3259 // is pretty messed up, so instead immediately send back a cancel
3260 // and let the new task continue launched as normal without a
3261 // dependency on its originator.
3262 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3263 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003264 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 Activity.RESULT_CANCELED, null);
3266 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 }
3268
3269 boolean addingToTask = false;
3270 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3271 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3272 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3273 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3274 // If bring to front is requested, and no result is requested, and
3275 // we can find a task that was started with this same
3276 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003277 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003278 // See if there is a task to bring to the front. If this is
3279 // a SINGLE_INSTANCE activity, there can be one and only one
3280 // instance of it in the history, and it is always in its own
3281 // unique task, so we do a special search.
3282 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3283 ? findTaskLocked(intent, r.info)
3284 : findActivityLocked(intent, r.info);
3285 if (taskTop != null) {
3286 if (taskTop.task.intent == null) {
3287 // This task was started because of movement of
3288 // the activity based on affinity... now that we
3289 // are actually launching it, we can assign the
3290 // base intent.
3291 taskTop.task.setIntent(intent, r.info);
3292 }
3293 // If the target task is not in the front, then we need
3294 // to bring it to the front... except... well, with
3295 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3296 // to have the same behavior as if a new instance was
3297 // being started, which means not bringing it to the front
3298 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003299 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 if (curTop.task != taskTop.task) {
3301 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3302 boolean callerAtFront = sourceRecord == null
3303 || curTop.task == sourceRecord.task;
3304 if (callerAtFront) {
3305 // We really do want to push this one into the
3306 // user's face, right now.
3307 moveTaskToFrontLocked(taskTop.task);
3308 }
3309 }
3310 // If the caller has requested that the target task be
3311 // reset, then do so.
3312 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3313 taskTop = resetTaskIfNeededLocked(taskTop, r);
3314 }
3315 if (onlyIfNeeded) {
3316 // We don't need to start a new activity, and
3317 // the client said not to do anything if that
3318 // is the case, so this is it! And for paranoia, make
3319 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003320 if (doResume) {
3321 resumeTopActivityLocked(null);
3322 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003323 return START_RETURN_INTENT_TO_CALLER;
3324 }
3325 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3326 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3327 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3328 // In this situation we want to remove all activities
3329 // from the task up to the one being started. In most
3330 // cases this means we are resetting the task to its
3331 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003332 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 taskTop.task.taskId, r, true);
3334 if (top != null) {
3335 if (top.frontOfTask) {
3336 // Activity aliases may mean we use different
3337 // intents for the top activity, so make sure
3338 // the task now has the identity of the new
3339 // intent.
3340 top.task.setIntent(r.intent, r.info);
3341 }
3342 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3343 deliverNewIntentLocked(top, r.intent);
3344 } else {
3345 // A special case: we need to
3346 // start the activity because it is not currently
3347 // running, and the caller has asked to clear the
3348 // current task to have this activity at the top.
3349 addingToTask = true;
3350 // Now pretend like this activity is being started
3351 // by the top of its task, so it is put in the
3352 // right place.
3353 sourceRecord = taskTop;
3354 }
3355 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3356 // In this case the top activity on the task is the
3357 // same as the one being launched, so we take that
3358 // as a request to bring the task to the foreground.
3359 // If the top activity in the task is the root
3360 // activity, deliver this new intent to it if it
3361 // desires.
3362 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3363 && taskTop.realActivity.equals(r.realActivity)) {
3364 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3365 if (taskTop.frontOfTask) {
3366 taskTop.task.setIntent(r.intent, r.info);
3367 }
3368 deliverNewIntentLocked(taskTop, r.intent);
3369 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3370 // In this case we are launching the root activity
3371 // of the task, but with a different intent. We
3372 // should start a new instance on top.
3373 addingToTask = true;
3374 sourceRecord = taskTop;
3375 }
3376 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3377 // In this case an activity is being launched in to an
3378 // existing task, without resetting that task. This
3379 // is typically the situation of launching an activity
3380 // from a notification or shortcut. We want to place
3381 // the new activity on top of the current task.
3382 addingToTask = true;
3383 sourceRecord = taskTop;
3384 } else if (!taskTop.task.rootWasReset) {
3385 // In this case we are launching in to an existing task
3386 // that has not yet been started from its front door.
3387 // The current task has been brought to the front.
3388 // Ideally, we'd probably like to place this new task
3389 // at the bottom of its stack, but that's a little hard
3390 // to do with the current organization of the code so
3391 // for now we'll just drop it.
3392 taskTop.task.setIntent(r.intent, r.info);
3393 }
3394 if (!addingToTask) {
3395 // We didn't do anything... but it was needed (a.k.a., client
3396 // don't use that intent!) And for paranoia, make
3397 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003398 if (doResume) {
3399 resumeTopActivityLocked(null);
3400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003401 return START_TASK_TO_FRONT;
3402 }
3403 }
3404 }
3405 }
3406
3407 //String uri = r.intent.toURI();
3408 //Intent intent2 = new Intent(uri);
3409 //Log.i(TAG, "Given intent: " + r.intent);
3410 //Log.i(TAG, "URI is: " + uri);
3411 //Log.i(TAG, "To intent: " + intent2);
3412
3413 if (r.packageName != null) {
3414 // If the activity being launched is the same as the one currently
3415 // at the top, then we need to check if it should only be launched
3416 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003417 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3418 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003419 if (top.realActivity.equals(r.realActivity)) {
3420 if (top.app != null && top.app.thread != null) {
3421 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3422 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3423 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3424 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3425 // For paranoia, make sure we have correctly
3426 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003427 if (doResume) {
3428 resumeTopActivityLocked(null);
3429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 if (onlyIfNeeded) {
3431 // We don't need to start a new activity, and
3432 // the client said not to do anything if that
3433 // is the case, so this is it!
3434 return START_RETURN_INTENT_TO_CALLER;
3435 }
3436 deliverNewIntentLocked(top, r.intent);
3437 return START_DELIVERED_TO_TOP;
3438 }
3439 }
3440 }
3441 }
3442
3443 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003444 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003445 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003446 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003447 Activity.RESULT_CANCELED, null);
3448 }
3449 return START_CLASS_NOT_FOUND;
3450 }
3451
3452 boolean newTask = false;
3453
3454 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003455 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003456 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3457 // todo: should do better management of integers.
3458 mCurTask++;
3459 if (mCurTask <= 0) {
3460 mCurTask = 1;
3461 }
3462 r.task = new TaskRecord(mCurTask, r.info, intent,
3463 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3464 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3465 + " in new task " + r.task);
3466 newTask = true;
3467 addRecentTask(r.task);
3468
3469 } else if (sourceRecord != null) {
3470 if (!addingToTask &&
3471 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3472 // In this case, we are adding the activity to an existing
3473 // task, but the caller has asked to clear that task if the
3474 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003475 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 sourceRecord.task.taskId, r, true);
3477 if (top != null) {
3478 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3479 deliverNewIntentLocked(top, r.intent);
3480 // For paranoia, make sure we have correctly
3481 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003482 if (doResume) {
3483 resumeTopActivityLocked(null);
3484 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485 return START_DELIVERED_TO_TOP;
3486 }
3487 } else if (!addingToTask &&
3488 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3489 // In this case, we are launching an activity in our own task
3490 // that may already be running somewhere in the history, and
3491 // we want to shuffle it to the front of the stack if so.
3492 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3493 if (where >= 0) {
3494 HistoryRecord top = moveActivityToFrontLocked(where);
3495 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3496 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003497 if (doResume) {
3498 resumeTopActivityLocked(null);
3499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500 return START_DELIVERED_TO_TOP;
3501 }
3502 }
3503 // An existing activity is starting this new activity, so we want
3504 // to keep the new one in the same task as the one that is starting
3505 // it.
3506 r.task = sourceRecord.task;
3507 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3508 + " in existing task " + r.task);
3509
3510 } else {
3511 // This not being started from an existing activity, and not part
3512 // of a new task... just put it in the top task, though these days
3513 // this case should never happen.
3514 final int N = mHistory.size();
3515 HistoryRecord prev =
3516 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3517 r.task = prev != null
3518 ? prev.task
3519 : new TaskRecord(mCurTask, r.info, intent,
3520 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3521 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3522 + " in new guessed " + r.task);
3523 }
3524 if (newTask) {
3525 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3526 }
3527 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003528 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 return START_SUCCESS;
3530 }
3531
3532 public final int startActivity(IApplicationThread caller,
3533 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3534 int grantedMode, IBinder resultTo,
3535 String resultWho, int requestCode, boolean onlyIfNeeded,
3536 boolean debug) {
3537 // Refuse possible leaked file descriptors
3538 if (intent != null && intent.hasFileDescriptors()) {
3539 throw new IllegalArgumentException("File descriptors passed in Intent");
3540 }
3541
The Android Open Source Project4df24232009-03-05 14:34:35 -08003542 final boolean componentSpecified = intent.getComponent() != null;
3543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003544 // Don't modify the client's object!
3545 intent = new Intent(intent);
3546
3547 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003548 ActivityInfo aInfo;
3549 try {
3550 ResolveInfo rInfo =
3551 ActivityThread.getPackageManager().resolveIntent(
3552 intent, resolvedType,
3553 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003554 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 aInfo = rInfo != null ? rInfo.activityInfo : null;
3556 } catch (RemoteException e) {
3557 aInfo = null;
3558 }
3559
3560 if (aInfo != null) {
3561 // Store the found target back into the intent, because now that
3562 // we have it we never want to do this again. For example, if the
3563 // user navigates back to this point in the history, we should
3564 // always restart the exact same activity.
3565 intent.setComponent(new ComponentName(
3566 aInfo.applicationInfo.packageName, aInfo.name));
3567
3568 // Don't debug things in the system process
3569 if (debug) {
3570 if (!aInfo.processName.equals("system")) {
3571 setDebugApp(aInfo.processName, true, false);
3572 }
3573 }
3574 }
3575
3576 synchronized(this) {
3577 final long origId = Binder.clearCallingIdentity();
3578 int res = startActivityLocked(caller, intent, resolvedType,
3579 grantedUriPermissions, grantedMode, aInfo,
3580 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003581 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 Binder.restoreCallingIdentity(origId);
3583 return res;
3584 }
3585 }
3586
3587 public boolean startNextMatchingActivity(IBinder callingActivity,
3588 Intent intent) {
3589 // Refuse possible leaked file descriptors
3590 if (intent != null && intent.hasFileDescriptors() == true) {
3591 throw new IllegalArgumentException("File descriptors passed in Intent");
3592 }
3593
3594 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003595 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 if (index < 0) {
3597 return false;
3598 }
3599 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3600 if (r.app == null || r.app.thread == null) {
3601 // The caller is not running... d'oh!
3602 return false;
3603 }
3604 intent = new Intent(intent);
3605 // The caller is not allowed to change the data.
3606 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3607 // And we are resetting to find the next component...
3608 intent.setComponent(null);
3609
3610 ActivityInfo aInfo = null;
3611 try {
3612 List<ResolveInfo> resolves =
3613 ActivityThread.getPackageManager().queryIntentActivities(
3614 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003615 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003616
3617 // Look for the original activity in the list...
3618 final int N = resolves != null ? resolves.size() : 0;
3619 for (int i=0; i<N; i++) {
3620 ResolveInfo rInfo = resolves.get(i);
3621 if (rInfo.activityInfo.packageName.equals(r.packageName)
3622 && rInfo.activityInfo.name.equals(r.info.name)) {
3623 // We found the current one... the next matching is
3624 // after it.
3625 i++;
3626 if (i<N) {
3627 aInfo = resolves.get(i).activityInfo;
3628 }
3629 break;
3630 }
3631 }
3632 } catch (RemoteException e) {
3633 }
3634
3635 if (aInfo == null) {
3636 // Nobody who is next!
3637 return false;
3638 }
3639
3640 intent.setComponent(new ComponentName(
3641 aInfo.applicationInfo.packageName, aInfo.name));
3642 intent.setFlags(intent.getFlags()&~(
3643 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3644 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3645 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3646 Intent.FLAG_ACTIVITY_NEW_TASK));
3647
3648 // Okay now we need to start the new activity, replacing the
3649 // currently running activity. This is a little tricky because
3650 // we want to start the new one as if the current one is finished,
3651 // but not finish the current one first so that there is no flicker.
3652 // And thus...
3653 final boolean wasFinishing = r.finishing;
3654 r.finishing = true;
3655
3656 // Propagate reply information over to the new activity.
3657 final HistoryRecord resultTo = r.resultTo;
3658 final String resultWho = r.resultWho;
3659 final int requestCode = r.requestCode;
3660 r.resultTo = null;
3661 if (resultTo != null) {
3662 resultTo.removeResultsLocked(r, resultWho, requestCode);
3663 }
3664
3665 final long origId = Binder.clearCallingIdentity();
3666 // XXX we are not dealing with propagating grantedUriPermissions...
3667 // those are not yet exposed to user code, so there is no need.
3668 int res = startActivityLocked(r.app.thread, intent,
3669 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003670 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003671 Binder.restoreCallingIdentity(origId);
3672
3673 r.finishing = wasFinishing;
3674 if (res != START_SUCCESS) {
3675 return false;
3676 }
3677 return true;
3678 }
3679 }
3680
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003681 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682 Intent intent, String resolvedType, IBinder resultTo,
3683 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003684
3685 // This is so super not safe, that only the system (or okay root)
3686 // can do it.
3687 final int callingUid = Binder.getCallingUid();
3688 if (callingUid != 0 && callingUid != Process.myUid()) {
3689 throw new SecurityException(
3690 "startActivityInPackage only available to the system");
3691 }
3692
The Android Open Source Project4df24232009-03-05 14:34:35 -08003693 final boolean componentSpecified = intent.getComponent() != null;
3694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 // Don't modify the client's object!
3696 intent = new Intent(intent);
3697
3698 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003699 ActivityInfo aInfo;
3700 try {
3701 ResolveInfo rInfo =
3702 ActivityThread.getPackageManager().resolveIntent(
3703 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003704 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 aInfo = rInfo != null ? rInfo.activityInfo : null;
3706 } catch (RemoteException e) {
3707 aInfo = null;
3708 }
3709
3710 if (aInfo != null) {
3711 // Store the found target back into the intent, because now that
3712 // we have it we never want to do this again. For example, if the
3713 // user navigates back to this point in the history, we should
3714 // always restart the exact same activity.
3715 intent.setComponent(new ComponentName(
3716 aInfo.applicationInfo.packageName, aInfo.name));
3717 }
3718
3719 synchronized(this) {
3720 return startActivityLocked(null, intent, resolvedType,
3721 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003722 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 }
3724 }
3725
3726 private final void addRecentTask(TaskRecord task) {
3727 // Remove any existing entries that are the same kind of task.
3728 int N = mRecentTasks.size();
3729 for (int i=0; i<N; i++) {
3730 TaskRecord tr = mRecentTasks.get(i);
3731 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3732 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3733 mRecentTasks.remove(i);
3734 i--;
3735 N--;
3736 if (task.intent == null) {
3737 // If the new recent task we are adding is not fully
3738 // specified, then replace it with the existing recent task.
3739 task = tr;
3740 }
3741 }
3742 }
3743 if (N >= MAX_RECENT_TASKS) {
3744 mRecentTasks.remove(N-1);
3745 }
3746 mRecentTasks.add(0, task);
3747 }
3748
3749 public void setRequestedOrientation(IBinder token,
3750 int requestedOrientation) {
3751 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003752 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003753 if (index < 0) {
3754 return;
3755 }
3756 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3757 final long origId = Binder.clearCallingIdentity();
3758 mWindowManager.setAppOrientation(r, requestedOrientation);
3759 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003760 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003761 r.mayFreezeScreenLocked(r.app) ? r : null);
3762 if (config != null) {
3763 r.frozenBeforeDestroy = true;
3764 if (!updateConfigurationLocked(config, r)) {
3765 resumeTopActivityLocked(null);
3766 }
3767 }
3768 Binder.restoreCallingIdentity(origId);
3769 }
3770 }
3771
3772 public int getRequestedOrientation(IBinder token) {
3773 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003774 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 if (index < 0) {
3776 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3777 }
3778 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3779 return mWindowManager.getAppOrientation(r);
3780 }
3781 }
3782
3783 private final void stopActivityLocked(HistoryRecord r) {
3784 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3785 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3786 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3787 if (!r.finishing) {
3788 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3789 "no-history");
3790 }
3791 } else if (r.app != null && r.app.thread != null) {
3792 if (mFocusedActivity == r) {
3793 setFocusedActivityLocked(topRunningActivityLocked(null));
3794 }
3795 r.resumeKeyDispatchingLocked();
3796 try {
3797 r.stopped = false;
3798 r.state = ActivityState.STOPPING;
3799 if (DEBUG_VISBILITY) Log.v(
3800 TAG, "Stopping visible=" + r.visible + " for " + r);
3801 if (!r.visible) {
3802 mWindowManager.setAppVisibility(r, false);
3803 }
3804 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3805 } catch (Exception e) {
3806 // Maybe just ignore exceptions here... if the process
3807 // has crashed, our death notification will clean things
3808 // up.
3809 Log.w(TAG, "Exception thrown during pause", e);
3810 // Just in case, assume it to be stopped.
3811 r.stopped = true;
3812 r.state = ActivityState.STOPPED;
3813 if (r.configDestroy) {
3814 destroyActivityLocked(r, true);
3815 }
3816 }
3817 }
3818 }
3819
3820 /**
3821 * @return Returns true if the activity is being finished, false if for
3822 * some reason it is being left as-is.
3823 */
3824 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3825 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003826 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 TAG, "Finishing activity: token=" + token
3828 + ", result=" + resultCode + ", data=" + resultData);
3829
Dianne Hackborn75b03852009-06-12 15:43:26 -07003830 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003831 if (index < 0) {
3832 return false;
3833 }
3834 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3835
3836 // Is this the last activity left?
3837 boolean lastActivity = true;
3838 for (int i=mHistory.size()-1; i>=0; i--) {
3839 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3840 if (!p.finishing && p != r) {
3841 lastActivity = false;
3842 break;
3843 }
3844 }
3845
3846 // If this is the last activity, but it is the home activity, then
3847 // just don't finish it.
3848 if (lastActivity) {
3849 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3850 return false;
3851 }
3852 }
3853
3854 finishActivityLocked(r, index, resultCode, resultData, reason);
3855 return true;
3856 }
3857
3858 /**
3859 * @return Returns true if this activity has been removed from the history
3860 * list, or false if it is still in the list and will be removed later.
3861 */
3862 private final boolean finishActivityLocked(HistoryRecord r, int index,
3863 int resultCode, Intent resultData, String reason) {
3864 if (r.finishing) {
3865 Log.w(TAG, "Duplicate finish request for " + r);
3866 return false;
3867 }
3868
3869 r.finishing = true;
3870 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3871 System.identityHashCode(r),
3872 r.task.taskId, r.shortComponentName, reason);
3873 r.task.numActivities--;
3874 if (r.frontOfTask && index < (mHistory.size()-1)) {
3875 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3876 if (next.task == r.task) {
3877 next.frontOfTask = true;
3878 }
3879 }
3880
3881 r.pauseKeyDispatchingLocked();
3882 if (mFocusedActivity == r) {
3883 setFocusedActivityLocked(topRunningActivityLocked(null));
3884 }
3885
3886 // send the result
3887 HistoryRecord resultTo = r.resultTo;
3888 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003889 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3890 + " who=" + r.resultWho + " req=" + r.requestCode
3891 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003892 if (r.info.applicationInfo.uid > 0) {
3893 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3894 r.packageName, resultData, r);
3895 }
3896 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3897 resultData);
3898 r.resultTo = null;
3899 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003900 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003901
3902 // Make sure this HistoryRecord is not holding on to other resources,
3903 // because clients have remote IPC references to this object so we
3904 // can't assume that will go away and want to avoid circular IPC refs.
3905 r.results = null;
3906 r.pendingResults = null;
3907 r.newIntents = null;
3908 r.icicle = null;
3909
3910 if (mPendingThumbnails.size() > 0) {
3911 // There are clients waiting to receive thumbnails so, in case
3912 // this is an activity that someone is waiting for, add it
3913 // to the pending list so we can correctly update the clients.
3914 mCancelledThumbnails.add(r);
3915 }
3916
3917 if (mResumedActivity == r) {
3918 boolean endTask = index <= 0
3919 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3920 if (DEBUG_TRANSITION) Log.v(TAG,
3921 "Prepare close transition: finishing " + r);
3922 mWindowManager.prepareAppTransition(endTask
3923 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3924 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3925
3926 // Tell window manager to prepare for this one to be removed.
3927 mWindowManager.setAppVisibility(r, false);
3928
3929 if (mPausingActivity == null) {
3930 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3931 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3932 startPausingLocked(false, false);
3933 }
3934
3935 } else if (r.state != ActivityState.PAUSING) {
3936 // If the activity is PAUSING, we will complete the finish once
3937 // it is done pausing; else we can just directly finish it here.
3938 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3939 return finishCurrentActivityLocked(r, index,
3940 FINISH_AFTER_PAUSE) == null;
3941 } else {
3942 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3943 }
3944
3945 return false;
3946 }
3947
3948 private static final int FINISH_IMMEDIATELY = 0;
3949 private static final int FINISH_AFTER_PAUSE = 1;
3950 private static final int FINISH_AFTER_VISIBLE = 2;
3951
3952 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3953 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003954 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003955 if (index < 0) {
3956 return null;
3957 }
3958
3959 return finishCurrentActivityLocked(r, index, mode);
3960 }
3961
3962 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3963 int index, int mode) {
3964 // First things first: if this activity is currently visible,
3965 // and the resumed activity is not yet visible, then hold off on
3966 // finishing until the resumed one becomes visible.
3967 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3968 if (!mStoppingActivities.contains(r)) {
3969 mStoppingActivities.add(r);
3970 if (mStoppingActivities.size() > 3) {
3971 // If we already have a few activities waiting to stop,
3972 // then give up on things going idle and start clearing
3973 // them out.
3974 Message msg = Message.obtain();
3975 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3976 mHandler.sendMessage(msg);
3977 }
3978 }
3979 r.state = ActivityState.STOPPING;
3980 updateOomAdjLocked();
3981 return r;
3982 }
3983
3984 // make sure the record is cleaned out of other places.
3985 mStoppingActivities.remove(r);
3986 mWaitingVisibleActivities.remove(r);
3987 if (mResumedActivity == r) {
3988 mResumedActivity = null;
3989 }
3990 final ActivityState prevState = r.state;
3991 r.state = ActivityState.FINISHING;
3992
3993 if (mode == FINISH_IMMEDIATELY
3994 || prevState == ActivityState.STOPPED
3995 || prevState == ActivityState.INITIALIZING) {
3996 // If this activity is already stopped, we can just finish
3997 // it right now.
3998 return destroyActivityLocked(r, true) ? null : r;
3999 } else {
4000 // Need to go through the full pause cycle to get this
4001 // activity into the stopped state and then finish it.
4002 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4003 mFinishingActivities.add(r);
4004 resumeTopActivityLocked(null);
4005 }
4006 return r;
4007 }
4008
4009 /**
4010 * This is the internal entry point for handling Activity.finish().
4011 *
4012 * @param token The Binder token referencing the Activity we want to finish.
4013 * @param resultCode Result code, if any, from this Activity.
4014 * @param resultData Result data (Intent), if any, from this Activity.
4015 *
4016 * @result Returns true if the activity successfully finished, or false if it is still running.
4017 */
4018 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4019 // Refuse possible leaked file descriptors
4020 if (resultData != null && resultData.hasFileDescriptors() == true) {
4021 throw new IllegalArgumentException("File descriptors passed in Intent");
4022 }
4023
4024 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004025 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026 // Find the first activity that is not finishing.
4027 HistoryRecord next = topRunningActivityLocked(token, 0);
4028 if (next != null) {
4029 // ask watcher if this is allowed
4030 boolean resumeOK = true;
4031 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004032 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004034 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004035 }
4036
4037 if (!resumeOK) {
4038 return false;
4039 }
4040 }
4041 }
4042 final long origId = Binder.clearCallingIdentity();
4043 boolean res = requestFinishActivityLocked(token, resultCode,
4044 resultData, "app-request");
4045 Binder.restoreCallingIdentity(origId);
4046 return res;
4047 }
4048 }
4049
4050 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4051 String resultWho, int requestCode, int resultCode, Intent data) {
4052
4053 if (callingUid > 0) {
4054 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4055 data, r);
4056 }
4057
The Android Open Source Project10592532009-03-18 17:39:46 -07004058 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4059 + " : who=" + resultWho + " req=" + requestCode
4060 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004061 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4062 try {
4063 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4064 list.add(new ResultInfo(resultWho, requestCode,
4065 resultCode, data));
4066 r.app.thread.scheduleSendResult(r, list);
4067 return;
4068 } catch (Exception e) {
4069 Log.w(TAG, "Exception thrown sending result to " + r, e);
4070 }
4071 }
4072
4073 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4074 }
4075
4076 public final void finishSubActivity(IBinder token, String resultWho,
4077 int requestCode) {
4078 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004079 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004080 if (index < 0) {
4081 return;
4082 }
4083 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4084
4085 final long origId = Binder.clearCallingIdentity();
4086
4087 int i;
4088 for (i=mHistory.size()-1; i>=0; i--) {
4089 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4090 if (r.resultTo == self && r.requestCode == requestCode) {
4091 if ((r.resultWho == null && resultWho == null) ||
4092 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4093 finishActivityLocked(r, i,
4094 Activity.RESULT_CANCELED, null, "request-sub");
4095 }
4096 }
4097 }
4098
4099 Binder.restoreCallingIdentity(origId);
4100 }
4101 }
4102
4103 /**
4104 * Perform clean-up of service connections in an activity record.
4105 */
4106 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4107 // Throw away any services that have been bound by this activity.
4108 if (r.connections != null) {
4109 Iterator<ConnectionRecord> it = r.connections.iterator();
4110 while (it.hasNext()) {
4111 ConnectionRecord c = it.next();
4112 removeConnectionLocked(c, null, r);
4113 }
4114 r.connections = null;
4115 }
4116 }
4117
4118 /**
4119 * Perform the common clean-up of an activity record. This is called both
4120 * as part of destroyActivityLocked() (when destroying the client-side
4121 * representation) and cleaning things up as a result of its hosting
4122 * processing going away, in which case there is no remaining client-side
4123 * state to destroy so only the cleanup here is needed.
4124 */
4125 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4126 if (mResumedActivity == r) {
4127 mResumedActivity = null;
4128 }
4129 if (mFocusedActivity == r) {
4130 mFocusedActivity = null;
4131 }
4132
4133 r.configDestroy = false;
4134 r.frozenBeforeDestroy = false;
4135
4136 // Make sure this record is no longer in the pending finishes list.
4137 // This could happen, for example, if we are trimming activities
4138 // down to the max limit while they are still waiting to finish.
4139 mFinishingActivities.remove(r);
4140 mWaitingVisibleActivities.remove(r);
4141
4142 // Remove any pending results.
4143 if (r.finishing && r.pendingResults != null) {
4144 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4145 PendingIntentRecord rec = apr.get();
4146 if (rec != null) {
4147 cancelIntentSenderLocked(rec, false);
4148 }
4149 }
4150 r.pendingResults = null;
4151 }
4152
4153 if (cleanServices) {
4154 cleanUpActivityServicesLocked(r);
4155 }
4156
4157 if (mPendingThumbnails.size() > 0) {
4158 // There are clients waiting to receive thumbnails so, in case
4159 // this is an activity that someone is waiting for, add it
4160 // to the pending list so we can correctly update the clients.
4161 mCancelledThumbnails.add(r);
4162 }
4163
4164 // Get rid of any pending idle timeouts.
4165 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4166 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4167 }
4168
4169 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4170 if (r.state != ActivityState.DESTROYED) {
4171 mHistory.remove(r);
4172 r.inHistory = false;
4173 r.state = ActivityState.DESTROYED;
4174 mWindowManager.removeAppToken(r);
4175 if (VALIDATE_TOKENS) {
4176 mWindowManager.validateAppTokens(mHistory);
4177 }
4178 cleanUpActivityServicesLocked(r);
4179 removeActivityUriPermissionsLocked(r);
4180 }
4181 }
4182
4183 /**
4184 * Destroy the current CLIENT SIDE instance of an activity. This may be
4185 * called both when actually finishing an activity, or when performing
4186 * a configuration switch where we destroy the current client-side object
4187 * but then create a new client-side object for this same HistoryRecord.
4188 */
4189 private final boolean destroyActivityLocked(HistoryRecord r,
4190 boolean removeFromApp) {
4191 if (DEBUG_SWITCH) Log.v(
4192 TAG, "Removing activity: token=" + r
4193 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4194 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4195 System.identityHashCode(r),
4196 r.task.taskId, r.shortComponentName);
4197
4198 boolean removedFromHistory = false;
4199
4200 cleanUpActivityLocked(r, false);
4201
4202 if (r.app != null) {
4203 if (removeFromApp) {
4204 int idx = r.app.activities.indexOf(r);
4205 if (idx >= 0) {
4206 r.app.activities.remove(idx);
4207 }
4208 if (r.persistent) {
4209 decPersistentCountLocked(r.app);
4210 }
4211 }
4212
4213 boolean skipDestroy = false;
4214
4215 try {
4216 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4217 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4218 r.configChangeFlags);
4219 } catch (Exception e) {
4220 // We can just ignore exceptions here... if the process
4221 // has crashed, our death notification will clean things
4222 // up.
4223 //Log.w(TAG, "Exception thrown during finish", e);
4224 if (r.finishing) {
4225 removeActivityFromHistoryLocked(r);
4226 removedFromHistory = true;
4227 skipDestroy = true;
4228 }
4229 }
4230
4231 r.app = null;
4232 r.nowVisible = false;
4233
4234 if (r.finishing && !skipDestroy) {
4235 r.state = ActivityState.DESTROYING;
4236 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4237 msg.obj = r;
4238 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4239 } else {
4240 r.state = ActivityState.DESTROYED;
4241 }
4242 } else {
4243 // remove this record from the history.
4244 if (r.finishing) {
4245 removeActivityFromHistoryLocked(r);
4246 removedFromHistory = true;
4247 } else {
4248 r.state = ActivityState.DESTROYED;
4249 }
4250 }
4251
4252 r.configChangeFlags = 0;
4253
4254 if (!mLRUActivities.remove(r)) {
4255 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4256 }
4257
4258 return removedFromHistory;
4259 }
4260
4261 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4262 ProcessRecord app)
4263 {
4264 int i = list.size();
4265 if (localLOGV) Log.v(
4266 TAG, "Removing app " + app + " from list " + list
4267 + " with " + i + " entries");
4268 while (i > 0) {
4269 i--;
4270 HistoryRecord r = (HistoryRecord)list.get(i);
4271 if (localLOGV) Log.v(
4272 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4273 if (r.app == app) {
4274 if (localLOGV) Log.v(TAG, "Removing this entry!");
4275 list.remove(i);
4276 }
4277 }
4278 }
4279
4280 /**
4281 * Main function for removing an existing process from the activity manager
4282 * as a result of that process going away. Clears out all connections
4283 * to the process.
4284 */
4285 private final void handleAppDiedLocked(ProcessRecord app,
4286 boolean restarting) {
4287 cleanUpApplicationRecordLocked(app, restarting, -1);
4288 if (!restarting) {
4289 mLRUProcesses.remove(app);
4290 }
4291
4292 // Just in case...
4293 if (mPausingActivity != null && mPausingActivity.app == app) {
4294 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4295 mPausingActivity = null;
4296 }
4297 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4298 mLastPausedActivity = null;
4299 }
4300
4301 // Remove this application's activities from active lists.
4302 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4303 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4304 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4305 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4306
4307 boolean atTop = true;
4308 boolean hasVisibleActivities = false;
4309
4310 // Clean out the history list.
4311 int i = mHistory.size();
4312 if (localLOGV) Log.v(
4313 TAG, "Removing app " + app + " from history with " + i + " entries");
4314 while (i > 0) {
4315 i--;
4316 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4317 if (localLOGV) Log.v(
4318 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4319 if (r.app == app) {
4320 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4321 if (localLOGV) Log.v(
4322 TAG, "Removing this entry! frozen=" + r.haveState
4323 + " finishing=" + r.finishing);
4324 mHistory.remove(i);
4325
4326 r.inHistory = false;
4327 mWindowManager.removeAppToken(r);
4328 if (VALIDATE_TOKENS) {
4329 mWindowManager.validateAppTokens(mHistory);
4330 }
4331 removeActivityUriPermissionsLocked(r);
4332
4333 } else {
4334 // We have the current state for this activity, so
4335 // it can be restarted later when needed.
4336 if (localLOGV) Log.v(
4337 TAG, "Keeping entry, setting app to null");
4338 if (r.visible) {
4339 hasVisibleActivities = true;
4340 }
4341 r.app = null;
4342 r.nowVisible = false;
4343 if (!r.haveState) {
4344 r.icicle = null;
4345 }
4346 }
4347
4348 cleanUpActivityLocked(r, true);
4349 r.state = ActivityState.STOPPED;
4350 }
4351 atTop = false;
4352 }
4353
4354 app.activities.clear();
4355
4356 if (app.instrumentationClass != null) {
4357 Log.w(TAG, "Crash of app " + app.processName
4358 + " running instrumentation " + app.instrumentationClass);
4359 Bundle info = new Bundle();
4360 info.putString("shortMsg", "Process crashed.");
4361 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4362 }
4363
4364 if (!restarting) {
4365 if (!resumeTopActivityLocked(null)) {
4366 // If there was nothing to resume, and we are not already
4367 // restarting this process, but there is a visible activity that
4368 // is hosted by the process... then make sure all visible
4369 // activities are running, taking care of restarting this
4370 // process.
4371 if (hasVisibleActivities) {
4372 ensureActivitiesVisibleLocked(null, 0);
4373 }
4374 }
4375 }
4376 }
4377
4378 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4379 IBinder threadBinder = thread.asBinder();
4380
4381 // Find the application record.
4382 int count = mLRUProcesses.size();
4383 int i;
4384 for (i=0; i<count; i++) {
4385 ProcessRecord rec = mLRUProcesses.get(i);
4386 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4387 return i;
4388 }
4389 }
4390 return -1;
4391 }
4392
4393 private final ProcessRecord getRecordForAppLocked(
4394 IApplicationThread thread) {
4395 if (thread == null) {
4396 return null;
4397 }
4398
4399 int appIndex = getLRURecordIndexForAppLocked(thread);
4400 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4401 }
4402
4403 private final void appDiedLocked(ProcessRecord app, int pid,
4404 IApplicationThread thread) {
4405
4406 mProcDeaths[0]++;
4407
4408 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4409 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4410 + ") has died.");
4411 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4412 if (localLOGV) Log.v(
4413 TAG, "Dying app: " + app + ", pid: " + pid
4414 + ", thread: " + thread.asBinder());
4415 boolean doLowMem = app.instrumentationClass == null;
4416 handleAppDiedLocked(app, false);
4417
4418 if (doLowMem) {
4419 // If there are no longer any background processes running,
4420 // and the app that died was not running instrumentation,
4421 // then tell everyone we are now low on memory.
4422 boolean haveBg = false;
4423 int count = mLRUProcesses.size();
4424 int i;
4425 for (i=0; i<count; i++) {
4426 ProcessRecord rec = mLRUProcesses.get(i);
4427 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4428 haveBg = true;
4429 break;
4430 }
4431 }
4432
4433 if (!haveBg) {
4434 Log.i(TAG, "Low Memory: No more background processes.");
4435 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4436 for (i=0; i<count; i++) {
4437 ProcessRecord rec = mLRUProcesses.get(i);
4438 if (rec.thread != null) {
4439 rec.lastRequestedGc = SystemClock.uptimeMillis();
4440 try {
4441 rec.thread.scheduleLowMemory();
4442 } catch (RemoteException e) {
4443 // Don't care if the process is gone.
4444 }
4445 }
4446 }
4447 }
4448 }
4449 } else if (Config.LOGD) {
4450 Log.d(TAG, "Received spurious death notification for thread "
4451 + thread.asBinder());
4452 }
4453 }
4454
4455 final String readFile(String filename) {
4456 try {
4457 FileInputStream fs = new FileInputStream(filename);
4458 byte[] inp = new byte[8192];
4459 int size = fs.read(inp);
4460 fs.close();
4461 return new String(inp, 0, 0, size);
4462 } catch (java.io.IOException e) {
4463 }
4464 return "";
4465 }
4466
4467 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004468 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004469 if (app.notResponding || app.crashing) {
4470 return;
4471 }
4472
4473 // Log the ANR to the event log.
4474 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4475
4476 // If we are on a secure build and the application is not interesting to the user (it is
4477 // not visible or in the background), just kill it instead of displaying a dialog.
4478 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4479 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4480 Process.killProcess(app.pid);
4481 return;
4482 }
4483
4484 // DeviceMonitor.start();
4485
4486 String processInfo = null;
4487 if (MONITOR_CPU_USAGE) {
4488 updateCpuStatsNow();
4489 synchronized (mProcessStatsThread) {
4490 processInfo = mProcessStats.printCurrentState();
4491 }
4492 }
4493
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004494 StringBuilder info = mStringBuilder;
4495 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004496 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004497 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004498 if (reportedActivity != null && reportedActivity.app != null) {
4499 info.append(" (last in ");
4500 info.append(reportedActivity.app.processName);
4501 info.append(")");
4502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004503 if (annotation != null) {
4504 info.append("\nAnnotation: ");
4505 info.append(annotation);
4506 }
4507 if (MONITOR_CPU_USAGE) {
4508 info.append("\nCPU usage:\n");
4509 info.append(processInfo);
4510 }
4511 Log.i(TAG, info.toString());
4512
4513 // The application is not responding. Dump as many thread traces as we can.
4514 boolean fileDump = prepareTraceFile(true);
4515 if (!fileDump) {
4516 // Dumping traces to the log, just dump the process that isn't responding so
4517 // we don't overflow the log
4518 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4519 } else {
4520 // Dumping traces to a file so dump all active processes we know about
4521 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004522 // First, these are the most important processes.
4523 final int[] imppids = new int[3];
4524 int i=0;
4525 imppids[0] = app.pid;
4526 i++;
4527 if (reportedActivity != null && reportedActivity.app != null
4528 && reportedActivity.app.thread != null
4529 && reportedActivity.app.pid != app.pid) {
4530 imppids[i] = reportedActivity.app.pid;
4531 i++;
4532 }
4533 imppids[i] = Process.myPid();
4534 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4535 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4536 synchronized (this) {
4537 try {
4538 wait(200);
4539 } catch (InterruptedException e) {
4540 }
4541 }
4542 }
4543 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004544 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004545 boolean done = false;
4546 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4547 if (imppids[j] == r.pid) {
4548 done = true;
4549 break;
4550 }
4551 }
4552 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004554 synchronized (this) {
4555 try {
4556 wait(200);
4557 } catch (InterruptedException e) {
4558 }
4559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004560 }
4561 }
4562 }
4563 }
4564
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004565 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004566 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004567 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 app.pid, info.toString());
4569 if (res != 0) {
4570 if (res < 0) {
4571 // wait until the SIGQUIT has had a chance to process before killing the
4572 // process.
4573 try {
4574 wait(2000);
4575 } catch (InterruptedException e) {
4576 }
4577
4578 Process.killProcess(app.pid);
4579 return;
4580 }
4581 }
4582 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004583 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004584 }
4585 }
4586
4587 makeAppNotRespondingLocked(app,
4588 activity != null ? activity.shortComponentName : null,
4589 annotation != null ? "ANR " + annotation : "ANR",
4590 info.toString(), null);
4591 Message msg = Message.obtain();
4592 HashMap map = new HashMap();
4593 msg.what = SHOW_NOT_RESPONDING_MSG;
4594 msg.obj = map;
4595 map.put("app", app);
4596 if (activity != null) {
4597 map.put("activity", activity);
4598 }
4599
4600 mHandler.sendMessage(msg);
4601 return;
4602 }
4603
4604 /**
4605 * If a stack trace file has been configured, prepare the filesystem
4606 * by creating the directory if it doesn't exist and optionally
4607 * removing the old trace file.
4608 *
4609 * @param removeExisting If set, the existing trace file will be removed.
4610 * @return Returns true if the trace file preparations succeeded
4611 */
4612 public static boolean prepareTraceFile(boolean removeExisting) {
4613 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4614 boolean fileReady = false;
4615 if (!TextUtils.isEmpty(tracesPath)) {
4616 File f = new File(tracesPath);
4617 if (!f.exists()) {
4618 // Ensure the enclosing directory exists
4619 File dir = f.getParentFile();
4620 if (!dir.exists()) {
4621 fileReady = dir.mkdirs();
4622 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004623 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004624 } else if (dir.isDirectory()) {
4625 fileReady = true;
4626 }
4627 } else if (removeExisting) {
4628 // Remove the previous traces file, so we don't fill the disk.
4629 // The VM will recreate it
4630 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4631 fileReady = f.delete();
4632 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004633
4634 if (removeExisting) {
4635 try {
4636 f.createNewFile();
4637 FileUtils.setPermissions(f.getAbsolutePath(),
4638 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4639 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4640 fileReady = true;
4641 } catch (IOException e) {
4642 Log.w(TAG, "Unable to make ANR traces file", e);
4643 }
4644 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004645 }
4646
4647 return fileReady;
4648 }
4649
4650
4651 private final void decPersistentCountLocked(ProcessRecord app)
4652 {
4653 app.persistentActivities--;
4654 if (app.persistentActivities > 0) {
4655 // Still more of 'em...
4656 return;
4657 }
4658 if (app.persistent) {
4659 // Ah, but the application itself is persistent. Whatever!
4660 return;
4661 }
4662
4663 // App is no longer persistent... make sure it and the ones
4664 // following it in the LRU list have the correc oom_adj.
4665 updateOomAdjLocked();
4666 }
4667
4668 public void setPersistent(IBinder token, boolean isPersistent) {
4669 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4670 != PackageManager.PERMISSION_GRANTED) {
4671 String msg = "Permission Denial: setPersistent() from pid="
4672 + Binder.getCallingPid()
4673 + ", uid=" + Binder.getCallingUid()
4674 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4675 Log.w(TAG, msg);
4676 throw new SecurityException(msg);
4677 }
4678
4679 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004680 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004681 if (index < 0) {
4682 return;
4683 }
4684 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4685 ProcessRecord app = r.app;
4686
4687 if (localLOGV) Log.v(
4688 TAG, "Setting persistence " + isPersistent + ": " + r);
4689
4690 if (isPersistent) {
4691 if (r.persistent) {
4692 // Okay okay, I heard you already!
4693 if (localLOGV) Log.v(TAG, "Already persistent!");
4694 return;
4695 }
4696 r.persistent = true;
4697 app.persistentActivities++;
4698 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4699 if (app.persistentActivities > 1) {
4700 // We aren't the first...
4701 if (localLOGV) Log.v(TAG, "Not the first!");
4702 return;
4703 }
4704 if (app.persistent) {
4705 // This would be redundant.
4706 if (localLOGV) Log.v(TAG, "App is persistent!");
4707 return;
4708 }
4709
4710 // App is now persistent... make sure it and the ones
4711 // following it now have the correct oom_adj.
4712 final long origId = Binder.clearCallingIdentity();
4713 updateOomAdjLocked();
4714 Binder.restoreCallingIdentity(origId);
4715
4716 } else {
4717 if (!r.persistent) {
4718 // Okay okay, I heard you already!
4719 return;
4720 }
4721 r.persistent = false;
4722 final long origId = Binder.clearCallingIdentity();
4723 decPersistentCountLocked(app);
4724 Binder.restoreCallingIdentity(origId);
4725
4726 }
4727 }
4728 }
4729
4730 public boolean clearApplicationUserData(final String packageName,
4731 final IPackageDataObserver observer) {
4732 int uid = Binder.getCallingUid();
4733 int pid = Binder.getCallingPid();
4734 long callingId = Binder.clearCallingIdentity();
4735 try {
4736 IPackageManager pm = ActivityThread.getPackageManager();
4737 int pkgUid = -1;
4738 synchronized(this) {
4739 try {
4740 pkgUid = pm.getPackageUid(packageName);
4741 } catch (RemoteException e) {
4742 }
4743 if (pkgUid == -1) {
4744 Log.w(TAG, "Invalid packageName:" + packageName);
4745 return false;
4746 }
4747 if (uid == pkgUid || checkComponentPermission(
4748 android.Manifest.permission.CLEAR_APP_USER_DATA,
4749 pid, uid, -1)
4750 == PackageManager.PERMISSION_GRANTED) {
4751 restartPackageLocked(packageName, pkgUid);
4752 } else {
4753 throw new SecurityException(pid+" does not have permission:"+
4754 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4755 "for process:"+packageName);
4756 }
4757 }
4758
4759 try {
4760 //clear application user data
4761 pm.clearApplicationUserData(packageName, observer);
4762 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4763 Uri.fromParts("package", packageName, null));
4764 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4765 broadcastIntentLocked(null, null, intent,
4766 null, null, 0, null, null, null,
4767 false, false, MY_PID, Process.SYSTEM_UID);
4768 } catch (RemoteException e) {
4769 }
4770 } finally {
4771 Binder.restoreCallingIdentity(callingId);
4772 }
4773 return true;
4774 }
4775
4776 public void restartPackage(final String packageName) {
4777 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4778 != PackageManager.PERMISSION_GRANTED) {
4779 String msg = "Permission Denial: restartPackage() from pid="
4780 + Binder.getCallingPid()
4781 + ", uid=" + Binder.getCallingUid()
4782 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4783 Log.w(TAG, msg);
4784 throw new SecurityException(msg);
4785 }
4786
4787 long callingId = Binder.clearCallingIdentity();
4788 try {
4789 IPackageManager pm = ActivityThread.getPackageManager();
4790 int pkgUid = -1;
4791 synchronized(this) {
4792 try {
4793 pkgUid = pm.getPackageUid(packageName);
4794 } catch (RemoteException e) {
4795 }
4796 if (pkgUid == -1) {
4797 Log.w(TAG, "Invalid packageName: " + packageName);
4798 return;
4799 }
4800 restartPackageLocked(packageName, pkgUid);
4801 }
4802 } finally {
4803 Binder.restoreCallingIdentity(callingId);
4804 }
4805 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004806
4807 /*
4808 * The pkg name and uid have to be specified.
4809 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4810 */
4811 public void killApplicationWithUid(String pkg, int uid) {
4812 if (pkg == null) {
4813 return;
4814 }
4815 // Make sure the uid is valid.
4816 if (uid < 0) {
4817 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4818 return;
4819 }
4820 int callerUid = Binder.getCallingUid();
4821 // Only the system server can kill an application
4822 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004823 // Post an aysnc message to kill the application
4824 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4825 msg.arg1 = uid;
4826 msg.arg2 = 0;
4827 msg.obj = pkg;
4828 mHandler.dispatchMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004829 } else {
4830 throw new SecurityException(callerUid + " cannot kill pkg: " +
4831 pkg);
4832 }
4833 }
4834
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004835 public void closeSystemDialogs(String reason) {
4836 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4837 if (reason != null) {
4838 intent.putExtra("reason", reason);
4839 }
4840
4841 final int uid = Binder.getCallingUid();
4842 final long origId = Binder.clearCallingIdentity();
4843 synchronized (this) {
4844 int i = mWatchers.beginBroadcast();
4845 while (i > 0) {
4846 i--;
4847 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4848 if (w != null) {
4849 try {
4850 w.closingSystemDialogs(reason);
4851 } catch (RemoteException e) {
4852 }
4853 }
4854 }
4855 mWatchers.finishBroadcast();
4856
4857 broadcastIntentLocked(null, null, intent, null,
4858 null, 0, null, null, null, false, false, -1, uid);
4859 }
4860 Binder.restoreCallingIdentity(origId);
4861 }
4862
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004863 private void restartPackageLocked(final String packageName, int uid) {
4864 uninstallPackageLocked(packageName, uid, false);
4865 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4866 Uri.fromParts("package", packageName, null));
4867 intent.putExtra(Intent.EXTRA_UID, uid);
4868 broadcastIntentLocked(null, null, intent,
4869 null, null, 0, null, null, null,
4870 false, false, MY_PID, Process.SYSTEM_UID);
4871 }
4872
4873 private final void uninstallPackageLocked(String name, int uid,
4874 boolean callerWillRestart) {
4875 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4876
4877 int i, N;
4878
4879 final String procNamePrefix = name + ":";
4880 if (uid < 0) {
4881 try {
4882 uid = ActivityThread.getPackageManager().getPackageUid(name);
4883 } catch (RemoteException e) {
4884 }
4885 }
4886
4887 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4888 while (badApps.hasNext()) {
4889 SparseArray<Long> ba = badApps.next();
4890 if (ba.get(uid) != null) {
4891 badApps.remove();
4892 }
4893 }
4894
4895 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4896
4897 // Remove all processes this package may have touched: all with the
4898 // same UID (except for the system or root user), and all whose name
4899 // matches the package name.
4900 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4901 final int NA = apps.size();
4902 for (int ia=0; ia<NA; ia++) {
4903 ProcessRecord app = apps.valueAt(ia);
4904 if (app.removed) {
4905 procs.add(app);
4906 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4907 || app.processName.equals(name)
4908 || app.processName.startsWith(procNamePrefix)) {
4909 app.removed = true;
4910 procs.add(app);
4911 }
4912 }
4913 }
4914
4915 N = procs.size();
4916 for (i=0; i<N; i++) {
4917 removeProcessLocked(procs.get(i), callerWillRestart);
4918 }
4919
4920 for (i=mHistory.size()-1; i>=0; i--) {
4921 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4922 if (r.packageName.equals(name)) {
4923 if (Config.LOGD) Log.d(
4924 TAG, " Force finishing activity "
4925 + r.intent.getComponent().flattenToShortString());
4926 if (r.app != null) {
4927 r.app.removed = true;
4928 }
4929 r.app = null;
4930 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4931 }
4932 }
4933
4934 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4935 for (ServiceRecord service : mServices.values()) {
4936 if (service.packageName.equals(name)) {
4937 if (service.app != null) {
4938 service.app.removed = true;
4939 }
4940 service.app = null;
4941 services.add(service);
4942 }
4943 }
4944
4945 N = services.size();
4946 for (i=0; i<N; i++) {
4947 bringDownServiceLocked(services.get(i), true);
4948 }
4949
4950 resumeTopActivityLocked(null);
4951 }
4952
4953 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4954 final String name = app.processName;
4955 final int uid = app.info.uid;
4956 if (Config.LOGD) Log.d(
4957 TAG, "Force removing process " + app + " (" + name
4958 + "/" + uid + ")");
4959
4960 mProcessNames.remove(name, uid);
4961 boolean needRestart = false;
4962 if (app.pid > 0 && app.pid != MY_PID) {
4963 int pid = app.pid;
4964 synchronized (mPidsSelfLocked) {
4965 mPidsSelfLocked.remove(pid);
4966 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4967 }
4968 handleAppDiedLocked(app, true);
4969 mLRUProcesses.remove(app);
4970 Process.killProcess(pid);
4971
4972 if (app.persistent) {
4973 if (!callerWillRestart) {
4974 addAppLocked(app.info);
4975 } else {
4976 needRestart = true;
4977 }
4978 }
4979 } else {
4980 mRemovedProcesses.add(app);
4981 }
4982
4983 return needRestart;
4984 }
4985
4986 private final void processStartTimedOutLocked(ProcessRecord app) {
4987 final int pid = app.pid;
4988 boolean gone = false;
4989 synchronized (mPidsSelfLocked) {
4990 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4991 if (knownApp != null && knownApp.thread == null) {
4992 mPidsSelfLocked.remove(pid);
4993 gone = true;
4994 }
4995 }
4996
4997 if (gone) {
4998 Log.w(TAG, "Process " + app + " failed to attach");
4999 mProcessNames.remove(app.processName, app.info.uid);
5000 Process.killProcess(pid);
5001 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5002 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5003 mPendingBroadcast = null;
5004 scheduleBroadcastsLocked();
5005 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005006 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5007 Log.w(TAG, "Unattached app died before backup, skipping");
5008 try {
5009 IBackupManager bm = IBackupManager.Stub.asInterface(
5010 ServiceManager.getService(Context.BACKUP_SERVICE));
5011 bm.agentDisconnected(app.info.packageName);
5012 } catch (RemoteException e) {
5013 // Can't happen; the backup manager is local
5014 }
5015 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005016 } else {
5017 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5018 }
5019 }
5020
5021 private final boolean attachApplicationLocked(IApplicationThread thread,
5022 int pid) {
5023
5024 // Find the application record that is being attached... either via
5025 // the pid if we are running in multiple processes, or just pull the
5026 // next app record if we are emulating process with anonymous threads.
5027 ProcessRecord app;
5028 if (pid != MY_PID && pid >= 0) {
5029 synchronized (mPidsSelfLocked) {
5030 app = mPidsSelfLocked.get(pid);
5031 }
5032 } else if (mStartingProcesses.size() > 0) {
5033 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005034 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005035 } else {
5036 app = null;
5037 }
5038
5039 if (app == null) {
5040 Log.w(TAG, "No pending application record for pid " + pid
5041 + " (IApplicationThread " + thread + "); dropping process");
5042 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5043 if (pid > 0 && pid != MY_PID) {
5044 Process.killProcess(pid);
5045 } else {
5046 try {
5047 thread.scheduleExit();
5048 } catch (Exception e) {
5049 // Ignore exceptions.
5050 }
5051 }
5052 return false;
5053 }
5054
5055 // If this application record is still attached to a previous
5056 // process, clean it up now.
5057 if (app.thread != null) {
5058 handleAppDiedLocked(app, true);
5059 }
5060
5061 // Tell the process all about itself.
5062
5063 if (localLOGV) Log.v(
5064 TAG, "Binding process pid " + pid + " to record " + app);
5065
5066 String processName = app.processName;
5067 try {
5068 thread.asBinder().linkToDeath(new AppDeathRecipient(
5069 app, pid, thread), 0);
5070 } catch (RemoteException e) {
5071 app.resetPackageList();
5072 startProcessLocked(app, "link fail", processName);
5073 return false;
5074 }
5075
5076 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5077
5078 app.thread = thread;
5079 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005080 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005081 app.forcingToForeground = null;
5082 app.foregroundServices = false;
5083 app.debugging = false;
5084
5085 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5086
5087 List providers = generateApplicationProvidersLocked(app);
5088
5089 if (localLOGV) Log.v(
5090 TAG, "New app record " + app
5091 + " thread=" + thread.asBinder() + " pid=" + pid);
5092 try {
5093 int testMode = IApplicationThread.DEBUG_OFF;
5094 if (mDebugApp != null && mDebugApp.equals(processName)) {
5095 testMode = mWaitForDebugger
5096 ? IApplicationThread.DEBUG_WAIT
5097 : IApplicationThread.DEBUG_ON;
5098 app.debugging = true;
5099 if (mDebugTransient) {
5100 mDebugApp = mOrigDebugApp;
5101 mWaitForDebugger = mOrigWaitForDebugger;
5102 }
5103 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005104 // If the app is being launched for restore or full backup, set it up specially
5105 boolean isRestrictedBackupMode = false;
5106 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5107 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5108 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5109 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005110 ensurePackageDexOpt(app.instrumentationInfo != null
5111 ? app.instrumentationInfo.packageName
5112 : app.info.packageName);
5113 if (app.instrumentationClass != null) {
5114 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005115 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005116 thread.bindApplication(processName, app.instrumentationInfo != null
5117 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005118 app.instrumentationClass, app.instrumentationProfileFile,
5119 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07005120 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005121 updateLRUListLocked(app, false);
5122 app.lastRequestedGc = SystemClock.uptimeMillis();
5123 } catch (Exception e) {
5124 // todo: Yikes! What should we do? For now we will try to
5125 // start another process, but that could easily get us in
5126 // an infinite loop of restarting processes...
5127 Log.w(TAG, "Exception thrown during bind!", e);
5128
5129 app.resetPackageList();
5130 startProcessLocked(app, "bind fail", processName);
5131 return false;
5132 }
5133
5134 // Remove this record from the list of starting applications.
5135 mPersistentStartingProcesses.remove(app);
5136 mProcessesOnHold.remove(app);
5137
5138 boolean badApp = false;
5139 boolean didSomething = false;
5140
5141 // See if the top visible activity is waiting to run in this process...
5142 HistoryRecord hr = topRunningActivityLocked(null);
5143 if (hr != null) {
5144 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5145 && processName.equals(hr.processName)) {
5146 try {
5147 if (realStartActivityLocked(hr, app, true, true)) {
5148 didSomething = true;
5149 }
5150 } catch (Exception e) {
5151 Log.w(TAG, "Exception in new application when starting activity "
5152 + hr.intent.getComponent().flattenToShortString(), e);
5153 badApp = true;
5154 }
5155 } else {
5156 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5157 }
5158 }
5159
5160 // Find any services that should be running in this process...
5161 if (!badApp && mPendingServices.size() > 0) {
5162 ServiceRecord sr = null;
5163 try {
5164 for (int i=0; i<mPendingServices.size(); i++) {
5165 sr = mPendingServices.get(i);
5166 if (app.info.uid != sr.appInfo.uid
5167 || !processName.equals(sr.processName)) {
5168 continue;
5169 }
5170
5171 mPendingServices.remove(i);
5172 i--;
5173 realStartServiceLocked(sr, app);
5174 didSomething = true;
5175 }
5176 } catch (Exception e) {
5177 Log.w(TAG, "Exception in new application when starting service "
5178 + sr.shortName, e);
5179 badApp = true;
5180 }
5181 }
5182
5183 // Check if the next broadcast receiver is in this process...
5184 BroadcastRecord br = mPendingBroadcast;
5185 if (!badApp && br != null && br.curApp == app) {
5186 try {
5187 mPendingBroadcast = null;
5188 processCurBroadcastLocked(br, app);
5189 didSomething = true;
5190 } catch (Exception e) {
5191 Log.w(TAG, "Exception in new application when starting receiver "
5192 + br.curComponent.flattenToShortString(), e);
5193 badApp = true;
5194 logBroadcastReceiverDiscard(br);
5195 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5196 br.resultExtras, br.resultAbort, true);
5197 scheduleBroadcastsLocked();
5198 }
5199 }
5200
Christopher Tate181fafa2009-05-14 11:12:14 -07005201 // Check whether the next backup agent is in this process...
5202 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5203 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005204 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005205 try {
5206 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5207 } catch (Exception e) {
5208 Log.w(TAG, "Exception scheduling backup agent creation: ");
5209 e.printStackTrace();
5210 }
5211 }
5212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005213 if (badApp) {
5214 // todo: Also need to kill application to deal with all
5215 // kinds of exceptions.
5216 handleAppDiedLocked(app, false);
5217 return false;
5218 }
5219
5220 if (!didSomething) {
5221 updateOomAdjLocked();
5222 }
5223
5224 return true;
5225 }
5226
5227 public final void attachApplication(IApplicationThread thread) {
5228 synchronized (this) {
5229 int callingPid = Binder.getCallingPid();
5230 final long origId = Binder.clearCallingIdentity();
5231 attachApplicationLocked(thread, callingPid);
5232 Binder.restoreCallingIdentity(origId);
5233 }
5234 }
5235
5236 public final void activityIdle(IBinder token) {
5237 final long origId = Binder.clearCallingIdentity();
5238 activityIdleInternal(token, false);
5239 Binder.restoreCallingIdentity(origId);
5240 }
5241
5242 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5243 boolean remove) {
5244 int N = mStoppingActivities.size();
5245 if (N <= 0) return null;
5246
5247 ArrayList<HistoryRecord> stops = null;
5248
5249 final boolean nowVisible = mResumedActivity != null
5250 && mResumedActivity.nowVisible
5251 && !mResumedActivity.waitingVisible;
5252 for (int i=0; i<N; i++) {
5253 HistoryRecord s = mStoppingActivities.get(i);
5254 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5255 + nowVisible + " waitingVisible=" + s.waitingVisible
5256 + " finishing=" + s.finishing);
5257 if (s.waitingVisible && nowVisible) {
5258 mWaitingVisibleActivities.remove(s);
5259 s.waitingVisible = false;
5260 if (s.finishing) {
5261 // If this activity is finishing, it is sitting on top of
5262 // everyone else but we now know it is no longer needed...
5263 // so get rid of it. Otherwise, we need to go through the
5264 // normal flow and hide it once we determine that it is
5265 // hidden by the activities in front of it.
5266 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5267 mWindowManager.setAppVisibility(s, false);
5268 }
5269 }
5270 if (!s.waitingVisible && remove) {
5271 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5272 if (stops == null) {
5273 stops = new ArrayList<HistoryRecord>();
5274 }
5275 stops.add(s);
5276 mStoppingActivities.remove(i);
5277 N--;
5278 i--;
5279 }
5280 }
5281
5282 return stops;
5283 }
5284
5285 void enableScreenAfterBoot() {
5286 mWindowManager.enableScreenAfterBoot();
5287 }
5288
5289 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5290 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5291
5292 ArrayList<HistoryRecord> stops = null;
5293 ArrayList<HistoryRecord> finishes = null;
5294 ArrayList<HistoryRecord> thumbnails = null;
5295 int NS = 0;
5296 int NF = 0;
5297 int NT = 0;
5298 IApplicationThread sendThumbnail = null;
5299 boolean booting = false;
5300 boolean enableScreen = false;
5301
5302 synchronized (this) {
5303 if (token != null) {
5304 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5305 }
5306
5307 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005308 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309 if (index >= 0) {
5310 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5311
5312 // No longer need to keep the device awake.
5313 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5314 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5315 mLaunchingActivity.release();
5316 }
5317
5318 // We are now idle. If someone is waiting for a thumbnail from
5319 // us, we can now deliver.
5320 r.idle = true;
5321 scheduleAppGcsLocked();
5322 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5323 sendThumbnail = r.app.thread;
5324 r.thumbnailNeeded = false;
5325 }
5326
5327 // If this activity is fullscreen, set up to hide those under it.
5328
5329 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5330 ensureActivitiesVisibleLocked(null, 0);
5331
5332 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5333 if (!mBooted && !fromTimeout) {
5334 mBooted = true;
5335 enableScreen = true;
5336 }
5337 }
5338
5339 // Atomically retrieve all of the other things to do.
5340 stops = processStoppingActivitiesLocked(true);
5341 NS = stops != null ? stops.size() : 0;
5342 if ((NF=mFinishingActivities.size()) > 0) {
5343 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5344 mFinishingActivities.clear();
5345 }
5346 if ((NT=mCancelledThumbnails.size()) > 0) {
5347 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5348 mCancelledThumbnails.clear();
5349 }
5350
5351 booting = mBooting;
5352 mBooting = false;
5353 }
5354
5355 int i;
5356
5357 // Send thumbnail if requested.
5358 if (sendThumbnail != null) {
5359 try {
5360 sendThumbnail.requestThumbnail(token);
5361 } catch (Exception e) {
5362 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5363 sendPendingThumbnail(null, token, null, null, true);
5364 }
5365 }
5366
5367 // Stop any activities that are scheduled to do so but have been
5368 // waiting for the next one to start.
5369 for (i=0; i<NS; i++) {
5370 HistoryRecord r = (HistoryRecord)stops.get(i);
5371 synchronized (this) {
5372 if (r.finishing) {
5373 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5374 } else {
5375 stopActivityLocked(r);
5376 }
5377 }
5378 }
5379
5380 // Finish any activities that are scheduled to do so but have been
5381 // waiting for the next one to start.
5382 for (i=0; i<NF; i++) {
5383 HistoryRecord r = (HistoryRecord)finishes.get(i);
5384 synchronized (this) {
5385 destroyActivityLocked(r, true);
5386 }
5387 }
5388
5389 // Report back to any thumbnail receivers.
5390 for (i=0; i<NT; i++) {
5391 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5392 sendPendingThumbnail(r, null, null, null, true);
5393 }
5394
5395 if (booting) {
5396 // Ensure that any processes we had put on hold are now started
5397 // up.
5398 final int NP = mProcessesOnHold.size();
5399 if (NP > 0) {
5400 ArrayList<ProcessRecord> procs =
5401 new ArrayList<ProcessRecord>(mProcessesOnHold);
5402 for (int ip=0; ip<NP; ip++) {
5403 this.startProcessLocked(procs.get(ip), "on-hold", null);
5404 }
5405 }
5406 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5407 // Tell anyone interested that we are done booting!
5408 synchronized (this) {
5409 broadcastIntentLocked(null, null,
5410 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5411 null, null, 0, null, null,
5412 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5413 false, false, MY_PID, Process.SYSTEM_UID);
5414 }
5415 }
5416 }
5417
5418 trimApplications();
5419 //dump();
5420 //mWindowManager.dump();
5421
5422 if (enableScreen) {
5423 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5424 SystemClock.uptimeMillis());
5425 enableScreenAfterBoot();
5426 }
5427 }
5428
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005429 final void ensureScreenEnabled() {
5430 boolean enableScreen;
5431 synchronized (this) {
5432 enableScreen = !mBooted;
5433 mBooted = true;
5434 }
5435
5436 if (enableScreen) {
5437 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5438 SystemClock.uptimeMillis());
5439 enableScreenAfterBoot();
5440 }
5441 }
5442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005443 public final void activityPaused(IBinder token, Bundle icicle) {
5444 // Refuse possible leaked file descriptors
5445 if (icicle != null && icicle.hasFileDescriptors()) {
5446 throw new IllegalArgumentException("File descriptors passed in Bundle");
5447 }
5448
5449 final long origId = Binder.clearCallingIdentity();
5450 activityPaused(token, icicle, false);
5451 Binder.restoreCallingIdentity(origId);
5452 }
5453
5454 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5455 if (DEBUG_PAUSE) Log.v(
5456 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5457 + ", timeout=" + timeout);
5458
5459 HistoryRecord r = null;
5460
5461 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005462 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005463 if (index >= 0) {
5464 r = (HistoryRecord)mHistory.get(index);
5465 if (!timeout) {
5466 r.icicle = icicle;
5467 r.haveState = true;
5468 }
5469 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5470 if (mPausingActivity == r) {
5471 r.state = ActivityState.PAUSED;
5472 completePauseLocked();
5473 } else {
5474 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5475 System.identityHashCode(r), r.shortComponentName,
5476 mPausingActivity != null
5477 ? mPausingActivity.shortComponentName : "(none)");
5478 }
5479 }
5480 }
5481 }
5482
5483 public final void activityStopped(IBinder token, Bitmap thumbnail,
5484 CharSequence description) {
5485 if (localLOGV) Log.v(
5486 TAG, "Activity stopped: token=" + token);
5487
5488 HistoryRecord r = null;
5489
5490 final long origId = Binder.clearCallingIdentity();
5491
5492 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005493 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005494 if (index >= 0) {
5495 r = (HistoryRecord)mHistory.get(index);
5496 r.thumbnail = thumbnail;
5497 r.description = description;
5498 r.stopped = true;
5499 r.state = ActivityState.STOPPED;
5500 if (!r.finishing) {
5501 if (r.configDestroy) {
5502 destroyActivityLocked(r, true);
5503 resumeTopActivityLocked(null);
5504 }
5505 }
5506 }
5507 }
5508
5509 if (r != null) {
5510 sendPendingThumbnail(r, null, null, null, false);
5511 }
5512
5513 trimApplications();
5514
5515 Binder.restoreCallingIdentity(origId);
5516 }
5517
5518 public final void activityDestroyed(IBinder token) {
5519 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5520 synchronized (this) {
5521 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5522
Dianne Hackborn75b03852009-06-12 15:43:26 -07005523 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005524 if (index >= 0) {
5525 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5526 if (r.state == ActivityState.DESTROYING) {
5527 final long origId = Binder.clearCallingIdentity();
5528 removeActivityFromHistoryLocked(r);
5529 Binder.restoreCallingIdentity(origId);
5530 }
5531 }
5532 }
5533 }
5534
5535 public String getCallingPackage(IBinder token) {
5536 synchronized (this) {
5537 HistoryRecord r = getCallingRecordLocked(token);
5538 return r != null && r.app != null ? r.app.processName : null;
5539 }
5540 }
5541
5542 public ComponentName getCallingActivity(IBinder token) {
5543 synchronized (this) {
5544 HistoryRecord r = getCallingRecordLocked(token);
5545 return r != null ? r.intent.getComponent() : null;
5546 }
5547 }
5548
5549 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005550 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005551 if (index >= 0) {
5552 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5553 if (r != null) {
5554 return r.resultTo;
5555 }
5556 }
5557 return null;
5558 }
5559
5560 public ComponentName getActivityClassForToken(IBinder token) {
5561 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005562 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005563 if (index >= 0) {
5564 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5565 return r.intent.getComponent();
5566 }
5567 return null;
5568 }
5569 }
5570
5571 public String getPackageForToken(IBinder token) {
5572 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005573 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005574 if (index >= 0) {
5575 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5576 return r.packageName;
5577 }
5578 return null;
5579 }
5580 }
5581
5582 public IIntentSender getIntentSender(int type,
5583 String packageName, IBinder token, String resultWho,
5584 int requestCode, Intent intent, String resolvedType, int flags) {
5585 // Refuse possible leaked file descriptors
5586 if (intent != null && intent.hasFileDescriptors() == true) {
5587 throw new IllegalArgumentException("File descriptors passed in Intent");
5588 }
5589
5590 synchronized(this) {
5591 int callingUid = Binder.getCallingUid();
5592 try {
5593 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5594 Process.supportsProcesses()) {
5595 int uid = ActivityThread.getPackageManager()
5596 .getPackageUid(packageName);
5597 if (uid != Binder.getCallingUid()) {
5598 String msg = "Permission Denial: getIntentSender() from pid="
5599 + Binder.getCallingPid()
5600 + ", uid=" + Binder.getCallingUid()
5601 + ", (need uid=" + uid + ")"
5602 + " is not allowed to send as package " + packageName;
5603 Log.w(TAG, msg);
5604 throw new SecurityException(msg);
5605 }
5606 }
5607 } catch (RemoteException e) {
5608 throw new SecurityException(e);
5609 }
5610 HistoryRecord activity = null;
5611 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005612 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005613 if (index < 0) {
5614 return null;
5615 }
5616 activity = (HistoryRecord)mHistory.get(index);
5617 if (activity.finishing) {
5618 return null;
5619 }
5620 }
5621
5622 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5623 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5624 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5625 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5626 |PendingIntent.FLAG_UPDATE_CURRENT);
5627
5628 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5629 type, packageName, activity, resultWho,
5630 requestCode, intent, resolvedType, flags);
5631 WeakReference<PendingIntentRecord> ref;
5632 ref = mIntentSenderRecords.get(key);
5633 PendingIntentRecord rec = ref != null ? ref.get() : null;
5634 if (rec != null) {
5635 if (!cancelCurrent) {
5636 if (updateCurrent) {
5637 rec.key.requestIntent.replaceExtras(intent);
5638 }
5639 return rec;
5640 }
5641 rec.canceled = true;
5642 mIntentSenderRecords.remove(key);
5643 }
5644 if (noCreate) {
5645 return rec;
5646 }
5647 rec = new PendingIntentRecord(this, key, callingUid);
5648 mIntentSenderRecords.put(key, rec.ref);
5649 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5650 if (activity.pendingResults == null) {
5651 activity.pendingResults
5652 = new HashSet<WeakReference<PendingIntentRecord>>();
5653 }
5654 activity.pendingResults.add(rec.ref);
5655 }
5656 return rec;
5657 }
5658 }
5659
5660 public void cancelIntentSender(IIntentSender sender) {
5661 if (!(sender instanceof PendingIntentRecord)) {
5662 return;
5663 }
5664 synchronized(this) {
5665 PendingIntentRecord rec = (PendingIntentRecord)sender;
5666 try {
5667 int uid = ActivityThread.getPackageManager()
5668 .getPackageUid(rec.key.packageName);
5669 if (uid != Binder.getCallingUid()) {
5670 String msg = "Permission Denial: cancelIntentSender() from pid="
5671 + Binder.getCallingPid()
5672 + ", uid=" + Binder.getCallingUid()
5673 + " is not allowed to cancel packges "
5674 + rec.key.packageName;
5675 Log.w(TAG, msg);
5676 throw new SecurityException(msg);
5677 }
5678 } catch (RemoteException e) {
5679 throw new SecurityException(e);
5680 }
5681 cancelIntentSenderLocked(rec, true);
5682 }
5683 }
5684
5685 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5686 rec.canceled = true;
5687 mIntentSenderRecords.remove(rec.key);
5688 if (cleanActivity && rec.key.activity != null) {
5689 rec.key.activity.pendingResults.remove(rec.ref);
5690 }
5691 }
5692
5693 public String getPackageForIntentSender(IIntentSender pendingResult) {
5694 if (!(pendingResult instanceof PendingIntentRecord)) {
5695 return null;
5696 }
5697 synchronized(this) {
5698 try {
5699 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5700 return res.key.packageName;
5701 } catch (ClassCastException e) {
5702 }
5703 }
5704 return null;
5705 }
5706
5707 public void setProcessLimit(int max) {
5708 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5709 "setProcessLimit()");
5710 mProcessLimit = max;
5711 }
5712
5713 public int getProcessLimit() {
5714 return mProcessLimit;
5715 }
5716
5717 void foregroundTokenDied(ForegroundToken token) {
5718 synchronized (ActivityManagerService.this) {
5719 synchronized (mPidsSelfLocked) {
5720 ForegroundToken cur
5721 = mForegroundProcesses.get(token.pid);
5722 if (cur != token) {
5723 return;
5724 }
5725 mForegroundProcesses.remove(token.pid);
5726 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5727 if (pr == null) {
5728 return;
5729 }
5730 pr.forcingToForeground = null;
5731 pr.foregroundServices = false;
5732 }
5733 updateOomAdjLocked();
5734 }
5735 }
5736
5737 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5738 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5739 "setProcessForeground()");
5740 synchronized(this) {
5741 boolean changed = false;
5742
5743 synchronized (mPidsSelfLocked) {
5744 ProcessRecord pr = mPidsSelfLocked.get(pid);
5745 if (pr == null) {
5746 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5747 return;
5748 }
5749 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5750 if (oldToken != null) {
5751 oldToken.token.unlinkToDeath(oldToken, 0);
5752 mForegroundProcesses.remove(pid);
5753 pr.forcingToForeground = null;
5754 changed = true;
5755 }
5756 if (isForeground && token != null) {
5757 ForegroundToken newToken = new ForegroundToken() {
5758 public void binderDied() {
5759 foregroundTokenDied(this);
5760 }
5761 };
5762 newToken.pid = pid;
5763 newToken.token = token;
5764 try {
5765 token.linkToDeath(newToken, 0);
5766 mForegroundProcesses.put(pid, newToken);
5767 pr.forcingToForeground = token;
5768 changed = true;
5769 } catch (RemoteException e) {
5770 // If the process died while doing this, we will later
5771 // do the cleanup with the process death link.
5772 }
5773 }
5774 }
5775
5776 if (changed) {
5777 updateOomAdjLocked();
5778 }
5779 }
5780 }
5781
5782 // =========================================================
5783 // PERMISSIONS
5784 // =========================================================
5785
5786 static class PermissionController extends IPermissionController.Stub {
5787 ActivityManagerService mActivityManagerService;
5788 PermissionController(ActivityManagerService activityManagerService) {
5789 mActivityManagerService = activityManagerService;
5790 }
5791
5792 public boolean checkPermission(String permission, int pid, int uid) {
5793 return mActivityManagerService.checkPermission(permission, pid,
5794 uid) == PackageManager.PERMISSION_GRANTED;
5795 }
5796 }
5797
5798 /**
5799 * This can be called with or without the global lock held.
5800 */
5801 int checkComponentPermission(String permission, int pid, int uid,
5802 int reqUid) {
5803 // We might be performing an operation on behalf of an indirect binder
5804 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5805 // client identity accordingly before proceeding.
5806 Identity tlsIdentity = sCallerIdentity.get();
5807 if (tlsIdentity != null) {
5808 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5809 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5810 uid = tlsIdentity.uid;
5811 pid = tlsIdentity.pid;
5812 }
5813
5814 // Root, system server and our own process get to do everything.
5815 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5816 !Process.supportsProcesses()) {
5817 return PackageManager.PERMISSION_GRANTED;
5818 }
5819 // If the target requires a specific UID, always fail for others.
5820 if (reqUid >= 0 && uid != reqUid) {
5821 return PackageManager.PERMISSION_DENIED;
5822 }
5823 if (permission == null) {
5824 return PackageManager.PERMISSION_GRANTED;
5825 }
5826 try {
5827 return ActivityThread.getPackageManager()
5828 .checkUidPermission(permission, uid);
5829 } catch (RemoteException e) {
5830 // Should never happen, but if it does... deny!
5831 Log.e(TAG, "PackageManager is dead?!?", e);
5832 }
5833 return PackageManager.PERMISSION_DENIED;
5834 }
5835
5836 /**
5837 * As the only public entry point for permissions checking, this method
5838 * can enforce the semantic that requesting a check on a null global
5839 * permission is automatically denied. (Internally a null permission
5840 * string is used when calling {@link #checkComponentPermission} in cases
5841 * when only uid-based security is needed.)
5842 *
5843 * This can be called with or without the global lock held.
5844 */
5845 public int checkPermission(String permission, int pid, int uid) {
5846 if (permission == null) {
5847 return PackageManager.PERMISSION_DENIED;
5848 }
5849 return checkComponentPermission(permission, pid, uid, -1);
5850 }
5851
5852 /**
5853 * Binder IPC calls go through the public entry point.
5854 * This can be called with or without the global lock held.
5855 */
5856 int checkCallingPermission(String permission) {
5857 return checkPermission(permission,
5858 Binder.getCallingPid(),
5859 Binder.getCallingUid());
5860 }
5861
5862 /**
5863 * This can be called with or without the global lock held.
5864 */
5865 void enforceCallingPermission(String permission, String func) {
5866 if (checkCallingPermission(permission)
5867 == PackageManager.PERMISSION_GRANTED) {
5868 return;
5869 }
5870
5871 String msg = "Permission Denial: " + func + " from pid="
5872 + Binder.getCallingPid()
5873 + ", uid=" + Binder.getCallingUid()
5874 + " requires " + permission;
5875 Log.w(TAG, msg);
5876 throw new SecurityException(msg);
5877 }
5878
5879 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5880 ProviderInfo pi, int uid, int modeFlags) {
5881 try {
5882 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5883 if ((pi.readPermission != null) &&
5884 (pm.checkUidPermission(pi.readPermission, uid)
5885 != PackageManager.PERMISSION_GRANTED)) {
5886 return false;
5887 }
5888 }
5889 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5890 if ((pi.writePermission != null) &&
5891 (pm.checkUidPermission(pi.writePermission, uid)
5892 != PackageManager.PERMISSION_GRANTED)) {
5893 return false;
5894 }
5895 }
5896 return true;
5897 } catch (RemoteException e) {
5898 return false;
5899 }
5900 }
5901
5902 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5903 int modeFlags) {
5904 // Root gets to do everything.
5905 if (uid == 0 || !Process.supportsProcesses()) {
5906 return true;
5907 }
5908 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5909 if (perms == null) return false;
5910 UriPermission perm = perms.get(uri);
5911 if (perm == null) return false;
5912 return (modeFlags&perm.modeFlags) == modeFlags;
5913 }
5914
5915 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5916 // Another redirected-binder-call permissions check as in
5917 // {@link checkComponentPermission}.
5918 Identity tlsIdentity = sCallerIdentity.get();
5919 if (tlsIdentity != null) {
5920 uid = tlsIdentity.uid;
5921 pid = tlsIdentity.pid;
5922 }
5923
5924 // Our own process gets to do everything.
5925 if (pid == MY_PID) {
5926 return PackageManager.PERMISSION_GRANTED;
5927 }
5928 synchronized(this) {
5929 return checkUriPermissionLocked(uri, uid, modeFlags)
5930 ? PackageManager.PERMISSION_GRANTED
5931 : PackageManager.PERMISSION_DENIED;
5932 }
5933 }
5934
5935 private void grantUriPermissionLocked(int callingUid,
5936 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5937 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5938 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5939 if (modeFlags == 0) {
5940 return;
5941 }
5942
5943 final IPackageManager pm = ActivityThread.getPackageManager();
5944
5945 // If this is not a content: uri, we can't do anything with it.
5946 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5947 return;
5948 }
5949
5950 String name = uri.getAuthority();
5951 ProviderInfo pi = null;
5952 ContentProviderRecord cpr
5953 = (ContentProviderRecord)mProvidersByName.get(name);
5954 if (cpr != null) {
5955 pi = cpr.info;
5956 } else {
5957 try {
5958 pi = pm.resolveContentProvider(name,
5959 PackageManager.GET_URI_PERMISSION_PATTERNS);
5960 } catch (RemoteException ex) {
5961 }
5962 }
5963 if (pi == null) {
5964 Log.w(TAG, "No content provider found for: " + name);
5965 return;
5966 }
5967
5968 int targetUid;
5969 try {
5970 targetUid = pm.getPackageUid(targetPkg);
5971 if (targetUid < 0) {
5972 return;
5973 }
5974 } catch (RemoteException ex) {
5975 return;
5976 }
5977
5978 // First... does the target actually need this permission?
5979 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5980 // No need to grant the target this permission.
5981 return;
5982 }
5983
5984 // Second... maybe someone else has already granted the
5985 // permission?
5986 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5987 // No need to grant the target this permission.
5988 return;
5989 }
5990
5991 // Third... is the provider allowing granting of URI permissions?
5992 if (!pi.grantUriPermissions) {
5993 throw new SecurityException("Provider " + pi.packageName
5994 + "/" + pi.name
5995 + " does not allow granting of Uri permissions (uri "
5996 + uri + ")");
5997 }
5998 if (pi.uriPermissionPatterns != null) {
5999 final int N = pi.uriPermissionPatterns.length;
6000 boolean allowed = false;
6001 for (int i=0; i<N; i++) {
6002 if (pi.uriPermissionPatterns[i] != null
6003 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6004 allowed = true;
6005 break;
6006 }
6007 }
6008 if (!allowed) {
6009 throw new SecurityException("Provider " + pi.packageName
6010 + "/" + pi.name
6011 + " does not allow granting of permission to path of Uri "
6012 + uri);
6013 }
6014 }
6015
6016 // Fourth... does the caller itself have permission to access
6017 // this uri?
6018 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6019 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6020 throw new SecurityException("Uid " + callingUid
6021 + " does not have permission to uri " + uri);
6022 }
6023 }
6024
6025 // Okay! So here we are: the caller has the assumed permission
6026 // to the uri, and the target doesn't. Let's now give this to
6027 // the target.
6028
6029 HashMap<Uri, UriPermission> targetUris
6030 = mGrantedUriPermissions.get(targetUid);
6031 if (targetUris == null) {
6032 targetUris = new HashMap<Uri, UriPermission>();
6033 mGrantedUriPermissions.put(targetUid, targetUris);
6034 }
6035
6036 UriPermission perm = targetUris.get(uri);
6037 if (perm == null) {
6038 perm = new UriPermission(targetUid, uri);
6039 targetUris.put(uri, perm);
6040
6041 }
6042 perm.modeFlags |= modeFlags;
6043 if (activity == null) {
6044 perm.globalModeFlags |= modeFlags;
6045 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6046 perm.readActivities.add(activity);
6047 if (activity.readUriPermissions == null) {
6048 activity.readUriPermissions = new HashSet<UriPermission>();
6049 }
6050 activity.readUriPermissions.add(perm);
6051 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6052 perm.writeActivities.add(activity);
6053 if (activity.writeUriPermissions == null) {
6054 activity.writeUriPermissions = new HashSet<UriPermission>();
6055 }
6056 activity.writeUriPermissions.add(perm);
6057 }
6058 }
6059
6060 private void grantUriPermissionFromIntentLocked(int callingUid,
6061 String targetPkg, Intent intent, HistoryRecord activity) {
6062 if (intent == null) {
6063 return;
6064 }
6065 Uri data = intent.getData();
6066 if (data == null) {
6067 return;
6068 }
6069 grantUriPermissionLocked(callingUid, targetPkg, data,
6070 intent.getFlags(), activity);
6071 }
6072
6073 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6074 Uri uri, int modeFlags) {
6075 synchronized(this) {
6076 final ProcessRecord r = getRecordForAppLocked(caller);
6077 if (r == null) {
6078 throw new SecurityException("Unable to find app for caller "
6079 + caller
6080 + " when granting permission to uri " + uri);
6081 }
6082 if (targetPkg == null) {
6083 Log.w(TAG, "grantUriPermission: null target");
6084 return;
6085 }
6086 if (uri == null) {
6087 Log.w(TAG, "grantUriPermission: null uri");
6088 return;
6089 }
6090
6091 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6092 null);
6093 }
6094 }
6095
6096 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6097 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6098 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6099 HashMap<Uri, UriPermission> perms
6100 = mGrantedUriPermissions.get(perm.uid);
6101 if (perms != null) {
6102 perms.remove(perm.uri);
6103 if (perms.size() == 0) {
6104 mGrantedUriPermissions.remove(perm.uid);
6105 }
6106 }
6107 }
6108 }
6109
6110 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6111 if (activity.readUriPermissions != null) {
6112 for (UriPermission perm : activity.readUriPermissions) {
6113 perm.readActivities.remove(activity);
6114 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6115 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6116 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6117 removeUriPermissionIfNeededLocked(perm);
6118 }
6119 }
6120 }
6121 if (activity.writeUriPermissions != null) {
6122 for (UriPermission perm : activity.writeUriPermissions) {
6123 perm.writeActivities.remove(activity);
6124 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6125 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6126 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6127 removeUriPermissionIfNeededLocked(perm);
6128 }
6129 }
6130 }
6131 }
6132
6133 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6134 int modeFlags) {
6135 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6136 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6137 if (modeFlags == 0) {
6138 return;
6139 }
6140
6141 final IPackageManager pm = ActivityThread.getPackageManager();
6142
6143 final String authority = uri.getAuthority();
6144 ProviderInfo pi = null;
6145 ContentProviderRecord cpr
6146 = (ContentProviderRecord)mProvidersByName.get(authority);
6147 if (cpr != null) {
6148 pi = cpr.info;
6149 } else {
6150 try {
6151 pi = pm.resolveContentProvider(authority,
6152 PackageManager.GET_URI_PERMISSION_PATTERNS);
6153 } catch (RemoteException ex) {
6154 }
6155 }
6156 if (pi == null) {
6157 Log.w(TAG, "No content provider found for: " + authority);
6158 return;
6159 }
6160
6161 // Does the caller have this permission on the URI?
6162 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6163 // Right now, if you are not the original owner of the permission,
6164 // you are not allowed to revoke it.
6165 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6166 throw new SecurityException("Uid " + callingUid
6167 + " does not have permission to uri " + uri);
6168 //}
6169 }
6170
6171 // Go through all of the permissions and remove any that match.
6172 final List<String> SEGMENTS = uri.getPathSegments();
6173 if (SEGMENTS != null) {
6174 final int NS = SEGMENTS.size();
6175 int N = mGrantedUriPermissions.size();
6176 for (int i=0; i<N; i++) {
6177 HashMap<Uri, UriPermission> perms
6178 = mGrantedUriPermissions.valueAt(i);
6179 Iterator<UriPermission> it = perms.values().iterator();
6180 toploop:
6181 while (it.hasNext()) {
6182 UriPermission perm = it.next();
6183 Uri targetUri = perm.uri;
6184 if (!authority.equals(targetUri.getAuthority())) {
6185 continue;
6186 }
6187 List<String> targetSegments = targetUri.getPathSegments();
6188 if (targetSegments == null) {
6189 continue;
6190 }
6191 if (targetSegments.size() < NS) {
6192 continue;
6193 }
6194 for (int j=0; j<NS; j++) {
6195 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6196 continue toploop;
6197 }
6198 }
6199 perm.clearModes(modeFlags);
6200 if (perm.modeFlags == 0) {
6201 it.remove();
6202 }
6203 }
6204 if (perms.size() == 0) {
6205 mGrantedUriPermissions.remove(
6206 mGrantedUriPermissions.keyAt(i));
6207 N--;
6208 i--;
6209 }
6210 }
6211 }
6212 }
6213
6214 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6215 int modeFlags) {
6216 synchronized(this) {
6217 final ProcessRecord r = getRecordForAppLocked(caller);
6218 if (r == null) {
6219 throw new SecurityException("Unable to find app for caller "
6220 + caller
6221 + " when revoking permission to uri " + uri);
6222 }
6223 if (uri == null) {
6224 Log.w(TAG, "revokeUriPermission: null uri");
6225 return;
6226 }
6227
6228 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6229 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6230 if (modeFlags == 0) {
6231 return;
6232 }
6233
6234 final IPackageManager pm = ActivityThread.getPackageManager();
6235
6236 final String authority = uri.getAuthority();
6237 ProviderInfo pi = null;
6238 ContentProviderRecord cpr
6239 = (ContentProviderRecord)mProvidersByName.get(authority);
6240 if (cpr != null) {
6241 pi = cpr.info;
6242 } else {
6243 try {
6244 pi = pm.resolveContentProvider(authority,
6245 PackageManager.GET_URI_PERMISSION_PATTERNS);
6246 } catch (RemoteException ex) {
6247 }
6248 }
6249 if (pi == null) {
6250 Log.w(TAG, "No content provider found for: " + authority);
6251 return;
6252 }
6253
6254 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6255 }
6256 }
6257
6258 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6259 synchronized (this) {
6260 ProcessRecord app =
6261 who != null ? getRecordForAppLocked(who) : null;
6262 if (app == null) return;
6263
6264 Message msg = Message.obtain();
6265 msg.what = WAIT_FOR_DEBUGGER_MSG;
6266 msg.obj = app;
6267 msg.arg1 = waiting ? 1 : 0;
6268 mHandler.sendMessage(msg);
6269 }
6270 }
6271
6272 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6273 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006274 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006275 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006276 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006277 }
6278
6279 // =========================================================
6280 // TASK MANAGEMENT
6281 // =========================================================
6282
6283 public List getTasks(int maxNum, int flags,
6284 IThumbnailReceiver receiver) {
6285 ArrayList list = new ArrayList();
6286
6287 PendingThumbnailsRecord pending = null;
6288 IApplicationThread topThumbnail = null;
6289 HistoryRecord topRecord = null;
6290
6291 synchronized(this) {
6292 if (localLOGV) Log.v(
6293 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6294 + ", receiver=" + receiver);
6295
6296 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6297 != PackageManager.PERMISSION_GRANTED) {
6298 if (receiver != null) {
6299 // If the caller wants to wait for pending thumbnails,
6300 // it ain't gonna get them.
6301 try {
6302 receiver.finished();
6303 } catch (RemoteException ex) {
6304 }
6305 }
6306 String msg = "Permission Denial: getTasks() from pid="
6307 + Binder.getCallingPid()
6308 + ", uid=" + Binder.getCallingUid()
6309 + " requires " + android.Manifest.permission.GET_TASKS;
6310 Log.w(TAG, msg);
6311 throw new SecurityException(msg);
6312 }
6313
6314 int pos = mHistory.size()-1;
6315 HistoryRecord next =
6316 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6317 HistoryRecord top = null;
6318 CharSequence topDescription = null;
6319 TaskRecord curTask = null;
6320 int numActivities = 0;
6321 int numRunning = 0;
6322 while (pos >= 0 && maxNum > 0) {
6323 final HistoryRecord r = next;
6324 pos--;
6325 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6326
6327 // Initialize state for next task if needed.
6328 if (top == null ||
6329 (top.state == ActivityState.INITIALIZING
6330 && top.task == r.task)) {
6331 top = r;
6332 topDescription = r.description;
6333 curTask = r.task;
6334 numActivities = numRunning = 0;
6335 }
6336
6337 // Add 'r' into the current task.
6338 numActivities++;
6339 if (r.app != null && r.app.thread != null) {
6340 numRunning++;
6341 }
6342 if (topDescription == null) {
6343 topDescription = r.description;
6344 }
6345
6346 if (localLOGV) Log.v(
6347 TAG, r.intent.getComponent().flattenToShortString()
6348 + ": task=" + r.task);
6349
6350 // If the next one is a different task, generate a new
6351 // TaskInfo entry for what we have.
6352 if (next == null || next.task != curTask) {
6353 ActivityManager.RunningTaskInfo ci
6354 = new ActivityManager.RunningTaskInfo();
6355 ci.id = curTask.taskId;
6356 ci.baseActivity = r.intent.getComponent();
6357 ci.topActivity = top.intent.getComponent();
6358 ci.thumbnail = top.thumbnail;
6359 ci.description = topDescription;
6360 ci.numActivities = numActivities;
6361 ci.numRunning = numRunning;
6362 //System.out.println(
6363 // "#" + maxNum + ": " + " descr=" + ci.description);
6364 if (ci.thumbnail == null && receiver != null) {
6365 if (localLOGV) Log.v(
6366 TAG, "State=" + top.state + "Idle=" + top.idle
6367 + " app=" + top.app
6368 + " thr=" + (top.app != null ? top.app.thread : null));
6369 if (top.state == ActivityState.RESUMED
6370 || top.state == ActivityState.PAUSING) {
6371 if (top.idle && top.app != null
6372 && top.app.thread != null) {
6373 topRecord = top;
6374 topThumbnail = top.app.thread;
6375 } else {
6376 top.thumbnailNeeded = true;
6377 }
6378 }
6379 if (pending == null) {
6380 pending = new PendingThumbnailsRecord(receiver);
6381 }
6382 pending.pendingRecords.add(top);
6383 }
6384 list.add(ci);
6385 maxNum--;
6386 top = null;
6387 }
6388 }
6389
6390 if (pending != null) {
6391 mPendingThumbnails.add(pending);
6392 }
6393 }
6394
6395 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6396
6397 if (topThumbnail != null) {
6398 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6399 try {
6400 topThumbnail.requestThumbnail(topRecord);
6401 } catch (Exception e) {
6402 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6403 sendPendingThumbnail(null, topRecord, null, null, true);
6404 }
6405 }
6406
6407 if (pending == null && receiver != null) {
6408 // In this case all thumbnails were available and the client
6409 // is being asked to be told when the remaining ones come in...
6410 // which is unusually, since the top-most currently running
6411 // activity should never have a canned thumbnail! Oh well.
6412 try {
6413 receiver.finished();
6414 } catch (RemoteException ex) {
6415 }
6416 }
6417
6418 return list;
6419 }
6420
6421 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6422 int flags) {
6423 synchronized (this) {
6424 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6425 "getRecentTasks()");
6426
6427 final int N = mRecentTasks.size();
6428 ArrayList<ActivityManager.RecentTaskInfo> res
6429 = new ArrayList<ActivityManager.RecentTaskInfo>(
6430 maxNum < N ? maxNum : N);
6431 for (int i=0; i<N && maxNum > 0; i++) {
6432 TaskRecord tr = mRecentTasks.get(i);
6433 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6434 || (tr.intent == null)
6435 || ((tr.intent.getFlags()
6436 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6437 ActivityManager.RecentTaskInfo rti
6438 = new ActivityManager.RecentTaskInfo();
6439 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6440 rti.baseIntent = new Intent(
6441 tr.intent != null ? tr.intent : tr.affinityIntent);
6442 rti.origActivity = tr.origActivity;
6443 res.add(rti);
6444 maxNum--;
6445 }
6446 }
6447 return res;
6448 }
6449 }
6450
6451 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6452 int j;
6453 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6454 TaskRecord jt = startTask;
6455
6456 // First look backwards
6457 for (j=startIndex-1; j>=0; j--) {
6458 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6459 if (r.task != jt) {
6460 jt = r.task;
6461 if (affinity.equals(jt.affinity)) {
6462 return j;
6463 }
6464 }
6465 }
6466
6467 // Now look forwards
6468 final int N = mHistory.size();
6469 jt = startTask;
6470 for (j=startIndex+1; j<N; j++) {
6471 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6472 if (r.task != jt) {
6473 if (affinity.equals(jt.affinity)) {
6474 return j;
6475 }
6476 jt = r.task;
6477 }
6478 }
6479
6480 // Might it be at the top?
6481 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6482 return N-1;
6483 }
6484
6485 return -1;
6486 }
6487
6488 /**
6489 * Perform a reset of the given task, if needed as part of launching it.
6490 * Returns the new HistoryRecord at the top of the task.
6491 */
6492 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6493 HistoryRecord newActivity) {
6494 boolean forceReset = (newActivity.info.flags
6495 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6496 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6497 if ((newActivity.info.flags
6498 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6499 forceReset = true;
6500 }
6501 }
6502
6503 final TaskRecord task = taskTop.task;
6504
6505 // We are going to move through the history list so that we can look
6506 // at each activity 'target' with 'below' either the interesting
6507 // activity immediately below it in the stack or null.
6508 HistoryRecord target = null;
6509 int targetI = 0;
6510 int taskTopI = -1;
6511 int replyChainEnd = -1;
6512 int lastReparentPos = -1;
6513 for (int i=mHistory.size()-1; i>=-1; i--) {
6514 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6515
6516 if (below != null && below.finishing) {
6517 continue;
6518 }
6519 if (target == null) {
6520 target = below;
6521 targetI = i;
6522 // If we were in the middle of a reply chain before this
6523 // task, it doesn't appear like the root of the chain wants
6524 // anything interesting, so drop it.
6525 replyChainEnd = -1;
6526 continue;
6527 }
6528
6529 final int flags = target.info.flags;
6530
6531 final boolean finishOnTaskLaunch =
6532 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6533 final boolean allowTaskReparenting =
6534 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6535
6536 if (target.task == task) {
6537 // We are inside of the task being reset... we'll either
6538 // finish this activity, push it out for another task,
6539 // or leave it as-is. We only do this
6540 // for activities that are not the root of the task (since
6541 // if we finish the root, we may no longer have the task!).
6542 if (taskTopI < 0) {
6543 taskTopI = targetI;
6544 }
6545 if (below != null && below.task == task) {
6546 final boolean clearWhenTaskReset =
6547 (target.intent.getFlags()
6548 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006549 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006550 // If this activity is sending a reply to a previous
6551 // activity, we can't do anything with it now until
6552 // we reach the start of the reply chain.
6553 // XXX note that we are assuming the result is always
6554 // to the previous activity, which is almost always
6555 // the case but we really shouldn't count on.
6556 if (replyChainEnd < 0) {
6557 replyChainEnd = targetI;
6558 }
Ed Heyl73798232009-03-24 21:32:21 -07006559 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006560 && target.taskAffinity != null
6561 && !target.taskAffinity.equals(task.affinity)) {
6562 // If this activity has an affinity for another
6563 // task, then we need to move it out of here. We will
6564 // move it as far out of the way as possible, to the
6565 // bottom of the activity stack. This also keeps it
6566 // correctly ordered with any activities we previously
6567 // moved.
6568 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6569 if (target.taskAffinity != null
6570 && target.taskAffinity.equals(p.task.affinity)) {
6571 // If the activity currently at the bottom has the
6572 // same task affinity as the one we are moving,
6573 // then merge it into the same task.
6574 target.task = p.task;
6575 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6576 + " out to bottom task " + p.task);
6577 } else {
6578 mCurTask++;
6579 if (mCurTask <= 0) {
6580 mCurTask = 1;
6581 }
6582 target.task = new TaskRecord(mCurTask, target.info, null,
6583 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6584 target.task.affinityIntent = target.intent;
6585 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6586 + " out to new task " + target.task);
6587 }
6588 mWindowManager.setAppGroupId(target, task.taskId);
6589 if (replyChainEnd < 0) {
6590 replyChainEnd = targetI;
6591 }
6592 int dstPos = 0;
6593 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6594 p = (HistoryRecord)mHistory.get(srcPos);
6595 if (p.finishing) {
6596 continue;
6597 }
6598 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6599 + " out to target's task " + target.task);
6600 task.numActivities--;
6601 p.task = target.task;
6602 target.task.numActivities++;
6603 mHistory.remove(srcPos);
6604 mHistory.add(dstPos, p);
6605 mWindowManager.moveAppToken(dstPos, p);
6606 mWindowManager.setAppGroupId(p, p.task.taskId);
6607 dstPos++;
6608 if (VALIDATE_TOKENS) {
6609 mWindowManager.validateAppTokens(mHistory);
6610 }
6611 i++;
6612 }
6613 if (taskTop == p) {
6614 taskTop = below;
6615 }
6616 if (taskTopI == replyChainEnd) {
6617 taskTopI = -1;
6618 }
6619 replyChainEnd = -1;
6620 addRecentTask(target.task);
6621 } else if (forceReset || finishOnTaskLaunch
6622 || clearWhenTaskReset) {
6623 // If the activity should just be removed -- either
6624 // because it asks for it, or the task should be
6625 // cleared -- then finish it and anything that is
6626 // part of its reply chain.
6627 if (clearWhenTaskReset) {
6628 // In this case, we want to finish this activity
6629 // and everything above it, so be sneaky and pretend
6630 // like these are all in the reply chain.
6631 replyChainEnd = targetI+1;
6632 while (replyChainEnd < mHistory.size() &&
6633 ((HistoryRecord)mHistory.get(
6634 replyChainEnd)).task == task) {
6635 replyChainEnd++;
6636 }
6637 replyChainEnd--;
6638 } else if (replyChainEnd < 0) {
6639 replyChainEnd = targetI;
6640 }
6641 HistoryRecord p = null;
6642 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6643 p = (HistoryRecord)mHistory.get(srcPos);
6644 if (p.finishing) {
6645 continue;
6646 }
6647 if (finishActivityLocked(p, srcPos,
6648 Activity.RESULT_CANCELED, null, "reset")) {
6649 replyChainEnd--;
6650 srcPos--;
6651 }
6652 }
6653 if (taskTop == p) {
6654 taskTop = below;
6655 }
6656 if (taskTopI == replyChainEnd) {
6657 taskTopI = -1;
6658 }
6659 replyChainEnd = -1;
6660 } else {
6661 // If we were in the middle of a chain, well the
6662 // activity that started it all doesn't want anything
6663 // special, so leave it all as-is.
6664 replyChainEnd = -1;
6665 }
6666 } else {
6667 // Reached the bottom of the task -- any reply chain
6668 // should be left as-is.
6669 replyChainEnd = -1;
6670 }
6671
6672 } else if (target.resultTo != null) {
6673 // If this activity is sending a reply to a previous
6674 // activity, we can't do anything with it now until
6675 // we reach the start of the reply chain.
6676 // XXX note that we are assuming the result is always
6677 // to the previous activity, which is almost always
6678 // the case but we really shouldn't count on.
6679 if (replyChainEnd < 0) {
6680 replyChainEnd = targetI;
6681 }
6682
6683 } else if (taskTopI >= 0 && allowTaskReparenting
6684 && task.affinity != null
6685 && task.affinity.equals(target.taskAffinity)) {
6686 // We are inside of another task... if this activity has
6687 // an affinity for our task, then either remove it if we are
6688 // clearing or move it over to our task. Note that
6689 // we currently punt on the case where we are resetting a
6690 // task that is not at the top but who has activities above
6691 // with an affinity to it... this is really not a normal
6692 // case, and we will need to later pull that task to the front
6693 // and usually at that point we will do the reset and pick
6694 // up those remaining activities. (This only happens if
6695 // someone starts an activity in a new task from an activity
6696 // in a task that is not currently on top.)
6697 if (forceReset || finishOnTaskLaunch) {
6698 if (replyChainEnd < 0) {
6699 replyChainEnd = targetI;
6700 }
6701 HistoryRecord p = null;
6702 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6703 p = (HistoryRecord)mHistory.get(srcPos);
6704 if (p.finishing) {
6705 continue;
6706 }
6707 if (finishActivityLocked(p, srcPos,
6708 Activity.RESULT_CANCELED, null, "reset")) {
6709 taskTopI--;
6710 lastReparentPos--;
6711 replyChainEnd--;
6712 srcPos--;
6713 }
6714 }
6715 replyChainEnd = -1;
6716 } else {
6717 if (replyChainEnd < 0) {
6718 replyChainEnd = targetI;
6719 }
6720 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6721 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6722 if (p.finishing) {
6723 continue;
6724 }
6725 if (lastReparentPos < 0) {
6726 lastReparentPos = taskTopI;
6727 taskTop = p;
6728 } else {
6729 lastReparentPos--;
6730 }
6731 mHistory.remove(srcPos);
6732 p.task.numActivities--;
6733 p.task = task;
6734 mHistory.add(lastReparentPos, p);
6735 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6736 + " in to resetting task " + task);
6737 task.numActivities++;
6738 mWindowManager.moveAppToken(lastReparentPos, p);
6739 mWindowManager.setAppGroupId(p, p.task.taskId);
6740 if (VALIDATE_TOKENS) {
6741 mWindowManager.validateAppTokens(mHistory);
6742 }
6743 }
6744 replyChainEnd = -1;
6745
6746 // Now we've moved it in to place... but what if this is
6747 // a singleTop activity and we have put it on top of another
6748 // instance of the same activity? Then we drop the instance
6749 // below so it remains singleTop.
6750 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6751 for (int j=lastReparentPos-1; j>=0; j--) {
6752 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6753 if (p.finishing) {
6754 continue;
6755 }
6756 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6757 if (finishActivityLocked(p, j,
6758 Activity.RESULT_CANCELED, null, "replace")) {
6759 taskTopI--;
6760 lastReparentPos--;
6761 }
6762 }
6763 }
6764 }
6765 }
6766 }
6767
6768 target = below;
6769 targetI = i;
6770 }
6771
6772 return taskTop;
6773 }
6774
6775 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006776 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006777 */
6778 public void moveTaskToFront(int task) {
6779 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6780 "moveTaskToFront()");
6781
6782 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006783 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6784 Binder.getCallingUid(), "Task to front")) {
6785 return;
6786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006787 final long origId = Binder.clearCallingIdentity();
6788 try {
6789 int N = mRecentTasks.size();
6790 for (int i=0; i<N; i++) {
6791 TaskRecord tr = mRecentTasks.get(i);
6792 if (tr.taskId == task) {
6793 moveTaskToFrontLocked(tr);
6794 return;
6795 }
6796 }
6797 for (int i=mHistory.size()-1; i>=0; i--) {
6798 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6799 if (hr.task.taskId == task) {
6800 moveTaskToFrontLocked(hr.task);
6801 return;
6802 }
6803 }
6804 } finally {
6805 Binder.restoreCallingIdentity(origId);
6806 }
6807 }
6808 }
6809
6810 private final void moveTaskToFrontLocked(TaskRecord tr) {
6811 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6812
6813 final int task = tr.taskId;
6814 int top = mHistory.size()-1;
6815
6816 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6817 // nothing to do!
6818 return;
6819 }
6820
6821 if (DEBUG_TRANSITION) Log.v(TAG,
6822 "Prepare to front transition: task=" + tr);
6823 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6824
6825 ArrayList moved = new ArrayList();
6826
6827 // Applying the affinities may have removed entries from the history,
6828 // so get the size again.
6829 top = mHistory.size()-1;
6830 int pos = top;
6831
6832 // Shift all activities with this task up to the top
6833 // of the stack, keeping them in the same internal order.
6834 while (pos >= 0) {
6835 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6836 if (localLOGV) Log.v(
6837 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6838 boolean first = true;
6839 if (r.task.taskId == task) {
6840 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6841 mHistory.remove(pos);
6842 mHistory.add(top, r);
6843 moved.add(0, r);
6844 top--;
6845 if (first) {
6846 addRecentTask(r.task);
6847 first = false;
6848 }
6849 }
6850 pos--;
6851 }
6852
6853 mWindowManager.moveAppTokensToTop(moved);
6854 if (VALIDATE_TOKENS) {
6855 mWindowManager.validateAppTokens(mHistory);
6856 }
6857
6858 finishTaskMove(task);
6859 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6860 }
6861
6862 private final void finishTaskMove(int task) {
6863 resumeTopActivityLocked(null);
6864 }
6865
6866 public void moveTaskToBack(int task) {
6867 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6868 "moveTaskToBack()");
6869
6870 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006871 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6872 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6873 Binder.getCallingUid(), "Task to back")) {
6874 return;
6875 }
6876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006877 final long origId = Binder.clearCallingIdentity();
6878 moveTaskToBackLocked(task);
6879 Binder.restoreCallingIdentity(origId);
6880 }
6881 }
6882
6883 /**
6884 * Moves an activity, and all of the other activities within the same task, to the bottom
6885 * of the history stack. The activity's order within the task is unchanged.
6886 *
6887 * @param token A reference to the activity we wish to move
6888 * @param nonRoot If false then this only works if the activity is the root
6889 * of a task; if true it will work for any activity in a task.
6890 * @return Returns true if the move completed, false if not.
6891 */
6892 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6893 synchronized(this) {
6894 final long origId = Binder.clearCallingIdentity();
6895 int taskId = getTaskForActivityLocked(token, !nonRoot);
6896 if (taskId >= 0) {
6897 return moveTaskToBackLocked(taskId);
6898 }
6899 Binder.restoreCallingIdentity(origId);
6900 }
6901 return false;
6902 }
6903
6904 /**
6905 * Worker method for rearranging history stack. Implements the function of moving all
6906 * activities for a specific task (gathering them if disjoint) into a single group at the
6907 * bottom of the stack.
6908 *
6909 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6910 * to premeptively cancel the move.
6911 *
6912 * @param task The taskId to collect and move to the bottom.
6913 * @return Returns true if the move completed, false if not.
6914 */
6915 private final boolean moveTaskToBackLocked(int task) {
6916 Log.i(TAG, "moveTaskToBack: " + task);
6917
6918 // If we have a watcher, preflight the move before committing to it. First check
6919 // for *other* available tasks, but if none are available, then try again allowing the
6920 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006921 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006922 HistoryRecord next = topRunningActivityLocked(null, task);
6923 if (next == null) {
6924 next = topRunningActivityLocked(null, 0);
6925 }
6926 if (next != null) {
6927 // ask watcher if this is allowed
6928 boolean moveOK = true;
6929 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006930 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006931 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006932 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006933 }
6934 if (!moveOK) {
6935 return false;
6936 }
6937 }
6938 }
6939
6940 ArrayList moved = new ArrayList();
6941
6942 if (DEBUG_TRANSITION) Log.v(TAG,
6943 "Prepare to back transition: task=" + task);
6944 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6945
6946 final int N = mHistory.size();
6947 int bottom = 0;
6948 int pos = 0;
6949
6950 // Shift all activities with this task down to the bottom
6951 // of the stack, keeping them in the same internal order.
6952 while (pos < N) {
6953 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6954 if (localLOGV) Log.v(
6955 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6956 if (r.task.taskId == task) {
6957 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6958 mHistory.remove(pos);
6959 mHistory.add(bottom, r);
6960 moved.add(r);
6961 bottom++;
6962 }
6963 pos++;
6964 }
6965
6966 mWindowManager.moveAppTokensToBottom(moved);
6967 if (VALIDATE_TOKENS) {
6968 mWindowManager.validateAppTokens(mHistory);
6969 }
6970
6971 finishTaskMove(task);
6972 return true;
6973 }
6974
6975 public void moveTaskBackwards(int task) {
6976 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6977 "moveTaskBackwards()");
6978
6979 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006980 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6981 Binder.getCallingUid(), "Task backwards")) {
6982 return;
6983 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006984 final long origId = Binder.clearCallingIdentity();
6985 moveTaskBackwardsLocked(task);
6986 Binder.restoreCallingIdentity(origId);
6987 }
6988 }
6989
6990 private final void moveTaskBackwardsLocked(int task) {
6991 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6992 }
6993
6994 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6995 synchronized(this) {
6996 return getTaskForActivityLocked(token, onlyRoot);
6997 }
6998 }
6999
7000 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7001 final int N = mHistory.size();
7002 TaskRecord lastTask = null;
7003 for (int i=0; i<N; i++) {
7004 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7005 if (r == token) {
7006 if (!onlyRoot || lastTask != r.task) {
7007 return r.task.taskId;
7008 }
7009 return -1;
7010 }
7011 lastTask = r.task;
7012 }
7013
7014 return -1;
7015 }
7016
7017 /**
7018 * Returns the top activity in any existing task matching the given
7019 * Intent. Returns null if no such task is found.
7020 */
7021 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7022 ComponentName cls = intent.getComponent();
7023 if (info.targetActivity != null) {
7024 cls = new ComponentName(info.packageName, info.targetActivity);
7025 }
7026
7027 TaskRecord cp = null;
7028
7029 final int N = mHistory.size();
7030 for (int i=(N-1); i>=0; i--) {
7031 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7032 if (!r.finishing && r.task != cp
7033 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7034 cp = r.task;
7035 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7036 // + "/aff=" + r.task.affinity + " to new cls="
7037 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7038 if (r.task.affinity != null) {
7039 if (r.task.affinity.equals(info.taskAffinity)) {
7040 //Log.i(TAG, "Found matching affinity!");
7041 return r;
7042 }
7043 } else if (r.task.intent != null
7044 && r.task.intent.getComponent().equals(cls)) {
7045 //Log.i(TAG, "Found matching class!");
7046 //dump();
7047 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7048 return r;
7049 } else if (r.task.affinityIntent != null
7050 && r.task.affinityIntent.getComponent().equals(cls)) {
7051 //Log.i(TAG, "Found matching class!");
7052 //dump();
7053 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7054 return r;
7055 }
7056 }
7057 }
7058
7059 return null;
7060 }
7061
7062 /**
7063 * Returns the first activity (starting from the top of the stack) that
7064 * is the same as the given activity. Returns null if no such activity
7065 * is found.
7066 */
7067 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7068 ComponentName cls = intent.getComponent();
7069 if (info.targetActivity != null) {
7070 cls = new ComponentName(info.packageName, info.targetActivity);
7071 }
7072
7073 final int N = mHistory.size();
7074 for (int i=(N-1); i>=0; i--) {
7075 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7076 if (!r.finishing) {
7077 if (r.intent.getComponent().equals(cls)) {
7078 //Log.i(TAG, "Found matching class!");
7079 //dump();
7080 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7081 return r;
7082 }
7083 }
7084 }
7085
7086 return null;
7087 }
7088
7089 public void finishOtherInstances(IBinder token, ComponentName className) {
7090 synchronized(this) {
7091 final long origId = Binder.clearCallingIdentity();
7092
7093 int N = mHistory.size();
7094 TaskRecord lastTask = null;
7095 for (int i=0; i<N; i++) {
7096 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7097 if (r.realActivity.equals(className)
7098 && r != token && lastTask != r.task) {
7099 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7100 null, "others")) {
7101 i--;
7102 N--;
7103 }
7104 }
7105 lastTask = r.task;
7106 }
7107
7108 Binder.restoreCallingIdentity(origId);
7109 }
7110 }
7111
7112 // =========================================================
7113 // THUMBNAILS
7114 // =========================================================
7115
7116 public void reportThumbnail(IBinder token,
7117 Bitmap thumbnail, CharSequence description) {
7118 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7119 final long origId = Binder.clearCallingIdentity();
7120 sendPendingThumbnail(null, token, thumbnail, description, true);
7121 Binder.restoreCallingIdentity(origId);
7122 }
7123
7124 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7125 Bitmap thumbnail, CharSequence description, boolean always) {
7126 TaskRecord task = null;
7127 ArrayList receivers = null;
7128
7129 //System.out.println("Send pending thumbnail: " + r);
7130
7131 synchronized(this) {
7132 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007133 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007134 if (index < 0) {
7135 return;
7136 }
7137 r = (HistoryRecord)mHistory.get(index);
7138 }
7139 if (thumbnail == null) {
7140 thumbnail = r.thumbnail;
7141 description = r.description;
7142 }
7143 if (thumbnail == null && !always) {
7144 // If there is no thumbnail, and this entry is not actually
7145 // going away, then abort for now and pick up the next
7146 // thumbnail we get.
7147 return;
7148 }
7149 task = r.task;
7150
7151 int N = mPendingThumbnails.size();
7152 int i=0;
7153 while (i<N) {
7154 PendingThumbnailsRecord pr =
7155 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7156 //System.out.println("Looking in " + pr.pendingRecords);
7157 if (pr.pendingRecords.remove(r)) {
7158 if (receivers == null) {
7159 receivers = new ArrayList();
7160 }
7161 receivers.add(pr);
7162 if (pr.pendingRecords.size() == 0) {
7163 pr.finished = true;
7164 mPendingThumbnails.remove(i);
7165 N--;
7166 continue;
7167 }
7168 }
7169 i++;
7170 }
7171 }
7172
7173 if (receivers != null) {
7174 final int N = receivers.size();
7175 for (int i=0; i<N; i++) {
7176 try {
7177 PendingThumbnailsRecord pr =
7178 (PendingThumbnailsRecord)receivers.get(i);
7179 pr.receiver.newThumbnail(
7180 task != null ? task.taskId : -1, thumbnail, description);
7181 if (pr.finished) {
7182 pr.receiver.finished();
7183 }
7184 } catch (Exception e) {
7185 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7186 }
7187 }
7188 }
7189 }
7190
7191 // =========================================================
7192 // CONTENT PROVIDERS
7193 // =========================================================
7194
7195 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7196 List providers = null;
7197 try {
7198 providers = ActivityThread.getPackageManager().
7199 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007200 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007201 } catch (RemoteException ex) {
7202 }
7203 if (providers != null) {
7204 final int N = providers.size();
7205 for (int i=0; i<N; i++) {
7206 ProviderInfo cpi =
7207 (ProviderInfo)providers.get(i);
7208 ContentProviderRecord cpr =
7209 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7210 if (cpr == null) {
7211 cpr = new ContentProviderRecord(cpi, app.info);
7212 mProvidersByClass.put(cpi.name, cpr);
7213 }
7214 app.pubProviders.put(cpi.name, cpr);
7215 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007216 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007217 }
7218 }
7219 return providers;
7220 }
7221
7222 private final String checkContentProviderPermissionLocked(
7223 ProviderInfo cpi, ProcessRecord r, int mode) {
7224 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7225 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7226 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7227 cpi.exported ? -1 : cpi.applicationInfo.uid)
7228 == PackageManager.PERMISSION_GRANTED
7229 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7230 return null;
7231 }
7232 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7233 cpi.exported ? -1 : cpi.applicationInfo.uid)
7234 == PackageManager.PERMISSION_GRANTED) {
7235 return null;
7236 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007237
7238 PathPermission[] pps = cpi.pathPermissions;
7239 if (pps != null) {
7240 int i = pps.length;
7241 while (i > 0) {
7242 i--;
7243 PathPermission pp = pps[i];
7244 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7245 cpi.exported ? -1 : cpi.applicationInfo.uid)
7246 == PackageManager.PERMISSION_GRANTED
7247 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7248 return null;
7249 }
7250 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7251 cpi.exported ? -1 : cpi.applicationInfo.uid)
7252 == PackageManager.PERMISSION_GRANTED) {
7253 return null;
7254 }
7255 }
7256 }
7257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007258 String msg = "Permission Denial: opening provider " + cpi.name
7259 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7260 + ", uid=" + callingUid + ") requires "
7261 + cpi.readPermission + " or " + cpi.writePermission;
7262 Log.w(TAG, msg);
7263 return msg;
7264 }
7265
7266 private final ContentProviderHolder getContentProviderImpl(
7267 IApplicationThread caller, String name) {
7268 ContentProviderRecord cpr;
7269 ProviderInfo cpi = null;
7270
7271 synchronized(this) {
7272 ProcessRecord r = null;
7273 if (caller != null) {
7274 r = getRecordForAppLocked(caller);
7275 if (r == null) {
7276 throw new SecurityException(
7277 "Unable to find app for caller " + caller
7278 + " (pid=" + Binder.getCallingPid()
7279 + ") when getting content provider " + name);
7280 }
7281 }
7282
7283 // First check if this content provider has been published...
7284 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7285 if (cpr != null) {
7286 cpi = cpr.info;
7287 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7288 return new ContentProviderHolder(cpi,
7289 cpi.readPermission != null
7290 ? cpi.readPermission : cpi.writePermission);
7291 }
7292
7293 if (r != null && cpr.canRunHere(r)) {
7294 // This provider has been published or is in the process
7295 // of being published... but it is also allowed to run
7296 // in the caller's process, so don't make a connection
7297 // and just let the caller instantiate its own instance.
7298 if (cpr.provider != null) {
7299 // don't give caller the provider object, it needs
7300 // to make its own.
7301 cpr = new ContentProviderRecord(cpr);
7302 }
7303 return cpr;
7304 }
7305
7306 final long origId = Binder.clearCallingIdentity();
7307
7308 // In this case the provider is a single instance, so we can
7309 // return it right away.
7310 if (r != null) {
7311 r.conProviders.add(cpr);
7312 cpr.clients.add(r);
7313 } else {
7314 cpr.externals++;
7315 }
7316
7317 if (cpr.app != null) {
7318 updateOomAdjLocked(cpr.app);
7319 }
7320
7321 Binder.restoreCallingIdentity(origId);
7322
7323 } else {
7324 try {
7325 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007326 resolveContentProvider(name,
7327 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007328 } catch (RemoteException ex) {
7329 }
7330 if (cpi == null) {
7331 return null;
7332 }
7333
7334 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7335 return new ContentProviderHolder(cpi,
7336 cpi.readPermission != null
7337 ? cpi.readPermission : cpi.writePermission);
7338 }
7339
7340 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7341 final boolean firstClass = cpr == null;
7342 if (firstClass) {
7343 try {
7344 ApplicationInfo ai =
7345 ActivityThread.getPackageManager().
7346 getApplicationInfo(
7347 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007348 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007349 if (ai == null) {
7350 Log.w(TAG, "No package info for content provider "
7351 + cpi.name);
7352 return null;
7353 }
7354 cpr = new ContentProviderRecord(cpi, ai);
7355 } catch (RemoteException ex) {
7356 // pm is in same process, this will never happen.
7357 }
7358 }
7359
7360 if (r != null && cpr.canRunHere(r)) {
7361 // If this is a multiprocess provider, then just return its
7362 // info and allow the caller to instantiate it. Only do
7363 // this if the provider is the same user as the caller's
7364 // process, or can run as root (so can be in any process).
7365 return cpr;
7366 }
7367
7368 if (false) {
7369 RuntimeException e = new RuntimeException("foo");
7370 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7371 // + " pruid " + ai.uid + "): " + cpi.className, e);
7372 }
7373
7374 // This is single process, and our app is now connecting to it.
7375 // See if we are already in the process of launching this
7376 // provider.
7377 final int N = mLaunchingProviders.size();
7378 int i;
7379 for (i=0; i<N; i++) {
7380 if (mLaunchingProviders.get(i) == cpr) {
7381 break;
7382 }
7383 if (false) {
7384 final ContentProviderRecord rec =
7385 (ContentProviderRecord)mLaunchingProviders.get(i);
7386 if (rec.info.name.equals(cpr.info.name)) {
7387 cpr = rec;
7388 break;
7389 }
7390 }
7391 }
7392
7393 // If the provider is not already being launched, then get it
7394 // started.
7395 if (i >= N) {
7396 final long origId = Binder.clearCallingIdentity();
7397 ProcessRecord proc = startProcessLocked(cpi.processName,
7398 cpr.appInfo, false, 0, "content provider",
7399 new ComponentName(cpi.applicationInfo.packageName,
7400 cpi.name));
7401 if (proc == null) {
7402 Log.w(TAG, "Unable to launch app "
7403 + cpi.applicationInfo.packageName + "/"
7404 + cpi.applicationInfo.uid + " for provider "
7405 + name + ": process is bad");
7406 return null;
7407 }
7408 cpr.launchingApp = proc;
7409 mLaunchingProviders.add(cpr);
7410 Binder.restoreCallingIdentity(origId);
7411 }
7412
7413 // Make sure the provider is published (the same provider class
7414 // may be published under multiple names).
7415 if (firstClass) {
7416 mProvidersByClass.put(cpi.name, cpr);
7417 }
7418 mProvidersByName.put(name, cpr);
7419
7420 if (r != null) {
7421 r.conProviders.add(cpr);
7422 cpr.clients.add(r);
7423 } else {
7424 cpr.externals++;
7425 }
7426 }
7427 }
7428
7429 // Wait for the provider to be published...
7430 synchronized (cpr) {
7431 while (cpr.provider == null) {
7432 if (cpr.launchingApp == null) {
7433 Log.w(TAG, "Unable to launch app "
7434 + cpi.applicationInfo.packageName + "/"
7435 + cpi.applicationInfo.uid + " for provider "
7436 + name + ": launching app became null");
7437 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7438 cpi.applicationInfo.packageName,
7439 cpi.applicationInfo.uid, name);
7440 return null;
7441 }
7442 try {
7443 cpr.wait();
7444 } catch (InterruptedException ex) {
7445 }
7446 }
7447 }
7448 return cpr;
7449 }
7450
7451 public final ContentProviderHolder getContentProvider(
7452 IApplicationThread caller, String name) {
7453 if (caller == null) {
7454 String msg = "null IApplicationThread when getting content provider "
7455 + name;
7456 Log.w(TAG, msg);
7457 throw new SecurityException(msg);
7458 }
7459
7460 return getContentProviderImpl(caller, name);
7461 }
7462
7463 private ContentProviderHolder getContentProviderExternal(String name) {
7464 return getContentProviderImpl(null, name);
7465 }
7466
7467 /**
7468 * Drop a content provider from a ProcessRecord's bookkeeping
7469 * @param cpr
7470 */
7471 public void removeContentProvider(IApplicationThread caller, String name) {
7472 synchronized (this) {
7473 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7474 if(cpr == null) {
7475 //remove from mProvidersByClass
7476 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7477 return;
7478 }
7479 final ProcessRecord r = getRecordForAppLocked(caller);
7480 if (r == null) {
7481 throw new SecurityException(
7482 "Unable to find app for caller " + caller +
7483 " when removing content provider " + name);
7484 }
7485 //update content provider record entry info
7486 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7487 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7488 r.info.processName+" from process "+localCpr.appInfo.processName);
7489 if(localCpr.appInfo.processName == r.info.processName) {
7490 //should not happen. taken care of as a local provider
7491 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7492 return;
7493 } else {
7494 localCpr.clients.remove(r);
7495 r.conProviders.remove(localCpr);
7496 }
7497 updateOomAdjLocked();
7498 }
7499 }
7500
7501 private void removeContentProviderExternal(String name) {
7502 synchronized (this) {
7503 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7504 if(cpr == null) {
7505 //remove from mProvidersByClass
7506 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7507 return;
7508 }
7509
7510 //update content provider record entry info
7511 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7512 localCpr.externals--;
7513 if (localCpr.externals < 0) {
7514 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7515 }
7516 updateOomAdjLocked();
7517 }
7518 }
7519
7520 public final void publishContentProviders(IApplicationThread caller,
7521 List<ContentProviderHolder> providers) {
7522 if (providers == null) {
7523 return;
7524 }
7525
7526 synchronized(this) {
7527 final ProcessRecord r = getRecordForAppLocked(caller);
7528 if (r == null) {
7529 throw new SecurityException(
7530 "Unable to find app for caller " + caller
7531 + " (pid=" + Binder.getCallingPid()
7532 + ") when publishing content providers");
7533 }
7534
7535 final long origId = Binder.clearCallingIdentity();
7536
7537 final int N = providers.size();
7538 for (int i=0; i<N; i++) {
7539 ContentProviderHolder src = providers.get(i);
7540 if (src == null || src.info == null || src.provider == null) {
7541 continue;
7542 }
7543 ContentProviderRecord dst =
7544 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7545 if (dst != null) {
7546 mProvidersByClass.put(dst.info.name, dst);
7547 String names[] = dst.info.authority.split(";");
7548 for (int j = 0; j < names.length; j++) {
7549 mProvidersByName.put(names[j], dst);
7550 }
7551
7552 int NL = mLaunchingProviders.size();
7553 int j;
7554 for (j=0; j<NL; j++) {
7555 if (mLaunchingProviders.get(j) == dst) {
7556 mLaunchingProviders.remove(j);
7557 j--;
7558 NL--;
7559 }
7560 }
7561 synchronized (dst) {
7562 dst.provider = src.provider;
7563 dst.app = r;
7564 dst.notifyAll();
7565 }
7566 updateOomAdjLocked(r);
7567 }
7568 }
7569
7570 Binder.restoreCallingIdentity(origId);
7571 }
7572 }
7573
7574 public static final void installSystemProviders() {
7575 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7576 List providers = mSelf.generateApplicationProvidersLocked(app);
7577 mSystemThread.installSystemProviders(providers);
7578 }
7579
7580 // =========================================================
7581 // GLOBAL MANAGEMENT
7582 // =========================================================
7583
7584 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7585 ApplicationInfo info, String customProcess) {
7586 String proc = customProcess != null ? customProcess : info.processName;
7587 BatteryStatsImpl.Uid.Proc ps = null;
7588 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7589 synchronized (stats) {
7590 ps = stats.getProcessStatsLocked(info.uid, proc);
7591 }
7592 return new ProcessRecord(ps, thread, info, proc);
7593 }
7594
7595 final ProcessRecord addAppLocked(ApplicationInfo info) {
7596 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7597
7598 if (app == null) {
7599 app = newProcessRecordLocked(null, info, null);
7600 mProcessNames.put(info.processName, info.uid, app);
7601 updateLRUListLocked(app, true);
7602 }
7603
7604 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7605 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7606 app.persistent = true;
7607 app.maxAdj = CORE_SERVER_ADJ;
7608 }
7609 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7610 mPersistentStartingProcesses.add(app);
7611 startProcessLocked(app, "added application", app.processName);
7612 }
7613
7614 return app;
7615 }
7616
7617 public void unhandledBack() {
7618 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7619 "unhandledBack()");
7620
7621 synchronized(this) {
7622 int count = mHistory.size();
7623 if (Config.LOGD) Log.d(
7624 TAG, "Performing unhandledBack(): stack size = " + count);
7625 if (count > 1) {
7626 final long origId = Binder.clearCallingIdentity();
7627 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7628 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7629 Binder.restoreCallingIdentity(origId);
7630 }
7631 }
7632 }
7633
7634 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7635 String name = uri.getAuthority();
7636 ContentProviderHolder cph = getContentProviderExternal(name);
7637 ParcelFileDescriptor pfd = null;
7638 if (cph != null) {
7639 // We record the binder invoker's uid in thread-local storage before
7640 // going to the content provider to open the file. Later, in the code
7641 // that handles all permissions checks, we look for this uid and use
7642 // that rather than the Activity Manager's own uid. The effect is that
7643 // we do the check against the caller's permissions even though it looks
7644 // to the content provider like the Activity Manager itself is making
7645 // the request.
7646 sCallerIdentity.set(new Identity(
7647 Binder.getCallingPid(), Binder.getCallingUid()));
7648 try {
7649 pfd = cph.provider.openFile(uri, "r");
7650 } catch (FileNotFoundException e) {
7651 // do nothing; pfd will be returned null
7652 } finally {
7653 // Ensure that whatever happens, we clean up the identity state
7654 sCallerIdentity.remove();
7655 }
7656
7657 // We've got the fd now, so we're done with the provider.
7658 removeContentProviderExternal(name);
7659 } else {
7660 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7661 }
7662 return pfd;
7663 }
7664
7665 public void goingToSleep() {
7666 synchronized(this) {
7667 mSleeping = true;
7668 mWindowManager.setEventDispatching(false);
7669
7670 if (mResumedActivity != null) {
7671 pauseIfSleepingLocked();
7672 } else {
7673 Log.w(TAG, "goingToSleep with no resumed activity!");
7674 }
7675 }
7676 }
7677
Dianne Hackborn55280a92009-05-07 15:53:46 -07007678 public boolean shutdown(int timeout) {
7679 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7680 != PackageManager.PERMISSION_GRANTED) {
7681 throw new SecurityException("Requires permission "
7682 + android.Manifest.permission.SHUTDOWN);
7683 }
7684
7685 boolean timedout = false;
7686
7687 synchronized(this) {
7688 mShuttingDown = true;
7689 mWindowManager.setEventDispatching(false);
7690
7691 if (mResumedActivity != null) {
7692 pauseIfSleepingLocked();
7693 final long endTime = System.currentTimeMillis() + timeout;
7694 while (mResumedActivity != null || mPausingActivity != null) {
7695 long delay = endTime - System.currentTimeMillis();
7696 if (delay <= 0) {
7697 Log.w(TAG, "Activity manager shutdown timed out");
7698 timedout = true;
7699 break;
7700 }
7701 try {
7702 this.wait();
7703 } catch (InterruptedException e) {
7704 }
7705 }
7706 }
7707 }
7708
7709 mUsageStatsService.shutdown();
7710 mBatteryStatsService.shutdown();
7711
7712 return timedout;
7713 }
7714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007715 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007716 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717 if (!mGoingToSleep.isHeld()) {
7718 mGoingToSleep.acquire();
7719 if (mLaunchingActivity.isHeld()) {
7720 mLaunchingActivity.release();
7721 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7722 }
7723 }
7724
7725 // If we are not currently pausing an activity, get the current
7726 // one to pause. If we are pausing one, we will just let that stuff
7727 // run and release the wake lock when all done.
7728 if (mPausingActivity == null) {
7729 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7730 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7731 startPausingLocked(false, true);
7732 }
7733 }
7734 }
7735
7736 public void wakingUp() {
7737 synchronized(this) {
7738 if (mGoingToSleep.isHeld()) {
7739 mGoingToSleep.release();
7740 }
7741 mWindowManager.setEventDispatching(true);
7742 mSleeping = false;
7743 resumeTopActivityLocked(null);
7744 }
7745 }
7746
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007747 public void stopAppSwitches() {
7748 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7749 != PackageManager.PERMISSION_GRANTED) {
7750 throw new SecurityException("Requires permission "
7751 + android.Manifest.permission.STOP_APP_SWITCHES);
7752 }
7753
7754 synchronized(this) {
7755 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7756 + APP_SWITCH_DELAY_TIME;
7757 mDidAppSwitch = false;
7758 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7759 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7760 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7761 }
7762 }
7763
7764 public void resumeAppSwitches() {
7765 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7766 != PackageManager.PERMISSION_GRANTED) {
7767 throw new SecurityException("Requires permission "
7768 + android.Manifest.permission.STOP_APP_SWITCHES);
7769 }
7770
7771 synchronized(this) {
7772 // Note that we don't execute any pending app switches... we will
7773 // let those wait until either the timeout, or the next start
7774 // activity request.
7775 mAppSwitchesAllowedTime = 0;
7776 }
7777 }
7778
7779 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7780 String name) {
7781 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7782 return true;
7783 }
7784
7785 final int perm = checkComponentPermission(
7786 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7787 callingUid, -1);
7788 if (perm == PackageManager.PERMISSION_GRANTED) {
7789 return true;
7790 }
7791
7792 Log.w(TAG, name + " request from " + callingUid + " stopped");
7793 return false;
7794 }
7795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007796 public void setDebugApp(String packageName, boolean waitForDebugger,
7797 boolean persistent) {
7798 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7799 "setDebugApp()");
7800
7801 // Note that this is not really thread safe if there are multiple
7802 // callers into it at the same time, but that's not a situation we
7803 // care about.
7804 if (persistent) {
7805 final ContentResolver resolver = mContext.getContentResolver();
7806 Settings.System.putString(
7807 resolver, Settings.System.DEBUG_APP,
7808 packageName);
7809 Settings.System.putInt(
7810 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7811 waitForDebugger ? 1 : 0);
7812 }
7813
7814 synchronized (this) {
7815 if (!persistent) {
7816 mOrigDebugApp = mDebugApp;
7817 mOrigWaitForDebugger = mWaitForDebugger;
7818 }
7819 mDebugApp = packageName;
7820 mWaitForDebugger = waitForDebugger;
7821 mDebugTransient = !persistent;
7822 if (packageName != null) {
7823 final long origId = Binder.clearCallingIdentity();
7824 uninstallPackageLocked(packageName, -1, false);
7825 Binder.restoreCallingIdentity(origId);
7826 }
7827 }
7828 }
7829
7830 public void setAlwaysFinish(boolean enabled) {
7831 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7832 "setAlwaysFinish()");
7833
7834 Settings.System.putInt(
7835 mContext.getContentResolver(),
7836 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7837
7838 synchronized (this) {
7839 mAlwaysFinishActivities = enabled;
7840 }
7841 }
7842
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007843 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007844 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007845 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007846 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007847 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007848 }
7849 }
7850
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007851 public void registerActivityWatcher(IActivityWatcher watcher) {
7852 mWatchers.register(watcher);
7853 }
7854
7855 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7856 mWatchers.unregister(watcher);
7857 }
7858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007859 public final void enterSafeMode() {
7860 synchronized(this) {
7861 // It only makes sense to do this before the system is ready
7862 // and started launching other packages.
7863 if (!mSystemReady) {
7864 try {
7865 ActivityThread.getPackageManager().enterSafeMode();
7866 } catch (RemoteException e) {
7867 }
7868
7869 View v = LayoutInflater.from(mContext).inflate(
7870 com.android.internal.R.layout.safe_mode, null);
7871 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7872 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7873 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7874 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7875 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7876 lp.format = v.getBackground().getOpacity();
7877 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7878 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7879 ((WindowManager)mContext.getSystemService(
7880 Context.WINDOW_SERVICE)).addView(v, lp);
7881 }
7882 }
7883 }
7884
7885 public void noteWakeupAlarm(IIntentSender sender) {
7886 if (!(sender instanceof PendingIntentRecord)) {
7887 return;
7888 }
7889 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7890 synchronized (stats) {
7891 if (mBatteryStatsService.isOnBattery()) {
7892 mBatteryStatsService.enforceCallingPermission();
7893 PendingIntentRecord rec = (PendingIntentRecord)sender;
7894 int MY_UID = Binder.getCallingUid();
7895 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7896 BatteryStatsImpl.Uid.Pkg pkg =
7897 stats.getPackageStatsLocked(uid, rec.key.packageName);
7898 pkg.incWakeupsLocked();
7899 }
7900 }
7901 }
7902
7903 public boolean killPidsForMemory(int[] pids) {
7904 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7905 throw new SecurityException("killPidsForMemory only available to the system");
7906 }
7907
7908 // XXX Note: don't acquire main activity lock here, because the window
7909 // manager calls in with its locks held.
7910
7911 boolean killed = false;
7912 synchronized (mPidsSelfLocked) {
7913 int[] types = new int[pids.length];
7914 int worstType = 0;
7915 for (int i=0; i<pids.length; i++) {
7916 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7917 if (proc != null) {
7918 int type = proc.setAdj;
7919 types[i] = type;
7920 if (type > worstType) {
7921 worstType = type;
7922 }
7923 }
7924 }
7925
7926 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7927 // then constrain it so we will kill all hidden procs.
7928 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7929 worstType = HIDDEN_APP_MIN_ADJ;
7930 }
7931 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7932 for (int i=0; i<pids.length; i++) {
7933 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7934 if (proc == null) {
7935 continue;
7936 }
7937 int adj = proc.setAdj;
7938 if (adj >= worstType) {
7939 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7940 + adj + ")");
7941 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7942 proc.processName, adj);
7943 killed = true;
7944 Process.killProcess(pids[i]);
7945 }
7946 }
7947 }
7948 return killed;
7949 }
7950
7951 public void reportPss(IApplicationThread caller, int pss) {
7952 Watchdog.PssRequestor req;
7953 String name;
7954 ProcessRecord callerApp;
7955 synchronized (this) {
7956 if (caller == null) {
7957 return;
7958 }
7959 callerApp = getRecordForAppLocked(caller);
7960 if (callerApp == null) {
7961 return;
7962 }
7963 callerApp.lastPss = pss;
7964 req = callerApp;
7965 name = callerApp.processName;
7966 }
7967 Watchdog.getInstance().reportPss(req, name, pss);
7968 if (!callerApp.persistent) {
7969 removeRequestedPss(callerApp);
7970 }
7971 }
7972
7973 public void requestPss(Runnable completeCallback) {
7974 ArrayList<ProcessRecord> procs;
7975 synchronized (this) {
7976 mRequestPssCallback = completeCallback;
7977 mRequestPssList.clear();
7978 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7979 ProcessRecord proc = mLRUProcesses.get(i);
7980 if (!proc.persistent) {
7981 mRequestPssList.add(proc);
7982 }
7983 }
7984 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7985 }
7986
7987 int oldPri = Process.getThreadPriority(Process.myTid());
7988 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7989 for (int i=procs.size()-1; i>=0; i--) {
7990 ProcessRecord proc = procs.get(i);
7991 proc.lastPss = 0;
7992 proc.requestPss();
7993 }
7994 Process.setThreadPriority(oldPri);
7995 }
7996
7997 void removeRequestedPss(ProcessRecord proc) {
7998 Runnable callback = null;
7999 synchronized (this) {
8000 if (mRequestPssList.remove(proc)) {
8001 if (mRequestPssList.size() == 0) {
8002 callback = mRequestPssCallback;
8003 mRequestPssCallback = null;
8004 }
8005 }
8006 }
8007
8008 if (callback != null) {
8009 callback.run();
8010 }
8011 }
8012
8013 public void collectPss(Watchdog.PssStats stats) {
8014 stats.mEmptyPss = 0;
8015 stats.mEmptyCount = 0;
8016 stats.mBackgroundPss = 0;
8017 stats.mBackgroundCount = 0;
8018 stats.mServicePss = 0;
8019 stats.mServiceCount = 0;
8020 stats.mVisiblePss = 0;
8021 stats.mVisibleCount = 0;
8022 stats.mForegroundPss = 0;
8023 stats.mForegroundCount = 0;
8024 stats.mNoPssCount = 0;
8025 synchronized (this) {
8026 int i;
8027 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8028 ? mProcDeaths.length : stats.mProcDeaths.length;
8029 int aggr = 0;
8030 for (i=0; i<NPD; i++) {
8031 aggr += mProcDeaths[i];
8032 stats.mProcDeaths[i] = aggr;
8033 }
8034 while (i<stats.mProcDeaths.length) {
8035 stats.mProcDeaths[i] = 0;
8036 i++;
8037 }
8038
8039 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8040 ProcessRecord proc = mLRUProcesses.get(i);
8041 if (proc.persistent) {
8042 continue;
8043 }
8044 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8045 if (proc.lastPss == 0) {
8046 stats.mNoPssCount++;
8047 continue;
8048 }
8049 if (proc.setAdj == EMPTY_APP_ADJ) {
8050 stats.mEmptyPss += proc.lastPss;
8051 stats.mEmptyCount++;
8052 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8053 stats.mEmptyPss += proc.lastPss;
8054 stats.mEmptyCount++;
8055 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8056 stats.mBackgroundPss += proc.lastPss;
8057 stats.mBackgroundCount++;
8058 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8059 stats.mVisiblePss += proc.lastPss;
8060 stats.mVisibleCount++;
8061 } else {
8062 stats.mForegroundPss += proc.lastPss;
8063 stats.mForegroundCount++;
8064 }
8065 }
8066 }
8067 }
8068
8069 public final void startRunning(String pkg, String cls, String action,
8070 String data) {
8071 synchronized(this) {
8072 if (mStartRunning) {
8073 return;
8074 }
8075 mStartRunning = true;
8076 mTopComponent = pkg != null && cls != null
8077 ? new ComponentName(pkg, cls) : null;
8078 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8079 mTopData = data;
8080 if (!mSystemReady) {
8081 return;
8082 }
8083 }
8084
8085 systemReady();
8086 }
8087
8088 private void retrieveSettings() {
8089 final ContentResolver resolver = mContext.getContentResolver();
8090 String debugApp = Settings.System.getString(
8091 resolver, Settings.System.DEBUG_APP);
8092 boolean waitForDebugger = Settings.System.getInt(
8093 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8094 boolean alwaysFinishActivities = Settings.System.getInt(
8095 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8096
8097 Configuration configuration = new Configuration();
8098 Settings.System.getConfiguration(resolver, configuration);
8099
8100 synchronized (this) {
8101 mDebugApp = mOrigDebugApp = debugApp;
8102 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8103 mAlwaysFinishActivities = alwaysFinishActivities;
8104 // This happens before any activities are started, so we can
8105 // change mConfiguration in-place.
8106 mConfiguration.updateFrom(configuration);
8107 }
8108 }
8109
8110 public boolean testIsSystemReady() {
8111 // no need to synchronize(this) just to read & return the value
8112 return mSystemReady;
8113 }
8114
8115 public void systemReady() {
8116 // In the simulator, startRunning will never have been called, which
8117 // normally sets a few crucial variables. Do it here instead.
8118 if (!Process.supportsProcesses()) {
8119 mStartRunning = true;
8120 mTopAction = Intent.ACTION_MAIN;
8121 }
8122
8123 synchronized(this) {
8124 if (mSystemReady) {
8125 return;
8126 }
8127 mSystemReady = true;
8128 if (!mStartRunning) {
8129 return;
8130 }
8131 }
8132
8133 if (Config.LOGD) Log.d(TAG, "Start running!");
8134 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8135 SystemClock.uptimeMillis());
8136
8137 synchronized(this) {
8138 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8139 ResolveInfo ri = mContext.getPackageManager()
8140 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008141 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008142 CharSequence errorMsg = null;
8143 if (ri != null) {
8144 ActivityInfo ai = ri.activityInfo;
8145 ApplicationInfo app = ai.applicationInfo;
8146 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8147 mTopAction = Intent.ACTION_FACTORY_TEST;
8148 mTopData = null;
8149 mTopComponent = new ComponentName(app.packageName,
8150 ai.name);
8151 } else {
8152 errorMsg = mContext.getResources().getText(
8153 com.android.internal.R.string.factorytest_not_system);
8154 }
8155 } else {
8156 errorMsg = mContext.getResources().getText(
8157 com.android.internal.R.string.factorytest_no_action);
8158 }
8159 if (errorMsg != null) {
8160 mTopAction = null;
8161 mTopData = null;
8162 mTopComponent = null;
8163 Message msg = Message.obtain();
8164 msg.what = SHOW_FACTORY_ERROR_MSG;
8165 msg.getData().putCharSequence("msg", errorMsg);
8166 mHandler.sendMessage(msg);
8167 }
8168 }
8169 }
8170
8171 retrieveSettings();
8172
8173 synchronized (this) {
8174 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8175 try {
8176 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008177 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008178 if (apps != null) {
8179 int N = apps.size();
8180 int i;
8181 for (i=0; i<N; i++) {
8182 ApplicationInfo info
8183 = (ApplicationInfo)apps.get(i);
8184 if (info != null &&
8185 !info.packageName.equals("android")) {
8186 addAppLocked(info);
8187 }
8188 }
8189 }
8190 } catch (RemoteException ex) {
8191 // pm is in same process, this will never happen.
8192 }
8193 }
8194
8195 try {
8196 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8197 Message msg = Message.obtain();
8198 msg.what = SHOW_UID_ERROR_MSG;
8199 mHandler.sendMessage(msg);
8200 }
8201 } catch (RemoteException e) {
8202 }
8203
8204 // Start up initial activity.
8205 mBooting = true;
8206 resumeTopActivityLocked(null);
8207 }
8208 }
8209
8210 boolean makeAppCrashingLocked(ProcessRecord app,
8211 String tag, String shortMsg, String longMsg, byte[] crashData) {
8212 app.crashing = true;
8213 app.crashingReport = generateProcessError(app,
8214 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8215 startAppProblemLocked(app);
8216 app.stopFreezingAllLocked();
8217 return handleAppCrashLocked(app);
8218 }
8219
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008220 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8221 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008222
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008223 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008224 // look for receiver in the installer package
8225 String candidate = pm.getInstallerPackageName(app.info.packageName);
8226 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8227 if (result != null) {
8228 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008229 }
8230
Jacek Surazski82a73df2009-06-17 14:33:18 +02008231 // if the error app is on the system image, look for system apps
8232 // error receiver
8233 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8234 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8235 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8236 if (result != null) {
8237 return result;
8238 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008239 }
8240
Jacek Surazski82a73df2009-06-17 14:33:18 +02008241 // if there is a default receiver, try that
8242 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8243 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008244 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008245 // should not happen
8246 Log.e(TAG, "error talking to PackageManager", e);
8247 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008248 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008249 }
8250
8251 /**
8252 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8253 *
8254 * @param pm PackageManager isntance
8255 * @param errorPackage package which caused the error
8256 * @param receiverPackage candidate package to receive the error
8257 * @return activity component within receiverPackage which handles
8258 * ACTION_APP_ERROR, or null if not found
8259 */
8260 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8261 String receiverPackage) throws RemoteException {
8262 if (receiverPackage == null || receiverPackage.length() == 0) {
8263 return null;
8264 }
8265
8266 // break the loop if it's the error report receiver package that crashed
8267 if (receiverPackage.equals(errorPackage)) {
8268 return null;
8269 }
8270
8271 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8272 intent.setPackage(receiverPackage);
8273 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8274 if (info == null || info.activityInfo == null) {
8275 return null;
8276 }
8277 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008278 }
8279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008280 void makeAppNotRespondingLocked(ProcessRecord app,
8281 String tag, String shortMsg, String longMsg, byte[] crashData) {
8282 app.notResponding = true;
8283 app.notRespondingReport = generateProcessError(app,
8284 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8285 crashData);
8286 startAppProblemLocked(app);
8287 app.stopFreezingAllLocked();
8288 }
8289
8290 /**
8291 * Generate a process error record, suitable for attachment to a ProcessRecord.
8292 *
8293 * @param app The ProcessRecord in which the error occurred.
8294 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8295 * ActivityManager.AppErrorStateInfo
8296 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8297 * @param shortMsg Short message describing the crash.
8298 * @param longMsg Long message describing the crash.
8299 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8300 *
8301 * @return Returns a fully-formed AppErrorStateInfo record.
8302 */
8303 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8304 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8305 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8306
8307 report.condition = condition;
8308 report.processName = app.processName;
8309 report.pid = app.pid;
8310 report.uid = app.info.uid;
8311 report.tag = tag;
8312 report.shortMsg = shortMsg;
8313 report.longMsg = longMsg;
8314 report.crashData = crashData;
8315
8316 return report;
8317 }
8318
8319 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8320 boolean crashed) {
8321 synchronized (this) {
8322 app.crashing = false;
8323 app.crashingReport = null;
8324 app.notResponding = false;
8325 app.notRespondingReport = null;
8326 if (app.anrDialog == fromDialog) {
8327 app.anrDialog = null;
8328 }
8329 if (app.waitDialog == fromDialog) {
8330 app.waitDialog = null;
8331 }
8332 if (app.pid > 0 && app.pid != MY_PID) {
8333 if (crashed) {
8334 handleAppCrashLocked(app);
8335 }
8336 Log.i(ActivityManagerService.TAG, "Killing process "
8337 + app.processName
8338 + " (pid=" + app.pid + ") at user's request");
8339 Process.killProcess(app.pid);
8340 }
8341
8342 }
8343 }
8344
8345 boolean handleAppCrashLocked(ProcessRecord app) {
8346 long now = SystemClock.uptimeMillis();
8347
8348 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8349 app.info.uid);
8350 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8351 // This process loses!
8352 Log.w(TAG, "Process " + app.info.processName
8353 + " has crashed too many times: killing!");
8354 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8355 app.info.processName, app.info.uid);
8356 killServicesLocked(app, false);
8357 for (int i=mHistory.size()-1; i>=0; i--) {
8358 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8359 if (r.app == app) {
8360 if (Config.LOGD) Log.d(
8361 TAG, " Force finishing activity "
8362 + r.intent.getComponent().flattenToShortString());
8363 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8364 }
8365 }
8366 if (!app.persistent) {
8367 // We don't want to start this process again until the user
8368 // explicitly does so... but for persistent process, we really
8369 // need to keep it running. If a persistent process is actually
8370 // repeatedly crashing, then badness for everyone.
8371 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8372 app.info.processName);
8373 mBadProcesses.put(app.info.processName, app.info.uid, now);
8374 app.bad = true;
8375 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8376 app.removed = true;
8377 removeProcessLocked(app, false);
8378 return false;
8379 }
8380 }
8381
8382 // Bump up the crash count of any services currently running in the proc.
8383 if (app.services.size() != 0) {
8384 // Any services running in the application need to be placed
8385 // back in the pending list.
8386 Iterator it = app.services.iterator();
8387 while (it.hasNext()) {
8388 ServiceRecord sr = (ServiceRecord)it.next();
8389 sr.crashCount++;
8390 }
8391 }
8392
8393 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8394 return true;
8395 }
8396
8397 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008398 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008399 skipCurrentReceiverLocked(app);
8400 }
8401
8402 void skipCurrentReceiverLocked(ProcessRecord app) {
8403 boolean reschedule = false;
8404 BroadcastRecord r = app.curReceiver;
8405 if (r != null) {
8406 // The current broadcast is waiting for this app's receiver
8407 // to be finished. Looks like that's not going to happen, so
8408 // let the broadcast continue.
8409 logBroadcastReceiverDiscard(r);
8410 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8411 r.resultExtras, r.resultAbort, true);
8412 reschedule = true;
8413 }
8414 r = mPendingBroadcast;
8415 if (r != null && r.curApp == app) {
8416 if (DEBUG_BROADCAST) Log.v(TAG,
8417 "skip & discard pending app " + r);
8418 logBroadcastReceiverDiscard(r);
8419 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8420 r.resultExtras, r.resultAbort, true);
8421 reschedule = true;
8422 }
8423 if (reschedule) {
8424 scheduleBroadcastsLocked();
8425 }
8426 }
8427
8428 public int handleApplicationError(IBinder app, int flags,
8429 String tag, String shortMsg, String longMsg, byte[] crashData) {
8430 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008431 ProcessRecord r = null;
8432 synchronized (this) {
8433 if (app != null) {
8434 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8435 final int NA = apps.size();
8436 for (int ia=0; ia<NA; ia++) {
8437 ProcessRecord p = apps.valueAt(ia);
8438 if (p.thread != null && p.thread.asBinder() == app) {
8439 r = p;
8440 break;
8441 }
8442 }
8443 }
8444 }
8445
8446 if (r != null) {
8447 // The application has crashed. Send the SIGQUIT to the process so
8448 // that it can dump its state.
8449 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8450 //Log.i(TAG, "Current system threads:");
8451 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8452 }
8453
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008454 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008455 try {
8456 String name = r != null ? r.processName : null;
8457 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008458 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008459 shortMsg, longMsg, crashData)) {
8460 Log.w(TAG, "Force-killing crashed app " + name
8461 + " at watcher's request");
8462 Process.killProcess(pid);
8463 return 0;
8464 }
8465 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008466 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008467 }
8468 }
8469
8470 final long origId = Binder.clearCallingIdentity();
8471
8472 // If this process is running instrumentation, finish it.
8473 if (r != null && r.instrumentationClass != null) {
8474 Log.w(TAG, "Error in app " + r.processName
8475 + " running instrumentation " + r.instrumentationClass + ":");
8476 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8477 if (longMsg != null) Log.w(TAG, " " + longMsg);
8478 Bundle info = new Bundle();
8479 info.putString("shortMsg", shortMsg);
8480 info.putString("longMsg", longMsg);
8481 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8482 Binder.restoreCallingIdentity(origId);
8483 return 0;
8484 }
8485
8486 if (r != null) {
8487 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8488 return 0;
8489 }
8490 } else {
8491 Log.w(TAG, "Some application object " + app + " tag " + tag
8492 + " has crashed, but I don't know who it is.");
8493 Log.w(TAG, "ShortMsg:" + shortMsg);
8494 Log.w(TAG, "LongMsg:" + longMsg);
8495 Binder.restoreCallingIdentity(origId);
8496 return 0;
8497 }
8498
8499 Message msg = Message.obtain();
8500 msg.what = SHOW_ERROR_MSG;
8501 HashMap data = new HashMap();
8502 data.put("result", result);
8503 data.put("app", r);
8504 data.put("flags", flags);
8505 data.put("shortMsg", shortMsg);
8506 data.put("longMsg", longMsg);
8507 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8508 // For system processes, submit crash data to the server.
8509 data.put("crashData", crashData);
8510 }
8511 msg.obj = data;
8512 mHandler.sendMessage(msg);
8513
8514 Binder.restoreCallingIdentity(origId);
8515 }
8516
8517 int res = result.get();
8518
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008519 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 synchronized (this) {
8521 if (r != null) {
8522 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8523 SystemClock.uptimeMillis());
8524 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008525 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8526 appErrorIntent = createAppErrorIntentLocked(r);
8527 res = AppErrorDialog.FORCE_QUIT;
8528 }
8529 }
8530
8531 if (appErrorIntent != null) {
8532 try {
8533 mContext.startActivity(appErrorIntent);
8534 } catch (ActivityNotFoundException e) {
8535 Log.w(TAG, "bug report receiver dissappeared", e);
8536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008537 }
8538
8539 return res;
8540 }
8541
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008542 Intent createAppErrorIntentLocked(ProcessRecord r) {
8543 ApplicationErrorReport report = createAppErrorReportLocked(r);
8544 if (report == null) {
8545 return null;
8546 }
8547 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8548 result.setComponent(r.errorReportReceiver);
8549 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8550 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8551 return result;
8552 }
8553
8554 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8555 if (r.errorReportReceiver == null) {
8556 return null;
8557 }
8558
8559 if (!r.crashing && !r.notResponding) {
8560 return null;
8561 }
8562
8563 try {
8564 ApplicationErrorReport report = new ApplicationErrorReport();
8565 report.packageName = r.info.packageName;
8566 report.installerPackageName = r.errorReportReceiver.getPackageName();
8567 report.processName = r.processName;
8568
8569 if (r.crashing) {
8570 report.type = ApplicationErrorReport.TYPE_CRASH;
8571 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8572
8573 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8574 r.crashingReport.crashData);
8575 DataInputStream dataStream = new DataInputStream(byteStream);
8576 CrashData crashData = new CrashData(dataStream);
8577 ThrowableData throwData = crashData.getThrowableData();
8578
8579 report.time = crashData.getTime();
8580 report.crashInfo.stackTrace = throwData.toString();
8581
Jacek Surazskif829a782009-06-11 22:47:02 +02008582 // Extract the source of the exception, useful for report
8583 // clustering. Also extract the "deepest" non-null exception
8584 // message.
8585 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008586 while (throwData.getCause() != null) {
8587 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008588 String msg = throwData.getMessage();
8589 if (msg != null && msg.length() > 0) {
8590 exceptionMessage = msg;
8591 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008592 }
8593 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008594 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008595 report.crashInfo.exceptionClassName = throwData.getType();
8596 report.crashInfo.throwFileName = trace.getFileName();
8597 report.crashInfo.throwClassName = trace.getClassName();
8598 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008599 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008600 } else if (r.notResponding) {
8601 report.type = ApplicationErrorReport.TYPE_ANR;
8602 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8603
8604 report.anrInfo.activity = r.notRespondingReport.tag;
8605 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8606 report.anrInfo.info = r.notRespondingReport.longMsg;
8607 }
8608
8609 return report;
8610 } catch (IOException e) {
8611 // we don't send it
8612 }
8613
8614 return null;
8615 }
8616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8618 // assume our apps are happy - lazy create the list
8619 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8620
8621 synchronized (this) {
8622
8623 // iterate across all processes
8624 final int N = mLRUProcesses.size();
8625 for (int i = 0; i < N; i++) {
8626 ProcessRecord app = mLRUProcesses.get(i);
8627 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8628 // This one's in trouble, so we'll generate a report for it
8629 // crashes are higher priority (in case there's a crash *and* an anr)
8630 ActivityManager.ProcessErrorStateInfo report = null;
8631 if (app.crashing) {
8632 report = app.crashingReport;
8633 } else if (app.notResponding) {
8634 report = app.notRespondingReport;
8635 }
8636
8637 if (report != null) {
8638 if (errList == null) {
8639 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8640 }
8641 errList.add(report);
8642 } else {
8643 Log.w(TAG, "Missing app error report, app = " + app.processName +
8644 " crashing = " + app.crashing +
8645 " notResponding = " + app.notResponding);
8646 }
8647 }
8648 }
8649 }
8650
8651 return errList;
8652 }
8653
8654 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8655 // Lazy instantiation of list
8656 List<ActivityManager.RunningAppProcessInfo> runList = null;
8657 synchronized (this) {
8658 // Iterate across all processes
8659 final int N = mLRUProcesses.size();
8660 for (int i = 0; i < N; i++) {
8661 ProcessRecord app = mLRUProcesses.get(i);
8662 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8663 // Generate process state info for running application
8664 ActivityManager.RunningAppProcessInfo currApp =
8665 new ActivityManager.RunningAppProcessInfo(app.processName,
8666 app.pid, app.getPackageList());
8667 int adj = app.curAdj;
8668 if (adj >= CONTENT_PROVIDER_ADJ) {
8669 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8670 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8671 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008672 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8673 } else if (adj >= HOME_APP_ADJ) {
8674 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8675 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008676 } else if (adj >= SECONDARY_SERVER_ADJ) {
8677 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8678 } else if (adj >= VISIBLE_APP_ADJ) {
8679 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8680 } else {
8681 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8682 }
8683 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8684 // + " lru=" + currApp.lru);
8685 if (runList == null) {
8686 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8687 }
8688 runList.add(currApp);
8689 }
8690 }
8691 }
8692 return runList;
8693 }
8694
8695 @Override
8696 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8697 synchronized (this) {
8698 if (checkCallingPermission(android.Manifest.permission.DUMP)
8699 != PackageManager.PERMISSION_GRANTED) {
8700 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8701 + Binder.getCallingPid()
8702 + ", uid=" + Binder.getCallingUid()
8703 + " without permission "
8704 + android.Manifest.permission.DUMP);
8705 return;
8706 }
8707 if (args.length != 0 && "service".equals(args[0])) {
8708 dumpService(fd, pw, args);
8709 return;
8710 }
8711 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008712 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008713 pw.println(" ");
8714 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008715 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008716 if (mWaitingVisibleActivities.size() > 0) {
8717 pw.println(" ");
8718 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008719 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008720 }
8721 if (mStoppingActivities.size() > 0) {
8722 pw.println(" ");
8723 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008724 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008725 }
8726 if (mFinishingActivities.size() > 0) {
8727 pw.println(" ");
8728 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008729 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008730 }
8731
8732 pw.println(" ");
8733 pw.println(" mPausingActivity: " + mPausingActivity);
8734 pw.println(" mResumedActivity: " + mResumedActivity);
8735 pw.println(" mFocusedActivity: " + mFocusedActivity);
8736 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8737
8738 if (mRecentTasks.size() > 0) {
8739 pw.println(" ");
8740 pw.println("Recent tasks in Current Activity Manager State:");
8741
8742 final int N = mRecentTasks.size();
8743 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008744 TaskRecord tr = mRecentTasks.get(i);
8745 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8746 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008747 mRecentTasks.get(i).dump(pw, " ");
8748 }
8749 }
8750
8751 pw.println(" ");
8752 pw.println(" mCurTask: " + mCurTask);
8753
8754 pw.println(" ");
8755 pw.println("Processes in Current Activity Manager State:");
8756
8757 boolean needSep = false;
8758 int numPers = 0;
8759
8760 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8761 final int NA = procs.size();
8762 for (int ia=0; ia<NA; ia++) {
8763 if (!needSep) {
8764 pw.println(" All known processes:");
8765 needSep = true;
8766 }
8767 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008768 pw.print(r.persistent ? " *PERS*" : " *APP*");
8769 pw.print(" UID "); pw.print(procs.keyAt(ia));
8770 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008771 r.dump(pw, " ");
8772 if (r.persistent) {
8773 numPers++;
8774 }
8775 }
8776 }
8777
8778 if (mLRUProcesses.size() > 0) {
8779 if (needSep) pw.println(" ");
8780 needSep = true;
8781 pw.println(" Running processes (most recent first):");
8782 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008783 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008784 needSep = true;
8785 }
8786
8787 synchronized (mPidsSelfLocked) {
8788 if (mPidsSelfLocked.size() > 0) {
8789 if (needSep) pw.println(" ");
8790 needSep = true;
8791 pw.println(" PID mappings:");
8792 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008793 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8794 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008795 }
8796 }
8797 }
8798
8799 if (mForegroundProcesses.size() > 0) {
8800 if (needSep) pw.println(" ");
8801 needSep = true;
8802 pw.println(" Foreground Processes:");
8803 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008804 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8805 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008806 }
8807 }
8808
8809 if (mPersistentStartingProcesses.size() > 0) {
8810 if (needSep) pw.println(" ");
8811 needSep = true;
8812 pw.println(" Persisent processes that are starting:");
8813 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008814 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008815 }
8816
8817 if (mStartingProcesses.size() > 0) {
8818 if (needSep) pw.println(" ");
8819 needSep = true;
8820 pw.println(" Processes that are starting:");
8821 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008822 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008823 }
8824
8825 if (mRemovedProcesses.size() > 0) {
8826 if (needSep) pw.println(" ");
8827 needSep = true;
8828 pw.println(" Processes that are being removed:");
8829 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008830 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008831 }
8832
8833 if (mProcessesOnHold.size() > 0) {
8834 if (needSep) pw.println(" ");
8835 needSep = true;
8836 pw.println(" Processes that are on old until the system is ready:");
8837 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008838 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008839 }
8840
8841 if (mProcessCrashTimes.getMap().size() > 0) {
8842 if (needSep) pw.println(" ");
8843 needSep = true;
8844 pw.println(" Time since processes crashed:");
8845 long now = SystemClock.uptimeMillis();
8846 for (Map.Entry<String, SparseArray<Long>> procs
8847 : mProcessCrashTimes.getMap().entrySet()) {
8848 SparseArray<Long> uids = procs.getValue();
8849 final int N = uids.size();
8850 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008851 pw.print(" Process "); pw.print(procs.getKey());
8852 pw.print(" uid "); pw.print(uids.keyAt(i));
8853 pw.print(": last crashed ");
8854 pw.print((now-uids.valueAt(i)));
8855 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008856 }
8857 }
8858 }
8859
8860 if (mBadProcesses.getMap().size() > 0) {
8861 if (needSep) pw.println(" ");
8862 needSep = true;
8863 pw.println(" Bad processes:");
8864 for (Map.Entry<String, SparseArray<Long>> procs
8865 : mBadProcesses.getMap().entrySet()) {
8866 SparseArray<Long> uids = procs.getValue();
8867 final int N = uids.size();
8868 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008869 pw.print(" Bad process "); pw.print(procs.getKey());
8870 pw.print(" uid "); pw.print(uids.keyAt(i));
8871 pw.print(": crashed at time ");
8872 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008873 }
8874 }
8875 }
8876
8877 pw.println(" ");
8878 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008879 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008880 pw.println(" mConfiguration: " + mConfiguration);
8881 pw.println(" mStartRunning=" + mStartRunning
8882 + " mSystemReady=" + mSystemReady
8883 + " mBooting=" + mBooting
8884 + " mBooted=" + mBooted
8885 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008886 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008887 pw.println(" mGoingToSleep=" + mGoingToSleep);
8888 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8889 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8890 + " mDebugTransient=" + mDebugTransient
8891 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8892 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008893 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008894 }
8895 }
8896
8897 /**
8898 * There are three ways to call this:
8899 * - no service specified: dump all the services
8900 * - a flattened component name that matched an existing service was specified as the
8901 * first arg: dump that one service
8902 * - the first arg isn't the flattened component name of an existing service:
8903 * dump all services whose component contains the first arg as a substring
8904 */
8905 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8906 String[] newArgs;
8907 String componentNameString;
8908 ServiceRecord r;
8909 if (args.length == 1) {
8910 componentNameString = null;
8911 newArgs = EMPTY_STRING_ARRAY;
8912 r = null;
8913 } else {
8914 componentNameString = args[1];
8915 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8916 r = componentName != null ? mServices.get(componentName) : null;
8917 newArgs = new String[args.length - 2];
8918 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8919 }
8920
8921 if (r != null) {
8922 dumpService(fd, pw, r, newArgs);
8923 } else {
8924 for (ServiceRecord r1 : mServices.values()) {
8925 if (componentNameString == null
8926 || r1.name.flattenToString().contains(componentNameString)) {
8927 dumpService(fd, pw, r1, newArgs);
8928 }
8929 }
8930 }
8931 }
8932
8933 /**
8934 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8935 * there is a thread associated with the service.
8936 */
8937 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8938 pw.println(" Service " + r.name.flattenToString());
8939 if (r.app != null && r.app.thread != null) {
8940 try {
8941 // flush anything that is already in the PrintWriter since the thread is going
8942 // to write to the file descriptor directly
8943 pw.flush();
8944 r.app.thread.dumpService(fd, r, args);
8945 pw.print("\n");
8946 } catch (RemoteException e) {
8947 pw.println("got a RemoteException while dumping the service");
8948 }
8949 }
8950 }
8951
8952 void dumpBroadcasts(PrintWriter pw) {
8953 synchronized (this) {
8954 if (checkCallingPermission(android.Manifest.permission.DUMP)
8955 != PackageManager.PERMISSION_GRANTED) {
8956 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8957 + Binder.getCallingPid()
8958 + ", uid=" + Binder.getCallingUid()
8959 + " without permission "
8960 + android.Manifest.permission.DUMP);
8961 return;
8962 }
8963 pw.println("Broadcasts in Current Activity Manager State:");
8964
8965 if (mRegisteredReceivers.size() > 0) {
8966 pw.println(" ");
8967 pw.println(" Registered Receivers:");
8968 Iterator it = mRegisteredReceivers.values().iterator();
8969 while (it.hasNext()) {
8970 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008971 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 r.dump(pw, " ");
8973 }
8974 }
8975
8976 pw.println(" ");
8977 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008978 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008979
8980 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8981 || mPendingBroadcast != null) {
8982 if (mParallelBroadcasts.size() > 0) {
8983 pw.println(" ");
8984 pw.println(" Active broadcasts:");
8985 }
8986 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8987 pw.println(" Broadcast #" + i + ":");
8988 mParallelBroadcasts.get(i).dump(pw, " ");
8989 }
8990 if (mOrderedBroadcasts.size() > 0) {
8991 pw.println(" ");
8992 pw.println(" Active serialized broadcasts:");
8993 }
8994 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8995 pw.println(" Serialized Broadcast #" + i + ":");
8996 mOrderedBroadcasts.get(i).dump(pw, " ");
8997 }
8998 pw.println(" ");
8999 pw.println(" Pending broadcast:");
9000 if (mPendingBroadcast != null) {
9001 mPendingBroadcast.dump(pw, " ");
9002 } else {
9003 pw.println(" (null)");
9004 }
9005 }
9006
9007 pw.println(" ");
9008 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9009 if (mStickyBroadcasts != null) {
9010 pw.println(" ");
9011 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009012 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009013 for (Map.Entry<String, ArrayList<Intent>> ent
9014 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009015 pw.print(" * Sticky action "); pw.print(ent.getKey());
9016 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009017 ArrayList<Intent> intents = ent.getValue();
9018 final int N = intents.size();
9019 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009020 sb.setLength(0);
9021 sb.append(" Intent: ");
9022 intents.get(i).toShortString(sb, true, false);
9023 pw.println(sb.toString());
9024 Bundle bundle = intents.get(i).getExtras();
9025 if (bundle != null) {
9026 pw.print(" ");
9027 pw.println(bundle.toString());
9028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009029 }
9030 }
9031 }
9032
9033 pw.println(" ");
9034 pw.println(" mHandler:");
9035 mHandler.dump(new PrintWriterPrinter(pw), " ");
9036 }
9037 }
9038
9039 void dumpServices(PrintWriter pw) {
9040 synchronized (this) {
9041 if (checkCallingPermission(android.Manifest.permission.DUMP)
9042 != PackageManager.PERMISSION_GRANTED) {
9043 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9044 + Binder.getCallingPid()
9045 + ", uid=" + Binder.getCallingUid()
9046 + " without permission "
9047 + android.Manifest.permission.DUMP);
9048 return;
9049 }
9050 pw.println("Services in Current Activity Manager State:");
9051
9052 boolean needSep = false;
9053
9054 if (mServices.size() > 0) {
9055 pw.println(" Active services:");
9056 Iterator<ServiceRecord> it = mServices.values().iterator();
9057 while (it.hasNext()) {
9058 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009059 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009060 r.dump(pw, " ");
9061 }
9062 needSep = true;
9063 }
9064
9065 if (mPendingServices.size() > 0) {
9066 if (needSep) pw.println(" ");
9067 pw.println(" Pending services:");
9068 for (int i=0; i<mPendingServices.size(); i++) {
9069 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009070 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 r.dump(pw, " ");
9072 }
9073 needSep = true;
9074 }
9075
9076 if (mRestartingServices.size() > 0) {
9077 if (needSep) pw.println(" ");
9078 pw.println(" Restarting services:");
9079 for (int i=0; i<mRestartingServices.size(); i++) {
9080 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009081 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009082 r.dump(pw, " ");
9083 }
9084 needSep = true;
9085 }
9086
9087 if (mStoppingServices.size() > 0) {
9088 if (needSep) pw.println(" ");
9089 pw.println(" Stopping services:");
9090 for (int i=0; i<mStoppingServices.size(); i++) {
9091 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009092 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009093 r.dump(pw, " ");
9094 }
9095 needSep = true;
9096 }
9097
9098 if (mServiceConnections.size() > 0) {
9099 if (needSep) pw.println(" ");
9100 pw.println(" Connection bindings to services:");
9101 Iterator<ConnectionRecord> it
9102 = mServiceConnections.values().iterator();
9103 while (it.hasNext()) {
9104 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009105 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009106 r.dump(pw, " ");
9107 }
9108 }
9109 }
9110 }
9111
9112 void dumpProviders(PrintWriter pw) {
9113 synchronized (this) {
9114 if (checkCallingPermission(android.Manifest.permission.DUMP)
9115 != PackageManager.PERMISSION_GRANTED) {
9116 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9117 + Binder.getCallingPid()
9118 + ", uid=" + Binder.getCallingUid()
9119 + " without permission "
9120 + android.Manifest.permission.DUMP);
9121 return;
9122 }
9123
9124 pw.println("Content Providers in Current Activity Manager State:");
9125
9126 boolean needSep = false;
9127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009128 if (mProvidersByClass.size() > 0) {
9129 if (needSep) pw.println(" ");
9130 pw.println(" Published content providers (by class):");
9131 Iterator it = mProvidersByClass.entrySet().iterator();
9132 while (it.hasNext()) {
9133 Map.Entry e = (Map.Entry)it.next();
9134 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009135 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009136 r.dump(pw, " ");
9137 }
9138 needSep = true;
9139 }
9140
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009141 if (mProvidersByName.size() > 0) {
9142 pw.println(" ");
9143 pw.println(" Authority to provider mappings:");
9144 Iterator it = mProvidersByName.entrySet().iterator();
9145 while (it.hasNext()) {
9146 Map.Entry e = (Map.Entry)it.next();
9147 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9148 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9149 pw.println(r);
9150 }
9151 needSep = true;
9152 }
9153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009154 if (mLaunchingProviders.size() > 0) {
9155 if (needSep) pw.println(" ");
9156 pw.println(" Launching content providers:");
9157 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009158 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9159 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009160 }
9161 needSep = true;
9162 }
9163
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009164 if (mGrantedUriPermissions.size() > 0) {
9165 pw.println();
9166 pw.println("Granted Uri Permissions:");
9167 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9168 int uid = mGrantedUriPermissions.keyAt(i);
9169 HashMap<Uri, UriPermission> perms
9170 = mGrantedUriPermissions.valueAt(i);
9171 pw.print(" * UID "); pw.print(uid);
9172 pw.println(" holds:");
9173 for (UriPermission perm : perms.values()) {
9174 pw.print(" "); pw.println(perm);
9175 perm.dump(pw, " ");
9176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009177 }
9178 }
9179 }
9180 }
9181
9182 void dumpSenders(PrintWriter pw) {
9183 synchronized (this) {
9184 if (checkCallingPermission(android.Manifest.permission.DUMP)
9185 != PackageManager.PERMISSION_GRANTED) {
9186 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9187 + Binder.getCallingPid()
9188 + ", uid=" + Binder.getCallingUid()
9189 + " without permission "
9190 + android.Manifest.permission.DUMP);
9191 return;
9192 }
9193
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009194 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009195
9196 if (this.mIntentSenderRecords.size() > 0) {
9197 Iterator<WeakReference<PendingIntentRecord>> it
9198 = mIntentSenderRecords.values().iterator();
9199 while (it.hasNext()) {
9200 WeakReference<PendingIntentRecord> ref = it.next();
9201 PendingIntentRecord rec = ref != null ? ref.get(): null;
9202 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009203 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009204 rec.dump(pw, " ");
9205 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009206 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009207 }
9208 }
9209 }
9210 }
9211 }
9212
9213 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009214 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009215 TaskRecord lastTask = null;
9216 for (int i=list.size()-1; i>=0; i--) {
9217 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009218 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009219 if (lastTask != r.task) {
9220 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009221 pw.print(prefix);
9222 pw.print(full ? "* " : " ");
9223 pw.println(lastTask);
9224 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009225 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009227 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009228 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9229 pw.print(" #"); pw.print(i); pw.print(": ");
9230 pw.println(r);
9231 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009232 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009233 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009234 }
9235 }
9236
9237 private static final int dumpProcessList(PrintWriter pw, List list,
9238 String prefix, String normalLabel, String persistentLabel,
9239 boolean inclOomAdj) {
9240 int numPers = 0;
9241 for (int i=list.size()-1; i>=0; i--) {
9242 ProcessRecord r = (ProcessRecord)list.get(i);
9243 if (false) {
9244 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9245 + " #" + i + ":");
9246 r.dump(pw, prefix + " ");
9247 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009248 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009249 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009250 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9251 if (r.adjSource != null || r.adjTarget != null) {
9252 pw.println(prefix + " " + r.adjTarget
9253 + " used by " + r.adjSource);
9254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009255 } else {
9256 pw.println(String.format("%s%s #%2d: %s",
9257 prefix, (r.persistent ? persistentLabel : normalLabel),
9258 i, r.toString()));
9259 }
9260 if (r.persistent) {
9261 numPers++;
9262 }
9263 }
9264 return numPers;
9265 }
9266
9267 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9268 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009269 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009270 long uptime = SystemClock.uptimeMillis();
9271 long realtime = SystemClock.elapsedRealtime();
9272
9273 if (isCheckinRequest) {
9274 // short checkin version
9275 pw.println(uptime + "," + realtime);
9276 pw.flush();
9277 } else {
9278 pw.println("Applications Memory Usage (kB):");
9279 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9280 }
9281 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9282 ProcessRecord r = (ProcessRecord)list.get(i);
9283 if (r.thread != null) {
9284 if (!isCheckinRequest) {
9285 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9286 pw.flush();
9287 }
9288 try {
9289 r.thread.asBinder().dump(fd, args);
9290 } catch (RemoteException e) {
9291 if (!isCheckinRequest) {
9292 pw.println("Got RemoteException!");
9293 pw.flush();
9294 }
9295 }
9296 }
9297 }
9298 }
9299
9300 /**
9301 * Searches array of arguments for the specified string
9302 * @param args array of argument strings
9303 * @param value value to search for
9304 * @return true if the value is contained in the array
9305 */
9306 private static boolean scanArgs(String[] args, String value) {
9307 if (args != null) {
9308 for (String arg : args) {
9309 if (value.equals(arg)) {
9310 return true;
9311 }
9312 }
9313 }
9314 return false;
9315 }
9316
Dianne Hackborn75b03852009-06-12 15:43:26 -07009317 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009318 int count = mHistory.size();
9319
9320 // convert the token to an entry in the history.
9321 HistoryRecord r = null;
9322 int index = -1;
9323 for (int i=count-1; i>=0; i--) {
9324 Object o = mHistory.get(i);
9325 if (o == token) {
9326 r = (HistoryRecord)o;
9327 index = i;
9328 break;
9329 }
9330 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009331
9332 return index;
9333 }
9334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009335 private final void killServicesLocked(ProcessRecord app,
9336 boolean allowRestart) {
9337 // Report disconnected services.
9338 if (false) {
9339 // XXX we are letting the client link to the service for
9340 // death notifications.
9341 if (app.services.size() > 0) {
9342 Iterator it = app.services.iterator();
9343 while (it.hasNext()) {
9344 ServiceRecord r = (ServiceRecord)it.next();
9345 if (r.connections.size() > 0) {
9346 Iterator<ConnectionRecord> jt
9347 = r.connections.values().iterator();
9348 while (jt.hasNext()) {
9349 ConnectionRecord c = jt.next();
9350 if (c.binding.client != app) {
9351 try {
9352 //c.conn.connected(r.className, null);
9353 } catch (Exception e) {
9354 // todo: this should be asynchronous!
9355 Log.w(TAG, "Exception thrown disconnected servce "
9356 + r.shortName
9357 + " from app " + app.processName, e);
9358 }
9359 }
9360 }
9361 }
9362 }
9363 }
9364 }
9365
9366 // Clean up any connections this application has to other services.
9367 if (app.connections.size() > 0) {
9368 Iterator<ConnectionRecord> it = app.connections.iterator();
9369 while (it.hasNext()) {
9370 ConnectionRecord r = it.next();
9371 removeConnectionLocked(r, app, null);
9372 }
9373 }
9374 app.connections.clear();
9375
9376 if (app.services.size() != 0) {
9377 // Any services running in the application need to be placed
9378 // back in the pending list.
9379 Iterator it = app.services.iterator();
9380 while (it.hasNext()) {
9381 ServiceRecord sr = (ServiceRecord)it.next();
9382 synchronized (sr.stats.getBatteryStats()) {
9383 sr.stats.stopLaunchedLocked();
9384 }
9385 sr.app = null;
9386 sr.executeNesting = 0;
9387 mStoppingServices.remove(sr);
9388 if (sr.bindings.size() > 0) {
9389 Iterator<IntentBindRecord> bindings
9390 = sr.bindings.values().iterator();
9391 while (bindings.hasNext()) {
9392 IntentBindRecord b = bindings.next();
9393 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9394 + ": shouldUnbind=" + b.hasBound);
9395 b.binder = null;
9396 b.requested = b.received = b.hasBound = false;
9397 }
9398 }
9399
9400 if (sr.crashCount >= 2) {
9401 Log.w(TAG, "Service crashed " + sr.crashCount
9402 + " times, stopping: " + sr);
9403 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9404 sr.crashCount, sr.shortName, app.pid);
9405 bringDownServiceLocked(sr, true);
9406 } else if (!allowRestart) {
9407 bringDownServiceLocked(sr, true);
9408 } else {
9409 scheduleServiceRestartLocked(sr);
9410 }
9411 }
9412
9413 if (!allowRestart) {
9414 app.services.clear();
9415 }
9416 }
9417
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009418 // Make sure we have no more records on the stopping list.
9419 int i = mStoppingServices.size();
9420 while (i > 0) {
9421 i--;
9422 ServiceRecord sr = mStoppingServices.get(i);
9423 if (sr.app == app) {
9424 mStoppingServices.remove(i);
9425 }
9426 }
9427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009428 app.executingServices.clear();
9429 }
9430
9431 private final void removeDyingProviderLocked(ProcessRecord proc,
9432 ContentProviderRecord cpr) {
9433 synchronized (cpr) {
9434 cpr.launchingApp = null;
9435 cpr.notifyAll();
9436 }
9437
9438 mProvidersByClass.remove(cpr.info.name);
9439 String names[] = cpr.info.authority.split(";");
9440 for (int j = 0; j < names.length; j++) {
9441 mProvidersByName.remove(names[j]);
9442 }
9443
9444 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9445 while (cit.hasNext()) {
9446 ProcessRecord capp = cit.next();
9447 if (!capp.persistent && capp.thread != null
9448 && capp.pid != 0
9449 && capp.pid != MY_PID) {
9450 Log.i(TAG, "Killing app " + capp.processName
9451 + " (pid " + capp.pid
9452 + ") because provider " + cpr.info.name
9453 + " is in dying process " + proc.processName);
9454 Process.killProcess(capp.pid);
9455 }
9456 }
9457
9458 mLaunchingProviders.remove(cpr);
9459 }
9460
9461 /**
9462 * Main code for cleaning up a process when it has gone away. This is
9463 * called both as a result of the process dying, or directly when stopping
9464 * a process when running in single process mode.
9465 */
9466 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9467 boolean restarting, int index) {
9468 if (index >= 0) {
9469 mLRUProcesses.remove(index);
9470 }
9471
9472 // Dismiss any open dialogs.
9473 if (app.crashDialog != null) {
9474 app.crashDialog.dismiss();
9475 app.crashDialog = null;
9476 }
9477 if (app.anrDialog != null) {
9478 app.anrDialog.dismiss();
9479 app.anrDialog = null;
9480 }
9481 if (app.waitDialog != null) {
9482 app.waitDialog.dismiss();
9483 app.waitDialog = null;
9484 }
9485
9486 app.crashing = false;
9487 app.notResponding = false;
9488
9489 app.resetPackageList();
9490 app.thread = null;
9491 app.forcingToForeground = null;
9492 app.foregroundServices = false;
9493
9494 killServicesLocked(app, true);
9495
9496 boolean restart = false;
9497
9498 int NL = mLaunchingProviders.size();
9499
9500 // Remove published content providers.
9501 if (!app.pubProviders.isEmpty()) {
9502 Iterator it = app.pubProviders.values().iterator();
9503 while (it.hasNext()) {
9504 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9505 cpr.provider = null;
9506 cpr.app = null;
9507
9508 // See if someone is waiting for this provider... in which
9509 // case we don't remove it, but just let it restart.
9510 int i = 0;
9511 if (!app.bad) {
9512 for (; i<NL; i++) {
9513 if (mLaunchingProviders.get(i) == cpr) {
9514 restart = true;
9515 break;
9516 }
9517 }
9518 } else {
9519 i = NL;
9520 }
9521
9522 if (i >= NL) {
9523 removeDyingProviderLocked(app, cpr);
9524 NL = mLaunchingProviders.size();
9525 }
9526 }
9527 app.pubProviders.clear();
9528 }
9529
9530 // Look through the content providers we are waiting to have launched,
9531 // and if any run in this process then either schedule a restart of
9532 // the process or kill the client waiting for it if this process has
9533 // gone bad.
9534 for (int i=0; i<NL; i++) {
9535 ContentProviderRecord cpr = (ContentProviderRecord)
9536 mLaunchingProviders.get(i);
9537 if (cpr.launchingApp == app) {
9538 if (!app.bad) {
9539 restart = true;
9540 } else {
9541 removeDyingProviderLocked(app, cpr);
9542 NL = mLaunchingProviders.size();
9543 }
9544 }
9545 }
9546
9547 // Unregister from connected content providers.
9548 if (!app.conProviders.isEmpty()) {
9549 Iterator it = app.conProviders.iterator();
9550 while (it.hasNext()) {
9551 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9552 cpr.clients.remove(app);
9553 }
9554 app.conProviders.clear();
9555 }
9556
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009557 // At this point there may be remaining entries in mLaunchingProviders
9558 // where we were the only one waiting, so they are no longer of use.
9559 // Look for these and clean up if found.
9560 // XXX Commented out for now. Trying to figure out a way to reproduce
9561 // the actual situation to identify what is actually going on.
9562 if (false) {
9563 for (int i=0; i<NL; i++) {
9564 ContentProviderRecord cpr = (ContentProviderRecord)
9565 mLaunchingProviders.get(i);
9566 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9567 synchronized (cpr) {
9568 cpr.launchingApp = null;
9569 cpr.notifyAll();
9570 }
9571 }
9572 }
9573 }
9574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009575 skipCurrentReceiverLocked(app);
9576
9577 // Unregister any receivers.
9578 if (app.receivers.size() > 0) {
9579 Iterator<ReceiverList> it = app.receivers.iterator();
9580 while (it.hasNext()) {
9581 removeReceiverLocked(it.next());
9582 }
9583 app.receivers.clear();
9584 }
9585
Christopher Tate181fafa2009-05-14 11:12:14 -07009586 // If the app is undergoing backup, tell the backup manager about it
9587 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9588 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9589 try {
9590 IBackupManager bm = IBackupManager.Stub.asInterface(
9591 ServiceManager.getService(Context.BACKUP_SERVICE));
9592 bm.agentDisconnected(app.info.packageName);
9593 } catch (RemoteException e) {
9594 // can't happen; backup manager is local
9595 }
9596 }
9597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009598 // If the caller is restarting this app, then leave it in its
9599 // current lists and let the caller take care of it.
9600 if (restarting) {
9601 return;
9602 }
9603
9604 if (!app.persistent) {
9605 if (DEBUG_PROCESSES) Log.v(TAG,
9606 "Removing non-persistent process during cleanup: " + app);
9607 mProcessNames.remove(app.processName, app.info.uid);
9608 } else if (!app.removed) {
9609 // This app is persistent, so we need to keep its record around.
9610 // If it is not already on the pending app list, add it there
9611 // and start a new process for it.
9612 app.thread = null;
9613 app.forcingToForeground = null;
9614 app.foregroundServices = false;
9615 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9616 mPersistentStartingProcesses.add(app);
9617 restart = true;
9618 }
9619 }
9620 mProcessesOnHold.remove(app);
9621
The Android Open Source Project4df24232009-03-05 14:34:35 -08009622 if (app == mHomeProcess) {
9623 mHomeProcess = null;
9624 }
9625
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009626 if (restart) {
9627 // We have components that still need to be running in the
9628 // process, so re-launch it.
9629 mProcessNames.put(app.processName, app.info.uid, app);
9630 startProcessLocked(app, "restart", app.processName);
9631 } else if (app.pid > 0 && app.pid != MY_PID) {
9632 // Goodbye!
9633 synchronized (mPidsSelfLocked) {
9634 mPidsSelfLocked.remove(app.pid);
9635 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9636 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009637 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009638 }
9639 }
9640
9641 // =========================================================
9642 // SERVICES
9643 // =========================================================
9644
9645 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9646 ActivityManager.RunningServiceInfo info =
9647 new ActivityManager.RunningServiceInfo();
9648 info.service = r.name;
9649 if (r.app != null) {
9650 info.pid = r.app.pid;
9651 }
9652 info.process = r.processName;
9653 info.foreground = r.isForeground;
9654 info.activeSince = r.createTime;
9655 info.started = r.startRequested;
9656 info.clientCount = r.connections.size();
9657 info.crashCount = r.crashCount;
9658 info.lastActivityTime = r.lastActivity;
9659 return info;
9660 }
9661
9662 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9663 int flags) {
9664 synchronized (this) {
9665 ArrayList<ActivityManager.RunningServiceInfo> res
9666 = new ArrayList<ActivityManager.RunningServiceInfo>();
9667
9668 if (mServices.size() > 0) {
9669 Iterator<ServiceRecord> it = mServices.values().iterator();
9670 while (it.hasNext() && res.size() < maxNum) {
9671 res.add(makeRunningServiceInfoLocked(it.next()));
9672 }
9673 }
9674
9675 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9676 ServiceRecord r = mRestartingServices.get(i);
9677 ActivityManager.RunningServiceInfo info =
9678 makeRunningServiceInfoLocked(r);
9679 info.restarting = r.nextRestartTime;
9680 res.add(info);
9681 }
9682
9683 return res;
9684 }
9685 }
9686
9687 private final ServiceRecord findServiceLocked(ComponentName name,
9688 IBinder token) {
9689 ServiceRecord r = mServices.get(name);
9690 return r == token ? r : null;
9691 }
9692
9693 private final class ServiceLookupResult {
9694 final ServiceRecord record;
9695 final String permission;
9696
9697 ServiceLookupResult(ServiceRecord _record, String _permission) {
9698 record = _record;
9699 permission = _permission;
9700 }
9701 };
9702
9703 private ServiceLookupResult findServiceLocked(Intent service,
9704 String resolvedType) {
9705 ServiceRecord r = null;
9706 if (service.getComponent() != null) {
9707 r = mServices.get(service.getComponent());
9708 }
9709 if (r == null) {
9710 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9711 r = mServicesByIntent.get(filter);
9712 }
9713
9714 if (r == null) {
9715 try {
9716 ResolveInfo rInfo =
9717 ActivityThread.getPackageManager().resolveService(
9718 service, resolvedType, 0);
9719 ServiceInfo sInfo =
9720 rInfo != null ? rInfo.serviceInfo : null;
9721 if (sInfo == null) {
9722 return null;
9723 }
9724
9725 ComponentName name = new ComponentName(
9726 sInfo.applicationInfo.packageName, sInfo.name);
9727 r = mServices.get(name);
9728 } catch (RemoteException ex) {
9729 // pm is in same process, this will never happen.
9730 }
9731 }
9732 if (r != null) {
9733 int callingPid = Binder.getCallingPid();
9734 int callingUid = Binder.getCallingUid();
9735 if (checkComponentPermission(r.permission,
9736 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9737 != PackageManager.PERMISSION_GRANTED) {
9738 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9739 + " from pid=" + callingPid
9740 + ", uid=" + callingUid
9741 + " requires " + r.permission);
9742 return new ServiceLookupResult(null, r.permission);
9743 }
9744 return new ServiceLookupResult(r, null);
9745 }
9746 return null;
9747 }
9748
9749 private class ServiceRestarter implements Runnable {
9750 private ServiceRecord mService;
9751
9752 void setService(ServiceRecord service) {
9753 mService = service;
9754 }
9755
9756 public void run() {
9757 synchronized(ActivityManagerService.this) {
9758 performServiceRestartLocked(mService);
9759 }
9760 }
9761 }
9762
9763 private ServiceLookupResult retrieveServiceLocked(Intent service,
9764 String resolvedType, int callingPid, int callingUid) {
9765 ServiceRecord r = null;
9766 if (service.getComponent() != null) {
9767 r = mServices.get(service.getComponent());
9768 }
9769 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9770 r = mServicesByIntent.get(filter);
9771 if (r == null) {
9772 try {
9773 ResolveInfo rInfo =
9774 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009775 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009776 ServiceInfo sInfo =
9777 rInfo != null ? rInfo.serviceInfo : null;
9778 if (sInfo == null) {
9779 Log.w(TAG, "Unable to start service " + service +
9780 ": not found");
9781 return null;
9782 }
9783
9784 ComponentName name = new ComponentName(
9785 sInfo.applicationInfo.packageName, sInfo.name);
9786 r = mServices.get(name);
9787 if (r == null) {
9788 filter = new Intent.FilterComparison(service.cloneFilter());
9789 ServiceRestarter res = new ServiceRestarter();
9790 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9791 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9792 synchronized (stats) {
9793 ss = stats.getServiceStatsLocked(
9794 sInfo.applicationInfo.uid, sInfo.packageName,
9795 sInfo.name);
9796 }
9797 r = new ServiceRecord(ss, name, filter, sInfo, res);
9798 res.setService(r);
9799 mServices.put(name, r);
9800 mServicesByIntent.put(filter, r);
9801
9802 // Make sure this component isn't in the pending list.
9803 int N = mPendingServices.size();
9804 for (int i=0; i<N; i++) {
9805 ServiceRecord pr = mPendingServices.get(i);
9806 if (pr.name.equals(name)) {
9807 mPendingServices.remove(i);
9808 i--;
9809 N--;
9810 }
9811 }
9812 }
9813 } catch (RemoteException ex) {
9814 // pm is in same process, this will never happen.
9815 }
9816 }
9817 if (r != null) {
9818 if (checkComponentPermission(r.permission,
9819 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9820 != PackageManager.PERMISSION_GRANTED) {
9821 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9822 + " from pid=" + Binder.getCallingPid()
9823 + ", uid=" + Binder.getCallingUid()
9824 + " requires " + r.permission);
9825 return new ServiceLookupResult(null, r.permission);
9826 }
9827 return new ServiceLookupResult(r, null);
9828 }
9829 return null;
9830 }
9831
9832 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9833 long now = SystemClock.uptimeMillis();
9834 if (r.executeNesting == 0 && r.app != null) {
9835 if (r.app.executingServices.size() == 0) {
9836 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9837 msg.obj = r.app;
9838 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9839 }
9840 r.app.executingServices.add(r);
9841 }
9842 r.executeNesting++;
9843 r.executingStart = now;
9844 }
9845
9846 private final void sendServiceArgsLocked(ServiceRecord r,
9847 boolean oomAdjusted) {
9848 final int N = r.startArgs.size();
9849 if (N == 0) {
9850 return;
9851 }
9852
9853 final int BASEID = r.lastStartId - N + 1;
9854 int i = 0;
9855 while (i < N) {
9856 try {
9857 Intent args = r.startArgs.get(i);
9858 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9859 + r.name + " " + r.intent + " args=" + args);
9860 bumpServiceExecutingLocked(r);
9861 if (!oomAdjusted) {
9862 oomAdjusted = true;
9863 updateOomAdjLocked(r.app);
9864 }
9865 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9866 i++;
9867 } catch (Exception e) {
9868 break;
9869 }
9870 }
9871 if (i == N) {
9872 r.startArgs.clear();
9873 } else {
9874 while (i > 0) {
9875 r.startArgs.remove(0);
9876 i--;
9877 }
9878 }
9879 }
9880
9881 private final boolean requestServiceBindingLocked(ServiceRecord r,
9882 IntentBindRecord i, boolean rebind) {
9883 if (r.app == null || r.app.thread == null) {
9884 // If service is not currently running, can't yet bind.
9885 return false;
9886 }
9887 if ((!i.requested || rebind) && i.apps.size() > 0) {
9888 try {
9889 bumpServiceExecutingLocked(r);
9890 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9891 + ": shouldUnbind=" + i.hasBound);
9892 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9893 if (!rebind) {
9894 i.requested = true;
9895 }
9896 i.hasBound = true;
9897 i.doRebind = false;
9898 } catch (RemoteException e) {
9899 return false;
9900 }
9901 }
9902 return true;
9903 }
9904
9905 private final void requestServiceBindingsLocked(ServiceRecord r) {
9906 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9907 while (bindings.hasNext()) {
9908 IntentBindRecord i = bindings.next();
9909 if (!requestServiceBindingLocked(r, i, false)) {
9910 break;
9911 }
9912 }
9913 }
9914
9915 private final void realStartServiceLocked(ServiceRecord r,
9916 ProcessRecord app) throws RemoteException {
9917 if (app.thread == null) {
9918 throw new RemoteException();
9919 }
9920
9921 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009922 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009923
9924 app.services.add(r);
9925 bumpServiceExecutingLocked(r);
9926 updateLRUListLocked(app, true);
9927
9928 boolean created = false;
9929 try {
9930 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9931 + r.name + " " + r.intent);
9932 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9933 System.identityHashCode(r), r.shortName,
9934 r.intent.getIntent().toString(), r.app.pid);
9935 synchronized (r.stats.getBatteryStats()) {
9936 r.stats.startLaunchedLocked();
9937 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009938 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009939 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07009940 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009941 created = true;
9942 } finally {
9943 if (!created) {
9944 app.services.remove(r);
9945 scheduleServiceRestartLocked(r);
9946 }
9947 }
9948
9949 requestServiceBindingsLocked(r);
9950 sendServiceArgsLocked(r, true);
9951 }
9952
9953 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9954 r.totalRestartCount++;
9955 if (r.restartDelay == 0) {
9956 r.restartCount++;
9957 r.restartDelay = SERVICE_RESTART_DURATION;
9958 } else {
9959 // If it has been a "reasonably long time" since the service
9960 // was started, then reset our restart duration back to
9961 // the beginning, so we don't infinitely increase the duration
9962 // on a service that just occasionally gets killed (which is
9963 // a normal case, due to process being killed to reclaim memory).
9964 long now = SystemClock.uptimeMillis();
9965 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9966 r.restartCount = 1;
9967 r.restartDelay = SERVICE_RESTART_DURATION;
9968 } else {
9969 r.restartDelay *= 2;
9970 }
9971 }
9972 if (!mRestartingServices.contains(r)) {
9973 mRestartingServices.add(r);
9974 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07009975 r.cancelNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009976 mHandler.removeCallbacks(r.restarter);
9977 mHandler.postDelayed(r.restarter, r.restartDelay);
9978 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9979 Log.w(TAG, "Scheduling restart of crashed service "
9980 + r.shortName + " in " + r.restartDelay + "ms");
9981 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9982 r.shortName, r.restartDelay);
9983
9984 Message msg = Message.obtain();
9985 msg.what = SERVICE_ERROR_MSG;
9986 msg.obj = r;
9987 mHandler.sendMessage(msg);
9988 }
9989
9990 final void performServiceRestartLocked(ServiceRecord r) {
9991 if (!mRestartingServices.contains(r)) {
9992 return;
9993 }
9994 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9995 }
9996
9997 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9998 if (r.restartDelay == 0) {
9999 return false;
10000 }
10001 r.resetRestartCounter();
10002 mRestartingServices.remove(r);
10003 mHandler.removeCallbacks(r.restarter);
10004 return true;
10005 }
10006
10007 private final boolean bringUpServiceLocked(ServiceRecord r,
10008 int intentFlags, boolean whileRestarting) {
10009 //Log.i(TAG, "Bring up service:");
10010 //r.dump(" ");
10011
10012 if (r.app != null) {
10013 sendServiceArgsLocked(r, false);
10014 return true;
10015 }
10016
10017 if (!whileRestarting && r.restartDelay > 0) {
10018 // If waiting for a restart, then do nothing.
10019 return true;
10020 }
10021
10022 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10023 + " " + r.intent);
10024
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010025 // We are now bringing the service up, so no longer in the
10026 // restarting state.
10027 mRestartingServices.remove(r);
10028
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010029 final String appName = r.processName;
10030 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10031 if (app != null && app.thread != null) {
10032 try {
10033 realStartServiceLocked(r, app);
10034 return true;
10035 } catch (RemoteException e) {
10036 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10037 }
10038
10039 // If a dead object exception was thrown -- fall through to
10040 // restart the application.
10041 }
10042
10043 if (!mPendingServices.contains(r)) {
10044 // Not running -- get it started, and enqueue this service record
10045 // to be executed when the app comes up.
10046 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10047 "service", r.name) == null) {
10048 Log.w(TAG, "Unable to launch app "
10049 + r.appInfo.packageName + "/"
10050 + r.appInfo.uid + " for service "
10051 + r.intent.getIntent() + ": process is bad");
10052 bringDownServiceLocked(r, true);
10053 return false;
10054 }
10055 mPendingServices.add(r);
10056 }
10057 return true;
10058 }
10059
10060 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10061 //Log.i(TAG, "Bring down service:");
10062 //r.dump(" ");
10063
10064 // Does it still need to run?
10065 if (!force && r.startRequested) {
10066 return;
10067 }
10068 if (r.connections.size() > 0) {
10069 if (!force) {
10070 // XXX should probably keep a count of the number of auto-create
10071 // connections directly in the service.
10072 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10073 while (it.hasNext()) {
10074 ConnectionRecord cr = it.next();
10075 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10076 return;
10077 }
10078 }
10079 }
10080
10081 // Report to all of the connections that the service is no longer
10082 // available.
10083 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10084 while (it.hasNext()) {
10085 ConnectionRecord c = it.next();
10086 try {
10087 // todo: shouldn't be a synchronous call!
10088 c.conn.connected(r.name, null);
10089 } catch (Exception e) {
10090 Log.w(TAG, "Failure disconnecting service " + r.name +
10091 " to connection " + c.conn.asBinder() +
10092 " (in " + c.binding.client.processName + ")", e);
10093 }
10094 }
10095 }
10096
10097 // Tell the service that it has been unbound.
10098 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10099 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10100 while (it.hasNext()) {
10101 IntentBindRecord ibr = it.next();
10102 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10103 + ": hasBound=" + ibr.hasBound);
10104 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10105 try {
10106 bumpServiceExecutingLocked(r);
10107 updateOomAdjLocked(r.app);
10108 ibr.hasBound = false;
10109 r.app.thread.scheduleUnbindService(r,
10110 ibr.intent.getIntent());
10111 } catch (Exception e) {
10112 Log.w(TAG, "Exception when unbinding service "
10113 + r.shortName, e);
10114 serviceDoneExecutingLocked(r, true);
10115 }
10116 }
10117 }
10118 }
10119
10120 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10121 + " " + r.intent);
10122 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10123 System.identityHashCode(r), r.shortName,
10124 (r.app != null) ? r.app.pid : -1);
10125
10126 mServices.remove(r.name);
10127 mServicesByIntent.remove(r.intent);
10128 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10129 r.totalRestartCount = 0;
10130 unscheduleServiceRestartLocked(r);
10131
10132 // Also make sure it is not on the pending list.
10133 int N = mPendingServices.size();
10134 for (int i=0; i<N; i++) {
10135 if (mPendingServices.get(i) == r) {
10136 mPendingServices.remove(i);
10137 if (DEBUG_SERVICE) Log.v(
10138 TAG, "Removed pending service: " + r.shortName);
10139 i--;
10140 N--;
10141 }
10142 }
10143
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010144 r.cancelNotification();
10145 r.isForeground = false;
10146 r.foregroundId = 0;
10147 r.foregroundNoti = null;
10148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010149 if (r.app != null) {
10150 synchronized (r.stats.getBatteryStats()) {
10151 r.stats.stopLaunchedLocked();
10152 }
10153 r.app.services.remove(r);
10154 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010155 try {
10156 Log.i(TAG, "Stopping service: " + r.shortName);
10157 bumpServiceExecutingLocked(r);
10158 mStoppingServices.add(r);
10159 updateOomAdjLocked(r.app);
10160 r.app.thread.scheduleStopService(r);
10161 } catch (Exception e) {
10162 Log.w(TAG, "Exception when stopping service "
10163 + r.shortName, e);
10164 serviceDoneExecutingLocked(r, true);
10165 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010166 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010167 } else {
10168 if (DEBUG_SERVICE) Log.v(
10169 TAG, "Removed service that has no process: " + r.shortName);
10170 }
10171 } else {
10172 if (DEBUG_SERVICE) Log.v(
10173 TAG, "Removed service that is not running: " + r.shortName);
10174 }
10175 }
10176
10177 ComponentName startServiceLocked(IApplicationThread caller,
10178 Intent service, String resolvedType,
10179 int callingPid, int callingUid) {
10180 synchronized(this) {
10181 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10182 + " type=" + resolvedType + " args=" + service.getExtras());
10183
10184 if (caller != null) {
10185 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10186 if (callerApp == null) {
10187 throw new SecurityException(
10188 "Unable to find app for caller " + caller
10189 + " (pid=" + Binder.getCallingPid()
10190 + ") when starting service " + service);
10191 }
10192 }
10193
10194 ServiceLookupResult res =
10195 retrieveServiceLocked(service, resolvedType,
10196 callingPid, callingUid);
10197 if (res == null) {
10198 return null;
10199 }
10200 if (res.record == null) {
10201 return new ComponentName("!", res.permission != null
10202 ? res.permission : "private to package");
10203 }
10204 ServiceRecord r = res.record;
10205 if (unscheduleServiceRestartLocked(r)) {
10206 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10207 + r.shortName);
10208 }
10209 r.startRequested = true;
10210 r.startArgs.add(service);
10211 r.lastStartId++;
10212 if (r.lastStartId < 1) {
10213 r.lastStartId = 1;
10214 }
10215 r.lastActivity = SystemClock.uptimeMillis();
10216 synchronized (r.stats.getBatteryStats()) {
10217 r.stats.startRunningLocked();
10218 }
10219 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10220 return new ComponentName("!", "Service process is bad");
10221 }
10222 return r.name;
10223 }
10224 }
10225
10226 public ComponentName startService(IApplicationThread caller, Intent service,
10227 String resolvedType) {
10228 // Refuse possible leaked file descriptors
10229 if (service != null && service.hasFileDescriptors() == true) {
10230 throw new IllegalArgumentException("File descriptors passed in Intent");
10231 }
10232
10233 synchronized(this) {
10234 final int callingPid = Binder.getCallingPid();
10235 final int callingUid = Binder.getCallingUid();
10236 final long origId = Binder.clearCallingIdentity();
10237 ComponentName res = startServiceLocked(caller, service,
10238 resolvedType, callingPid, callingUid);
10239 Binder.restoreCallingIdentity(origId);
10240 return res;
10241 }
10242 }
10243
10244 ComponentName startServiceInPackage(int uid,
10245 Intent service, String resolvedType) {
10246 synchronized(this) {
10247 final long origId = Binder.clearCallingIdentity();
10248 ComponentName res = startServiceLocked(null, service,
10249 resolvedType, -1, uid);
10250 Binder.restoreCallingIdentity(origId);
10251 return res;
10252 }
10253 }
10254
10255 public int stopService(IApplicationThread caller, Intent service,
10256 String resolvedType) {
10257 // Refuse possible leaked file descriptors
10258 if (service != null && service.hasFileDescriptors() == true) {
10259 throw new IllegalArgumentException("File descriptors passed in Intent");
10260 }
10261
10262 synchronized(this) {
10263 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10264 + " type=" + resolvedType);
10265
10266 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10267 if (caller != null && callerApp == null) {
10268 throw new SecurityException(
10269 "Unable to find app for caller " + caller
10270 + " (pid=" + Binder.getCallingPid()
10271 + ") when stopping service " + service);
10272 }
10273
10274 // If this service is active, make sure it is stopped.
10275 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10276 if (r != null) {
10277 if (r.record != null) {
10278 synchronized (r.record.stats.getBatteryStats()) {
10279 r.record.stats.stopRunningLocked();
10280 }
10281 r.record.startRequested = false;
10282 final long origId = Binder.clearCallingIdentity();
10283 bringDownServiceLocked(r.record, false);
10284 Binder.restoreCallingIdentity(origId);
10285 return 1;
10286 }
10287 return -1;
10288 }
10289 }
10290
10291 return 0;
10292 }
10293
10294 public IBinder peekService(Intent service, String resolvedType) {
10295 // Refuse possible leaked file descriptors
10296 if (service != null && service.hasFileDescriptors() == true) {
10297 throw new IllegalArgumentException("File descriptors passed in Intent");
10298 }
10299
10300 IBinder ret = null;
10301
10302 synchronized(this) {
10303 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10304
10305 if (r != null) {
10306 // r.record is null if findServiceLocked() failed the caller permission check
10307 if (r.record == null) {
10308 throw new SecurityException(
10309 "Permission Denial: Accessing service " + r.record.name
10310 + " from pid=" + Binder.getCallingPid()
10311 + ", uid=" + Binder.getCallingUid()
10312 + " requires " + r.permission);
10313 }
10314 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10315 if (ib != null) {
10316 ret = ib.binder;
10317 }
10318 }
10319 }
10320
10321 return ret;
10322 }
10323
10324 public boolean stopServiceToken(ComponentName className, IBinder token,
10325 int startId) {
10326 synchronized(this) {
10327 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10328 + " " + token + " startId=" + startId);
10329 ServiceRecord r = findServiceLocked(className, token);
10330 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10331 synchronized (r.stats.getBatteryStats()) {
10332 r.stats.stopRunningLocked();
10333 r.startRequested = false;
10334 }
10335 final long origId = Binder.clearCallingIdentity();
10336 bringDownServiceLocked(r, false);
10337 Binder.restoreCallingIdentity(origId);
10338 return true;
10339 }
10340 }
10341 return false;
10342 }
10343
10344 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010345 int id, Notification notification, boolean removeNotification) {
10346 final long origId = Binder.clearCallingIdentity();
10347 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010348 synchronized(this) {
10349 ServiceRecord r = findServiceLocked(className, token);
10350 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010351 if (id != 0) {
10352 if (notification == null) {
10353 throw new IllegalArgumentException("null notification");
10354 }
10355 if (r.foregroundId != id) {
10356 r.cancelNotification();
10357 r.foregroundId = id;
10358 }
10359 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10360 r.foregroundNoti = notification;
10361 r.isForeground = true;
10362 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010363 if (r.app != null) {
10364 updateServiceForegroundLocked(r.app, true);
10365 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010366 } else {
10367 if (r.isForeground) {
10368 r.isForeground = false;
10369 if (r.app != null) {
10370 updateServiceForegroundLocked(r.app, true);
10371 }
10372 }
10373 if (removeNotification) {
10374 r.cancelNotification();
10375 r.foregroundId = 0;
10376 r.foregroundNoti = null;
10377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010378 }
10379 }
10380 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010381 } finally {
10382 Binder.restoreCallingIdentity(origId);
10383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010384 }
10385
10386 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10387 boolean anyForeground = false;
10388 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10389 if (sr.isForeground) {
10390 anyForeground = true;
10391 break;
10392 }
10393 }
10394 if (anyForeground != proc.foregroundServices) {
10395 proc.foregroundServices = anyForeground;
10396 if (oomAdj) {
10397 updateOomAdjLocked();
10398 }
10399 }
10400 }
10401
10402 public int bindService(IApplicationThread caller, IBinder token,
10403 Intent service, String resolvedType,
10404 IServiceConnection connection, int flags) {
10405 // Refuse possible leaked file descriptors
10406 if (service != null && service.hasFileDescriptors() == true) {
10407 throw new IllegalArgumentException("File descriptors passed in Intent");
10408 }
10409
10410 synchronized(this) {
10411 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10412 + " type=" + resolvedType + " conn=" + connection.asBinder()
10413 + " flags=0x" + Integer.toHexString(flags));
10414 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10415 if (callerApp == null) {
10416 throw new SecurityException(
10417 "Unable to find app for caller " + caller
10418 + " (pid=" + Binder.getCallingPid()
10419 + ") when binding service " + service);
10420 }
10421
10422 HistoryRecord activity = null;
10423 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010424 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010425 if (aindex < 0) {
10426 Log.w(TAG, "Binding with unknown activity: " + token);
10427 return 0;
10428 }
10429 activity = (HistoryRecord)mHistory.get(aindex);
10430 }
10431
10432 ServiceLookupResult res =
10433 retrieveServiceLocked(service, resolvedType,
10434 Binder.getCallingPid(), Binder.getCallingUid());
10435 if (res == null) {
10436 return 0;
10437 }
10438 if (res.record == null) {
10439 return -1;
10440 }
10441 ServiceRecord s = res.record;
10442
10443 final long origId = Binder.clearCallingIdentity();
10444
10445 if (unscheduleServiceRestartLocked(s)) {
10446 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10447 + s.shortName);
10448 }
10449
10450 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10451 ConnectionRecord c = new ConnectionRecord(b, activity,
10452 connection, flags);
10453
10454 IBinder binder = connection.asBinder();
10455 s.connections.put(binder, c);
10456 b.connections.add(c);
10457 if (activity != null) {
10458 if (activity.connections == null) {
10459 activity.connections = new HashSet<ConnectionRecord>();
10460 }
10461 activity.connections.add(c);
10462 }
10463 b.client.connections.add(c);
10464 mServiceConnections.put(binder, c);
10465
10466 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10467 s.lastActivity = SystemClock.uptimeMillis();
10468 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10469 return 0;
10470 }
10471 }
10472
10473 if (s.app != null) {
10474 // This could have made the service more important.
10475 updateOomAdjLocked(s.app);
10476 }
10477
10478 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10479 + ": received=" + b.intent.received
10480 + " apps=" + b.intent.apps.size()
10481 + " doRebind=" + b.intent.doRebind);
10482
10483 if (s.app != null && b.intent.received) {
10484 // Service is already running, so we can immediately
10485 // publish the connection.
10486 try {
10487 c.conn.connected(s.name, b.intent.binder);
10488 } catch (Exception e) {
10489 Log.w(TAG, "Failure sending service " + s.shortName
10490 + " to connection " + c.conn.asBinder()
10491 + " (in " + c.binding.client.processName + ")", e);
10492 }
10493
10494 // If this is the first app connected back to this binding,
10495 // and the service had previously asked to be told when
10496 // rebound, then do so.
10497 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10498 requestServiceBindingLocked(s, b.intent, true);
10499 }
10500 } else if (!b.intent.requested) {
10501 requestServiceBindingLocked(s, b.intent, false);
10502 }
10503
10504 Binder.restoreCallingIdentity(origId);
10505 }
10506
10507 return 1;
10508 }
10509
10510 private void removeConnectionLocked(
10511 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10512 IBinder binder = c.conn.asBinder();
10513 AppBindRecord b = c.binding;
10514 ServiceRecord s = b.service;
10515 s.connections.remove(binder);
10516 b.connections.remove(c);
10517 if (c.activity != null && c.activity != skipAct) {
10518 if (c.activity.connections != null) {
10519 c.activity.connections.remove(c);
10520 }
10521 }
10522 if (b.client != skipApp) {
10523 b.client.connections.remove(c);
10524 }
10525 mServiceConnections.remove(binder);
10526
10527 if (b.connections.size() == 0) {
10528 b.intent.apps.remove(b.client);
10529 }
10530
10531 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10532 + ": shouldUnbind=" + b.intent.hasBound);
10533 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10534 && b.intent.hasBound) {
10535 try {
10536 bumpServiceExecutingLocked(s);
10537 updateOomAdjLocked(s.app);
10538 b.intent.hasBound = false;
10539 // Assume the client doesn't want to know about a rebind;
10540 // we will deal with that later if it asks for one.
10541 b.intent.doRebind = false;
10542 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10543 } catch (Exception e) {
10544 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10545 serviceDoneExecutingLocked(s, true);
10546 }
10547 }
10548
10549 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10550 bringDownServiceLocked(s, false);
10551 }
10552 }
10553
10554 public boolean unbindService(IServiceConnection connection) {
10555 synchronized (this) {
10556 IBinder binder = connection.asBinder();
10557 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10558 ConnectionRecord r = mServiceConnections.get(binder);
10559 if (r == null) {
10560 Log.w(TAG, "Unbind failed: could not find connection for "
10561 + connection.asBinder());
10562 return false;
10563 }
10564
10565 final long origId = Binder.clearCallingIdentity();
10566
10567 removeConnectionLocked(r, null, null);
10568
10569 if (r.binding.service.app != null) {
10570 // This could have made the service less important.
10571 updateOomAdjLocked(r.binding.service.app);
10572 }
10573
10574 Binder.restoreCallingIdentity(origId);
10575 }
10576
10577 return true;
10578 }
10579
10580 public void publishService(IBinder token, Intent intent, IBinder service) {
10581 // Refuse possible leaked file descriptors
10582 if (intent != null && intent.hasFileDescriptors() == true) {
10583 throw new IllegalArgumentException("File descriptors passed in Intent");
10584 }
10585
10586 synchronized(this) {
10587 if (!(token instanceof ServiceRecord)) {
10588 throw new IllegalArgumentException("Invalid service token");
10589 }
10590 ServiceRecord r = (ServiceRecord)token;
10591
10592 final long origId = Binder.clearCallingIdentity();
10593
10594 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10595 + " " + intent + ": " + service);
10596 if (r != null) {
10597 Intent.FilterComparison filter
10598 = new Intent.FilterComparison(intent);
10599 IntentBindRecord b = r.bindings.get(filter);
10600 if (b != null && !b.received) {
10601 b.binder = service;
10602 b.requested = true;
10603 b.received = true;
10604 if (r.connections.size() > 0) {
10605 Iterator<ConnectionRecord> it
10606 = r.connections.values().iterator();
10607 while (it.hasNext()) {
10608 ConnectionRecord c = it.next();
10609 if (!filter.equals(c.binding.intent.intent)) {
10610 if (DEBUG_SERVICE) Log.v(
10611 TAG, "Not publishing to: " + c);
10612 if (DEBUG_SERVICE) Log.v(
10613 TAG, "Bound intent: " + c.binding.intent.intent);
10614 if (DEBUG_SERVICE) Log.v(
10615 TAG, "Published intent: " + intent);
10616 continue;
10617 }
10618 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10619 try {
10620 c.conn.connected(r.name, service);
10621 } catch (Exception e) {
10622 Log.w(TAG, "Failure sending service " + r.name +
10623 " to connection " + c.conn.asBinder() +
10624 " (in " + c.binding.client.processName + ")", e);
10625 }
10626 }
10627 }
10628 }
10629
10630 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10631
10632 Binder.restoreCallingIdentity(origId);
10633 }
10634 }
10635 }
10636
10637 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10638 // Refuse possible leaked file descriptors
10639 if (intent != null && intent.hasFileDescriptors() == true) {
10640 throw new IllegalArgumentException("File descriptors passed in Intent");
10641 }
10642
10643 synchronized(this) {
10644 if (!(token instanceof ServiceRecord)) {
10645 throw new IllegalArgumentException("Invalid service token");
10646 }
10647 ServiceRecord r = (ServiceRecord)token;
10648
10649 final long origId = Binder.clearCallingIdentity();
10650
10651 if (r != null) {
10652 Intent.FilterComparison filter
10653 = new Intent.FilterComparison(intent);
10654 IntentBindRecord b = r.bindings.get(filter);
10655 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10656 + " at " + b + ": apps="
10657 + (b != null ? b.apps.size() : 0));
10658 if (b != null) {
10659 if (b.apps.size() > 0) {
10660 // Applications have already bound since the last
10661 // unbind, so just rebind right here.
10662 requestServiceBindingLocked(r, b, true);
10663 } else {
10664 // Note to tell the service the next time there is
10665 // a new client.
10666 b.doRebind = true;
10667 }
10668 }
10669
10670 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10671
10672 Binder.restoreCallingIdentity(origId);
10673 }
10674 }
10675 }
10676
10677 public void serviceDoneExecuting(IBinder token) {
10678 synchronized(this) {
10679 if (!(token instanceof ServiceRecord)) {
10680 throw new IllegalArgumentException("Invalid service token");
10681 }
10682 ServiceRecord r = (ServiceRecord)token;
10683 boolean inStopping = mStoppingServices.contains(token);
10684 if (r != null) {
10685 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10686 + ": nesting=" + r.executeNesting
10687 + ", inStopping=" + inStopping);
10688 if (r != token) {
10689 Log.w(TAG, "Done executing service " + r.name
10690 + " with incorrect token: given " + token
10691 + ", expected " + r);
10692 return;
10693 }
10694
10695 final long origId = Binder.clearCallingIdentity();
10696 serviceDoneExecutingLocked(r, inStopping);
10697 Binder.restoreCallingIdentity(origId);
10698 } else {
10699 Log.w(TAG, "Done executing unknown service " + r.name
10700 + " with token " + token);
10701 }
10702 }
10703 }
10704
10705 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10706 r.executeNesting--;
10707 if (r.executeNesting <= 0 && r.app != null) {
10708 r.app.executingServices.remove(r);
10709 if (r.app.executingServices.size() == 0) {
10710 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10711 }
10712 if (inStopping) {
10713 mStoppingServices.remove(r);
10714 }
10715 updateOomAdjLocked(r.app);
10716 }
10717 }
10718
10719 void serviceTimeout(ProcessRecord proc) {
10720 synchronized(this) {
10721 if (proc.executingServices.size() == 0 || proc.thread == null) {
10722 return;
10723 }
10724 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10725 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10726 ServiceRecord timeout = null;
10727 long nextTime = 0;
10728 while (it.hasNext()) {
10729 ServiceRecord sr = it.next();
10730 if (sr.executingStart < maxTime) {
10731 timeout = sr;
10732 break;
10733 }
10734 if (sr.executingStart > nextTime) {
10735 nextTime = sr.executingStart;
10736 }
10737 }
10738 if (timeout != null && mLRUProcesses.contains(proc)) {
10739 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070010740 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010741 + timeout.name);
10742 } else {
10743 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10744 msg.obj = proc;
10745 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10746 }
10747 }
10748 }
10749
10750 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010751 // BACKUP AND RESTORE
10752 // =========================================================
10753
10754 // Cause the target app to be launched if necessary and its backup agent
10755 // instantiated. The backup agent will invoke backupAgentCreated() on the
10756 // activity manager to announce its creation.
10757 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10758 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10759 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10760
10761 synchronized(this) {
10762 // !!! TODO: currently no check here that we're already bound
10763 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10764 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10765 synchronized (stats) {
10766 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10767 }
10768
10769 BackupRecord r = new BackupRecord(ss, app, backupMode);
10770 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10771 // startProcessLocked() returns existing proc's record if it's already running
10772 ProcessRecord proc = startProcessLocked(app.processName, app,
10773 false, 0, "backup", hostingName);
10774 if (proc == null) {
10775 Log.e(TAG, "Unable to start backup agent process " + r);
10776 return false;
10777 }
10778
10779 r.app = proc;
10780 mBackupTarget = r;
10781 mBackupAppName = app.packageName;
10782
Christopher Tate6fa95972009-06-05 18:43:55 -070010783 // Try not to kill the process during backup
10784 updateOomAdjLocked(proc);
10785
Christopher Tate181fafa2009-05-14 11:12:14 -070010786 // If the process is already attached, schedule the creation of the backup agent now.
10787 // If it is not yet live, this will be done when it attaches to the framework.
10788 if (proc.thread != null) {
10789 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10790 try {
10791 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10792 } catch (RemoteException e) {
10793 // !!! TODO: notify the backup manager that we crashed, or rely on
10794 // death notices, or...?
10795 }
10796 } else {
10797 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10798 }
10799 // Invariants: at this point, the target app process exists and the application
10800 // is either already running or in the process of coming up. mBackupTarget and
10801 // mBackupAppName describe the app, so that when it binds back to the AM we
10802 // know that it's scheduled for a backup-agent operation.
10803 }
10804
10805 return true;
10806 }
10807
10808 // A backup agent has just come up
10809 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10810 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10811 + " = " + agent);
10812
10813 synchronized(this) {
10814 if (!agentPackageName.equals(mBackupAppName)) {
10815 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10816 return;
10817 }
10818
Christopher Tate043dadc2009-06-02 16:11:00 -070010819 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010820 try {
10821 IBackupManager bm = IBackupManager.Stub.asInterface(
10822 ServiceManager.getService(Context.BACKUP_SERVICE));
10823 bm.agentConnected(agentPackageName, agent);
10824 } catch (RemoteException e) {
10825 // can't happen; the backup manager service is local
10826 } catch (Exception e) {
10827 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10828 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010829 } finally {
10830 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010831 }
10832 }
10833 }
10834
10835 // done with this agent
10836 public void unbindBackupAgent(ApplicationInfo appInfo) {
10837 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010838 if (appInfo == null) {
10839 Log.w(TAG, "unbind backup agent for null app");
10840 return;
10841 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010842
10843 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010844 if (mBackupAppName == null) {
10845 Log.w(TAG, "Unbinding backup agent with no active backup");
10846 return;
10847 }
10848
Christopher Tate181fafa2009-05-14 11:12:14 -070010849 if (!mBackupAppName.equals(appInfo.packageName)) {
10850 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10851 return;
10852 }
10853
Christopher Tate6fa95972009-06-05 18:43:55 -070010854 ProcessRecord proc = mBackupTarget.app;
10855 mBackupTarget = null;
10856 mBackupAppName = null;
10857
10858 // Not backing this app up any more; reset its OOM adjustment
10859 updateOomAdjLocked(proc);
10860
Christopher Tatec7b31e32009-06-10 15:49:30 -070010861 // If the app crashed during backup, 'thread' will be null here
10862 if (proc.thread != null) {
10863 try {
10864 proc.thread.scheduleDestroyBackupAgent(appInfo);
10865 } catch (Exception e) {
10866 Log.e(TAG, "Exception when unbinding backup agent:");
10867 e.printStackTrace();
10868 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010869 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010870 }
10871 }
10872 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010873 // BROADCASTS
10874 // =========================================================
10875
10876 private final List getStickies(String action, IntentFilter filter,
10877 List cur) {
10878 final ContentResolver resolver = mContext.getContentResolver();
10879 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10880 if (list == null) {
10881 return cur;
10882 }
10883 int N = list.size();
10884 for (int i=0; i<N; i++) {
10885 Intent intent = list.get(i);
10886 if (filter.match(resolver, intent, true, TAG) >= 0) {
10887 if (cur == null) {
10888 cur = new ArrayList<Intent>();
10889 }
10890 cur.add(intent);
10891 }
10892 }
10893 return cur;
10894 }
10895
10896 private final void scheduleBroadcastsLocked() {
10897 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10898 + mBroadcastsScheduled);
10899
10900 if (mBroadcastsScheduled) {
10901 return;
10902 }
10903 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10904 mBroadcastsScheduled = true;
10905 }
10906
10907 public Intent registerReceiver(IApplicationThread caller,
10908 IIntentReceiver receiver, IntentFilter filter, String permission) {
10909 synchronized(this) {
10910 ProcessRecord callerApp = null;
10911 if (caller != null) {
10912 callerApp = getRecordForAppLocked(caller);
10913 if (callerApp == null) {
10914 throw new SecurityException(
10915 "Unable to find app for caller " + caller
10916 + " (pid=" + Binder.getCallingPid()
10917 + ") when registering receiver " + receiver);
10918 }
10919 }
10920
10921 List allSticky = null;
10922
10923 // Look for any matching sticky broadcasts...
10924 Iterator actions = filter.actionsIterator();
10925 if (actions != null) {
10926 while (actions.hasNext()) {
10927 String action = (String)actions.next();
10928 allSticky = getStickies(action, filter, allSticky);
10929 }
10930 } else {
10931 allSticky = getStickies(null, filter, allSticky);
10932 }
10933
10934 // The first sticky in the list is returned directly back to
10935 // the client.
10936 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10937
10938 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10939 + ": " + sticky);
10940
10941 if (receiver == null) {
10942 return sticky;
10943 }
10944
10945 ReceiverList rl
10946 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10947 if (rl == null) {
10948 rl = new ReceiverList(this, callerApp,
10949 Binder.getCallingPid(),
10950 Binder.getCallingUid(), receiver);
10951 if (rl.app != null) {
10952 rl.app.receivers.add(rl);
10953 } else {
10954 try {
10955 receiver.asBinder().linkToDeath(rl, 0);
10956 } catch (RemoteException e) {
10957 return sticky;
10958 }
10959 rl.linkedToDeath = true;
10960 }
10961 mRegisteredReceivers.put(receiver.asBinder(), rl);
10962 }
10963 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10964 rl.add(bf);
10965 if (!bf.debugCheck()) {
10966 Log.w(TAG, "==> For Dynamic broadast");
10967 }
10968 mReceiverResolver.addFilter(bf);
10969
10970 // Enqueue broadcasts for all existing stickies that match
10971 // this filter.
10972 if (allSticky != null) {
10973 ArrayList receivers = new ArrayList();
10974 receivers.add(bf);
10975
10976 int N = allSticky.size();
10977 for (int i=0; i<N; i++) {
10978 Intent intent = (Intent)allSticky.get(i);
10979 BroadcastRecord r = new BroadcastRecord(intent, null,
10980 null, -1, -1, null, receivers, null, 0, null, null,
10981 false);
10982 if (mParallelBroadcasts.size() == 0) {
10983 scheduleBroadcastsLocked();
10984 }
10985 mParallelBroadcasts.add(r);
10986 }
10987 }
10988
10989 return sticky;
10990 }
10991 }
10992
10993 public void unregisterReceiver(IIntentReceiver receiver) {
10994 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10995
10996 boolean doNext = false;
10997
10998 synchronized(this) {
10999 ReceiverList rl
11000 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11001 if (rl != null) {
11002 if (rl.curBroadcast != null) {
11003 BroadcastRecord r = rl.curBroadcast;
11004 doNext = finishReceiverLocked(
11005 receiver.asBinder(), r.resultCode, r.resultData,
11006 r.resultExtras, r.resultAbort, true);
11007 }
11008
11009 if (rl.app != null) {
11010 rl.app.receivers.remove(rl);
11011 }
11012 removeReceiverLocked(rl);
11013 if (rl.linkedToDeath) {
11014 rl.linkedToDeath = false;
11015 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11016 }
11017 }
11018 }
11019
11020 if (!doNext) {
11021 return;
11022 }
11023
11024 final long origId = Binder.clearCallingIdentity();
11025 processNextBroadcast(false);
11026 trimApplications();
11027 Binder.restoreCallingIdentity(origId);
11028 }
11029
11030 void removeReceiverLocked(ReceiverList rl) {
11031 mRegisteredReceivers.remove(rl.receiver.asBinder());
11032 int N = rl.size();
11033 for (int i=0; i<N; i++) {
11034 mReceiverResolver.removeFilter(rl.get(i));
11035 }
11036 }
11037
11038 private final int broadcastIntentLocked(ProcessRecord callerApp,
11039 String callerPackage, Intent intent, String resolvedType,
11040 IIntentReceiver resultTo, int resultCode, String resultData,
11041 Bundle map, String requiredPermission,
11042 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11043 intent = new Intent(intent);
11044
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011045 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011046 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11047 + " ordered=" + ordered);
11048 if ((resultTo != null) && !ordered) {
11049 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11050 }
11051
11052 // Handle special intents: if this broadcast is from the package
11053 // manager about a package being removed, we need to remove all of
11054 // its activities from the history stack.
11055 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11056 intent.getAction());
11057 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11058 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11059 || uidRemoved) {
11060 if (checkComponentPermission(
11061 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11062 callingPid, callingUid, -1)
11063 == PackageManager.PERMISSION_GRANTED) {
11064 if (uidRemoved) {
11065 final Bundle intentExtras = intent.getExtras();
11066 final int uid = intentExtras != null
11067 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11068 if (uid >= 0) {
11069 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11070 synchronized (bs) {
11071 bs.removeUidStatsLocked(uid);
11072 }
11073 }
11074 } else {
11075 Uri data = intent.getData();
11076 String ssp;
11077 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11078 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11079 uninstallPackageLocked(ssp,
11080 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011081 AttributeCache ac = AttributeCache.instance();
11082 if (ac != null) {
11083 ac.removePackage(ssp);
11084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011085 }
11086 }
11087 }
11088 } else {
11089 String msg = "Permission Denial: " + intent.getAction()
11090 + " broadcast from " + callerPackage + " (pid=" + callingPid
11091 + ", uid=" + callingUid + ")"
11092 + " requires "
11093 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11094 Log.w(TAG, msg);
11095 throw new SecurityException(msg);
11096 }
11097 }
11098
11099 /*
11100 * If this is the time zone changed action, queue up a message that will reset the timezone
11101 * of all currently running processes. This message will get queued up before the broadcast
11102 * happens.
11103 */
11104 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11105 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11106 }
11107
Dianne Hackborn854060af2009-07-09 18:14:31 -070011108 /*
11109 * Prevent non-system code (defined here to be non-persistent
11110 * processes) from sending protected broadcasts.
11111 */
11112 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11113 || callingUid == Process.SHELL_UID || callingUid == 0) {
11114 // Always okay.
11115 } else if (callerApp == null || !callerApp.persistent) {
11116 try {
11117 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11118 intent.getAction())) {
11119 String msg = "Permission Denial: not allowed to send broadcast "
11120 + intent.getAction() + " from pid="
11121 + callingPid + ", uid=" + callingUid;
11122 Log.w(TAG, msg);
11123 throw new SecurityException(msg);
11124 }
11125 } catch (RemoteException e) {
11126 Log.w(TAG, "Remote exception", e);
11127 return BROADCAST_SUCCESS;
11128 }
11129 }
11130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011131 // Add to the sticky list if requested.
11132 if (sticky) {
11133 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11134 callingPid, callingUid)
11135 != PackageManager.PERMISSION_GRANTED) {
11136 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11137 + callingPid + ", uid=" + callingUid
11138 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11139 Log.w(TAG, msg);
11140 throw new SecurityException(msg);
11141 }
11142 if (requiredPermission != null) {
11143 Log.w(TAG, "Can't broadcast sticky intent " + intent
11144 + " and enforce permission " + requiredPermission);
11145 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11146 }
11147 if (intent.getComponent() != null) {
11148 throw new SecurityException(
11149 "Sticky broadcasts can't target a specific component");
11150 }
11151 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11152 if (list == null) {
11153 list = new ArrayList<Intent>();
11154 mStickyBroadcasts.put(intent.getAction(), list);
11155 }
11156 int N = list.size();
11157 int i;
11158 for (i=0; i<N; i++) {
11159 if (intent.filterEquals(list.get(i))) {
11160 // This sticky already exists, replace it.
11161 list.set(i, new Intent(intent));
11162 break;
11163 }
11164 }
11165 if (i >= N) {
11166 list.add(new Intent(intent));
11167 }
11168 }
11169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011170 // Figure out who all will receive this broadcast.
11171 List receivers = null;
11172 List<BroadcastFilter> registeredReceivers = null;
11173 try {
11174 if (intent.getComponent() != null) {
11175 // Broadcast is going to one specific receiver class...
11176 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011177 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011178 if (ai != null) {
11179 receivers = new ArrayList();
11180 ResolveInfo ri = new ResolveInfo();
11181 ri.activityInfo = ai;
11182 receivers.add(ri);
11183 }
11184 } else {
11185 // Need to resolve the intent to interested receivers...
11186 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11187 == 0) {
11188 receivers =
11189 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011190 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011191 }
Mihai Preda074edef2009-05-18 17:13:31 +020011192 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011193 }
11194 } catch (RemoteException ex) {
11195 // pm is in same process, this will never happen.
11196 }
11197
11198 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11199 if (!ordered && NR > 0) {
11200 // If we are not serializing this broadcast, then send the
11201 // registered receivers separately so they don't wait for the
11202 // components to be launched.
11203 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11204 callerPackage, callingPid, callingUid, requiredPermission,
11205 registeredReceivers, resultTo, resultCode, resultData, map,
11206 ordered);
11207 if (DEBUG_BROADCAST) Log.v(
11208 TAG, "Enqueueing parallel broadcast " + r
11209 + ": prev had " + mParallelBroadcasts.size());
11210 mParallelBroadcasts.add(r);
11211 scheduleBroadcastsLocked();
11212 registeredReceivers = null;
11213 NR = 0;
11214 }
11215
11216 // Merge into one list.
11217 int ir = 0;
11218 if (receivers != null) {
11219 // A special case for PACKAGE_ADDED: do not allow the package
11220 // being added to see this broadcast. This prevents them from
11221 // using this as a back door to get run as soon as they are
11222 // installed. Maybe in the future we want to have a special install
11223 // broadcast or such for apps, but we'd like to deliberately make
11224 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011225 boolean skip = false;
11226 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011227 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011228 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11229 skip = true;
11230 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11231 skip = true;
11232 }
11233 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011234 ? intent.getData().getSchemeSpecificPart()
11235 : null;
11236 if (skipPackage != null && receivers != null) {
11237 int NT = receivers.size();
11238 for (int it=0; it<NT; it++) {
11239 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11240 if (curt.activityInfo.packageName.equals(skipPackage)) {
11241 receivers.remove(it);
11242 it--;
11243 NT--;
11244 }
11245 }
11246 }
11247
11248 int NT = receivers != null ? receivers.size() : 0;
11249 int it = 0;
11250 ResolveInfo curt = null;
11251 BroadcastFilter curr = null;
11252 while (it < NT && ir < NR) {
11253 if (curt == null) {
11254 curt = (ResolveInfo)receivers.get(it);
11255 }
11256 if (curr == null) {
11257 curr = registeredReceivers.get(ir);
11258 }
11259 if (curr.getPriority() >= curt.priority) {
11260 // Insert this broadcast record into the final list.
11261 receivers.add(it, curr);
11262 ir++;
11263 curr = null;
11264 it++;
11265 NT++;
11266 } else {
11267 // Skip to the next ResolveInfo in the final list.
11268 it++;
11269 curt = null;
11270 }
11271 }
11272 }
11273 while (ir < NR) {
11274 if (receivers == null) {
11275 receivers = new ArrayList();
11276 }
11277 receivers.add(registeredReceivers.get(ir));
11278 ir++;
11279 }
11280
11281 if ((receivers != null && receivers.size() > 0)
11282 || resultTo != null) {
11283 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11284 callerPackage, callingPid, callingUid, requiredPermission,
11285 receivers, resultTo, resultCode, resultData, map, ordered);
11286 if (DEBUG_BROADCAST) Log.v(
11287 TAG, "Enqueueing ordered broadcast " + r
11288 + ": prev had " + mOrderedBroadcasts.size());
11289 if (DEBUG_BROADCAST) {
11290 int seq = r.intent.getIntExtra("seq", -1);
11291 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11292 }
11293 mOrderedBroadcasts.add(r);
11294 scheduleBroadcastsLocked();
11295 }
11296
11297 return BROADCAST_SUCCESS;
11298 }
11299
11300 public final int broadcastIntent(IApplicationThread caller,
11301 Intent intent, String resolvedType, IIntentReceiver resultTo,
11302 int resultCode, String resultData, Bundle map,
11303 String requiredPermission, boolean serialized, boolean sticky) {
11304 // Refuse possible leaked file descriptors
11305 if (intent != null && intent.hasFileDescriptors() == true) {
11306 throw new IllegalArgumentException("File descriptors passed in Intent");
11307 }
11308
11309 synchronized(this) {
11310 if (!mSystemReady) {
11311 // if the caller really truly claims to know what they're doing, go
11312 // ahead and allow the broadcast without launching any receivers
11313 int flags = intent.getFlags();
11314 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11315 intent = new Intent(intent);
11316 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11317 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11318 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11319 + " before boot completion");
11320 throw new IllegalStateException("Cannot broadcast before boot completed");
11321 }
11322 }
11323
11324 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11325 final int callingPid = Binder.getCallingPid();
11326 final int callingUid = Binder.getCallingUid();
11327 final long origId = Binder.clearCallingIdentity();
11328 int res = broadcastIntentLocked(callerApp,
11329 callerApp != null ? callerApp.info.packageName : null,
11330 intent, resolvedType, resultTo,
11331 resultCode, resultData, map, requiredPermission, serialized,
11332 sticky, callingPid, callingUid);
11333 Binder.restoreCallingIdentity(origId);
11334 return res;
11335 }
11336 }
11337
11338 int broadcastIntentInPackage(String packageName, int uid,
11339 Intent intent, String resolvedType, IIntentReceiver resultTo,
11340 int resultCode, String resultData, Bundle map,
11341 String requiredPermission, boolean serialized, boolean sticky) {
11342 synchronized(this) {
11343 final long origId = Binder.clearCallingIdentity();
11344 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11345 resultTo, resultCode, resultData, map, requiredPermission,
11346 serialized, sticky, -1, uid);
11347 Binder.restoreCallingIdentity(origId);
11348 return res;
11349 }
11350 }
11351
11352 public final void unbroadcastIntent(IApplicationThread caller,
11353 Intent intent) {
11354 // Refuse possible leaked file descriptors
11355 if (intent != null && intent.hasFileDescriptors() == true) {
11356 throw new IllegalArgumentException("File descriptors passed in Intent");
11357 }
11358
11359 synchronized(this) {
11360 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11361 != PackageManager.PERMISSION_GRANTED) {
11362 String msg = "Permission Denial: unbroadcastIntent() from pid="
11363 + Binder.getCallingPid()
11364 + ", uid=" + Binder.getCallingUid()
11365 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11366 Log.w(TAG, msg);
11367 throw new SecurityException(msg);
11368 }
11369 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11370 if (list != null) {
11371 int N = list.size();
11372 int i;
11373 for (i=0; i<N; i++) {
11374 if (intent.filterEquals(list.get(i))) {
11375 list.remove(i);
11376 break;
11377 }
11378 }
11379 }
11380 }
11381 }
11382
11383 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11384 String resultData, Bundle resultExtras, boolean resultAbort,
11385 boolean explicit) {
11386 if (mOrderedBroadcasts.size() == 0) {
11387 if (explicit) {
11388 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11389 }
11390 return false;
11391 }
11392 BroadcastRecord r = mOrderedBroadcasts.get(0);
11393 if (r.receiver == null) {
11394 if (explicit) {
11395 Log.w(TAG, "finishReceiver called but none active");
11396 }
11397 return false;
11398 }
11399 if (r.receiver != receiver) {
11400 Log.w(TAG, "finishReceiver called but active receiver is different");
11401 return false;
11402 }
11403 int state = r.state;
11404 r.state = r.IDLE;
11405 if (state == r.IDLE) {
11406 if (explicit) {
11407 Log.w(TAG, "finishReceiver called but state is IDLE");
11408 }
11409 }
11410 r.receiver = null;
11411 r.intent.setComponent(null);
11412 if (r.curApp != null) {
11413 r.curApp.curReceiver = null;
11414 }
11415 if (r.curFilter != null) {
11416 r.curFilter.receiverList.curBroadcast = null;
11417 }
11418 r.curFilter = null;
11419 r.curApp = null;
11420 r.curComponent = null;
11421 r.curReceiver = null;
11422 mPendingBroadcast = null;
11423
11424 r.resultCode = resultCode;
11425 r.resultData = resultData;
11426 r.resultExtras = resultExtras;
11427 r.resultAbort = resultAbort;
11428
11429 // We will process the next receiver right now if this is finishing
11430 // an app receiver (which is always asynchronous) or after we have
11431 // come back from calling a receiver.
11432 return state == BroadcastRecord.APP_RECEIVE
11433 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11434 }
11435
11436 public void finishReceiver(IBinder who, int resultCode, String resultData,
11437 Bundle resultExtras, boolean resultAbort) {
11438 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11439
11440 // Refuse possible leaked file descriptors
11441 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11442 throw new IllegalArgumentException("File descriptors passed in Bundle");
11443 }
11444
11445 boolean doNext;
11446
11447 final long origId = Binder.clearCallingIdentity();
11448
11449 synchronized(this) {
11450 doNext = finishReceiverLocked(
11451 who, resultCode, resultData, resultExtras, resultAbort, true);
11452 }
11453
11454 if (doNext) {
11455 processNextBroadcast(false);
11456 }
11457 trimApplications();
11458
11459 Binder.restoreCallingIdentity(origId);
11460 }
11461
11462 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11463 if (r.nextReceiver > 0) {
11464 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11465 if (curReceiver instanceof BroadcastFilter) {
11466 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11467 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11468 System.identityHashCode(r),
11469 r.intent.getAction(),
11470 r.nextReceiver - 1,
11471 System.identityHashCode(bf));
11472 } else {
11473 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11474 System.identityHashCode(r),
11475 r.intent.getAction(),
11476 r.nextReceiver - 1,
11477 ((ResolveInfo)curReceiver).toString());
11478 }
11479 } else {
11480 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11481 + r);
11482 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11483 System.identityHashCode(r),
11484 r.intent.getAction(),
11485 r.nextReceiver,
11486 "NONE");
11487 }
11488 }
11489
11490 private final void broadcastTimeout() {
11491 synchronized (this) {
11492 if (mOrderedBroadcasts.size() == 0) {
11493 return;
11494 }
11495 long now = SystemClock.uptimeMillis();
11496 BroadcastRecord r = mOrderedBroadcasts.get(0);
11497 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11498 if (DEBUG_BROADCAST) Log.v(TAG,
11499 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11500 + (r.startTime + BROADCAST_TIMEOUT));
11501 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11502 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11503 return;
11504 }
11505
11506 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11507 r.startTime = now;
11508 r.anrCount++;
11509
11510 // Current receiver has passed its expiration date.
11511 if (r.nextReceiver <= 0) {
11512 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11513 return;
11514 }
11515
11516 ProcessRecord app = null;
11517
11518 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11519 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11520 logBroadcastReceiverDiscard(r);
11521 if (curReceiver instanceof BroadcastFilter) {
11522 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11523 if (bf.receiverList.pid != 0
11524 && bf.receiverList.pid != MY_PID) {
11525 synchronized (this.mPidsSelfLocked) {
11526 app = this.mPidsSelfLocked.get(
11527 bf.receiverList.pid);
11528 }
11529 }
11530 } else {
11531 app = r.curApp;
11532 }
11533
11534 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011535 appNotRespondingLocked(app, null, null,
11536 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011537 }
11538
11539 if (mPendingBroadcast == r) {
11540 mPendingBroadcast = null;
11541 }
11542
11543 // Move on to the next receiver.
11544 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11545 r.resultExtras, r.resultAbort, true);
11546 scheduleBroadcastsLocked();
11547 }
11548 }
11549
11550 private final void processCurBroadcastLocked(BroadcastRecord r,
11551 ProcessRecord app) throws RemoteException {
11552 if (app.thread == null) {
11553 throw new RemoteException();
11554 }
11555 r.receiver = app.thread.asBinder();
11556 r.curApp = app;
11557 app.curReceiver = r;
11558 updateLRUListLocked(app, true);
11559
11560 // Tell the application to launch this receiver.
11561 r.intent.setComponent(r.curComponent);
11562
11563 boolean started = false;
11564 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011565 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011566 "Delivering to component " + r.curComponent
11567 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011568 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011569 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11570 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11571 started = true;
11572 } finally {
11573 if (!started) {
11574 r.receiver = null;
11575 r.curApp = null;
11576 app.curReceiver = null;
11577 }
11578 }
11579
11580 }
11581
11582 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11583 Intent intent, int resultCode, String data,
11584 Bundle extras, boolean ordered) throws RemoteException {
11585 if (app != null && app.thread != null) {
11586 // If we have an app thread, do the call through that so it is
11587 // correctly ordered with other one-way calls.
11588 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11589 data, extras, ordered);
11590 } else {
11591 receiver.performReceive(intent, resultCode, data, extras, ordered);
11592 }
11593 }
11594
11595 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11596 BroadcastFilter filter, boolean ordered) {
11597 boolean skip = false;
11598 if (filter.requiredPermission != null) {
11599 int perm = checkComponentPermission(filter.requiredPermission,
11600 r.callingPid, r.callingUid, -1);
11601 if (perm != PackageManager.PERMISSION_GRANTED) {
11602 Log.w(TAG, "Permission Denial: broadcasting "
11603 + r.intent.toString()
11604 + " from " + r.callerPackage + " (pid="
11605 + r.callingPid + ", uid=" + r.callingUid + ")"
11606 + " requires " + filter.requiredPermission
11607 + " due to registered receiver " + filter);
11608 skip = true;
11609 }
11610 }
11611 if (r.requiredPermission != null) {
11612 int perm = checkComponentPermission(r.requiredPermission,
11613 filter.receiverList.pid, filter.receiverList.uid, -1);
11614 if (perm != PackageManager.PERMISSION_GRANTED) {
11615 Log.w(TAG, "Permission Denial: receiving "
11616 + r.intent.toString()
11617 + " to " + filter.receiverList.app
11618 + " (pid=" + filter.receiverList.pid
11619 + ", uid=" + filter.receiverList.uid + ")"
11620 + " requires " + r.requiredPermission
11621 + " due to sender " + r.callerPackage
11622 + " (uid " + r.callingUid + ")");
11623 skip = true;
11624 }
11625 }
11626
11627 if (!skip) {
11628 // If this is not being sent as an ordered broadcast, then we
11629 // don't want to touch the fields that keep track of the current
11630 // state of ordered broadcasts.
11631 if (ordered) {
11632 r.receiver = filter.receiverList.receiver.asBinder();
11633 r.curFilter = filter;
11634 filter.receiverList.curBroadcast = r;
11635 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011636 if (filter.receiverList.app != null) {
11637 // Bump hosting application to no longer be in background
11638 // scheduling class. Note that we can't do that if there
11639 // isn't an app... but we can only be in that case for
11640 // things that directly call the IActivityManager API, which
11641 // are already core system stuff so don't matter for this.
11642 r.curApp = filter.receiverList.app;
11643 filter.receiverList.app.curReceiver = r;
11644 updateOomAdjLocked();
11645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011646 }
11647 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011648 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011649 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011650 Log.i(TAG, "Delivering to " + filter.receiverList.app
11651 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011652 }
11653 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11654 new Intent(r.intent), r.resultCode,
11655 r.resultData, r.resultExtras, r.ordered);
11656 if (ordered) {
11657 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11658 }
11659 } catch (RemoteException e) {
11660 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11661 if (ordered) {
11662 r.receiver = null;
11663 r.curFilter = null;
11664 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011665 if (filter.receiverList.app != null) {
11666 filter.receiverList.app.curReceiver = null;
11667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011668 }
11669 }
11670 }
11671 }
11672
11673 private final void processNextBroadcast(boolean fromMsg) {
11674 synchronized(this) {
11675 BroadcastRecord r;
11676
11677 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11678 + mParallelBroadcasts.size() + " broadcasts, "
11679 + mOrderedBroadcasts.size() + " serialized broadcasts");
11680
11681 updateCpuStats();
11682
11683 if (fromMsg) {
11684 mBroadcastsScheduled = false;
11685 }
11686
11687 // First, deliver any non-serialized broadcasts right away.
11688 while (mParallelBroadcasts.size() > 0) {
11689 r = mParallelBroadcasts.remove(0);
11690 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011691 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11692 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011693 for (int i=0; i<N; i++) {
11694 Object target = r.receivers.get(i);
11695 if (DEBUG_BROADCAST) Log.v(TAG,
11696 "Delivering non-serialized to registered "
11697 + target + ": " + r);
11698 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11699 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011700 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11701 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011702 }
11703
11704 // Now take care of the next serialized one...
11705
11706 // If we are waiting for a process to come up to handle the next
11707 // broadcast, then do nothing at this point. Just in case, we
11708 // check that the process we're waiting for still exists.
11709 if (mPendingBroadcast != null) {
11710 Log.i(TAG, "processNextBroadcast: waiting for "
11711 + mPendingBroadcast.curApp);
11712
11713 boolean isDead;
11714 synchronized (mPidsSelfLocked) {
11715 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11716 }
11717 if (!isDead) {
11718 // It's still alive, so keep waiting
11719 return;
11720 } else {
11721 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11722 + " died before responding to broadcast");
11723 mPendingBroadcast = null;
11724 }
11725 }
11726
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011727 boolean looped = false;
11728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011729 do {
11730 if (mOrderedBroadcasts.size() == 0) {
11731 // No more broadcasts pending, so all done!
11732 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011733 if (looped) {
11734 // If we had finished the last ordered broadcast, then
11735 // make sure all processes have correct oom and sched
11736 // adjustments.
11737 updateOomAdjLocked();
11738 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011739 return;
11740 }
11741 r = mOrderedBroadcasts.get(0);
11742 boolean forceReceive = false;
11743
11744 // Ensure that even if something goes awry with the timeout
11745 // detection, we catch "hung" broadcasts here, discard them,
11746 // and continue to make progress.
11747 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11748 long now = SystemClock.uptimeMillis();
11749 if (r.dispatchTime > 0) {
11750 if ((numReceivers > 0) &&
11751 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11752 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11753 + " now=" + now
11754 + " dispatchTime=" + r.dispatchTime
11755 + " startTime=" + r.startTime
11756 + " intent=" + r.intent
11757 + " numReceivers=" + numReceivers
11758 + " nextReceiver=" + r.nextReceiver
11759 + " state=" + r.state);
11760 broadcastTimeout(); // forcibly finish this broadcast
11761 forceReceive = true;
11762 r.state = BroadcastRecord.IDLE;
11763 }
11764 }
11765
11766 if (r.state != BroadcastRecord.IDLE) {
11767 if (DEBUG_BROADCAST) Log.d(TAG,
11768 "processNextBroadcast() called when not idle (state="
11769 + r.state + ")");
11770 return;
11771 }
11772
11773 if (r.receivers == null || r.nextReceiver >= numReceivers
11774 || r.resultAbort || forceReceive) {
11775 // No more receivers for this broadcast! Send the final
11776 // result if requested...
11777 if (r.resultTo != null) {
11778 try {
11779 if (DEBUG_BROADCAST) {
11780 int seq = r.intent.getIntExtra("seq", -1);
11781 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11782 + " seq=" + seq + " app=" + r.callerApp);
11783 }
11784 performReceive(r.callerApp, r.resultTo,
11785 new Intent(r.intent), r.resultCode,
11786 r.resultData, r.resultExtras, false);
11787 } catch (RemoteException e) {
11788 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11789 }
11790 }
11791
11792 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11793 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11794
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011795 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11796 + r);
11797
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011798 // ... and on to the next...
11799 mOrderedBroadcasts.remove(0);
11800 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011801 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011802 continue;
11803 }
11804 } while (r == null);
11805
11806 // Get the next receiver...
11807 int recIdx = r.nextReceiver++;
11808
11809 // Keep track of when this receiver started, and make sure there
11810 // is a timeout message pending to kill it if need be.
11811 r.startTime = SystemClock.uptimeMillis();
11812 if (recIdx == 0) {
11813 r.dispatchTime = r.startTime;
11814
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011815 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11816 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011817 if (DEBUG_BROADCAST) Log.v(TAG,
11818 "Submitting BROADCAST_TIMEOUT_MSG for "
11819 + (r.startTime + BROADCAST_TIMEOUT));
11820 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11821 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11822 }
11823
11824 Object nextReceiver = r.receivers.get(recIdx);
11825 if (nextReceiver instanceof BroadcastFilter) {
11826 // Simple case: this is a registered receiver who gets
11827 // a direct call.
11828 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11829 if (DEBUG_BROADCAST) Log.v(TAG,
11830 "Delivering serialized to registered "
11831 + filter + ": " + r);
11832 deliverToRegisteredReceiver(r, filter, r.ordered);
11833 if (r.receiver == null || !r.ordered) {
11834 // The receiver has already finished, so schedule to
11835 // process the next one.
11836 r.state = BroadcastRecord.IDLE;
11837 scheduleBroadcastsLocked();
11838 }
11839 return;
11840 }
11841
11842 // Hard case: need to instantiate the receiver, possibly
11843 // starting its application process to host it.
11844
11845 ResolveInfo info =
11846 (ResolveInfo)nextReceiver;
11847
11848 boolean skip = false;
11849 int perm = checkComponentPermission(info.activityInfo.permission,
11850 r.callingPid, r.callingUid,
11851 info.activityInfo.exported
11852 ? -1 : info.activityInfo.applicationInfo.uid);
11853 if (perm != PackageManager.PERMISSION_GRANTED) {
11854 Log.w(TAG, "Permission Denial: broadcasting "
11855 + r.intent.toString()
11856 + " from " + r.callerPackage + " (pid=" + r.callingPid
11857 + ", uid=" + r.callingUid + ")"
11858 + " requires " + info.activityInfo.permission
11859 + " due to receiver " + info.activityInfo.packageName
11860 + "/" + info.activityInfo.name);
11861 skip = true;
11862 }
11863 if (r.callingUid != Process.SYSTEM_UID &&
11864 r.requiredPermission != null) {
11865 try {
11866 perm = ActivityThread.getPackageManager().
11867 checkPermission(r.requiredPermission,
11868 info.activityInfo.applicationInfo.packageName);
11869 } catch (RemoteException e) {
11870 perm = PackageManager.PERMISSION_DENIED;
11871 }
11872 if (perm != PackageManager.PERMISSION_GRANTED) {
11873 Log.w(TAG, "Permission Denial: receiving "
11874 + r.intent + " to "
11875 + info.activityInfo.applicationInfo.packageName
11876 + " requires " + r.requiredPermission
11877 + " due to sender " + r.callerPackage
11878 + " (uid " + r.callingUid + ")");
11879 skip = true;
11880 }
11881 }
11882 if (r.curApp != null && r.curApp.crashing) {
11883 // If the target process is crashing, just skip it.
11884 skip = true;
11885 }
11886
11887 if (skip) {
11888 r.receiver = null;
11889 r.curFilter = null;
11890 r.state = BroadcastRecord.IDLE;
11891 scheduleBroadcastsLocked();
11892 return;
11893 }
11894
11895 r.state = BroadcastRecord.APP_RECEIVE;
11896 String targetProcess = info.activityInfo.processName;
11897 r.curComponent = new ComponentName(
11898 info.activityInfo.applicationInfo.packageName,
11899 info.activityInfo.name);
11900 r.curReceiver = info.activityInfo;
11901
11902 // Is this receiver's application already running?
11903 ProcessRecord app = getProcessRecordLocked(targetProcess,
11904 info.activityInfo.applicationInfo.uid);
11905 if (app != null && app.thread != null) {
11906 try {
11907 processCurBroadcastLocked(r, app);
11908 return;
11909 } catch (RemoteException e) {
11910 Log.w(TAG, "Exception when sending broadcast to "
11911 + r.curComponent, e);
11912 }
11913
11914 // If a dead object exception was thrown -- fall through to
11915 // restart the application.
11916 }
11917
11918 // Not running -- get it started, and enqueue this history record
11919 // to be executed when the app comes up.
11920 if ((r.curApp=startProcessLocked(targetProcess,
11921 info.activityInfo.applicationInfo, true,
11922 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11923 "broadcast", r.curComponent)) == null) {
11924 // Ah, this recipient is unavailable. Finish it if necessary,
11925 // and mark the broadcast record as ready for the next.
11926 Log.w(TAG, "Unable to launch app "
11927 + info.activityInfo.applicationInfo.packageName + "/"
11928 + info.activityInfo.applicationInfo.uid + " for broadcast "
11929 + r.intent + ": process is bad");
11930 logBroadcastReceiverDiscard(r);
11931 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11932 r.resultExtras, r.resultAbort, true);
11933 scheduleBroadcastsLocked();
11934 r.state = BroadcastRecord.IDLE;
11935 return;
11936 }
11937
11938 mPendingBroadcast = r;
11939 }
11940 }
11941
11942 // =========================================================
11943 // INSTRUMENTATION
11944 // =========================================================
11945
11946 public boolean startInstrumentation(ComponentName className,
11947 String profileFile, int flags, Bundle arguments,
11948 IInstrumentationWatcher watcher) {
11949 // Refuse possible leaked file descriptors
11950 if (arguments != null && arguments.hasFileDescriptors()) {
11951 throw new IllegalArgumentException("File descriptors passed in Bundle");
11952 }
11953
11954 synchronized(this) {
11955 InstrumentationInfo ii = null;
11956 ApplicationInfo ai = null;
11957 try {
11958 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011959 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011960 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011961 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011962 } catch (PackageManager.NameNotFoundException e) {
11963 }
11964 if (ii == null) {
11965 reportStartInstrumentationFailure(watcher, className,
11966 "Unable to find instrumentation info for: " + className);
11967 return false;
11968 }
11969 if (ai == null) {
11970 reportStartInstrumentationFailure(watcher, className,
11971 "Unable to find instrumentation target package: " + ii.targetPackage);
11972 return false;
11973 }
11974
11975 int match = mContext.getPackageManager().checkSignatures(
11976 ii.targetPackage, ii.packageName);
11977 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11978 String msg = "Permission Denial: starting instrumentation "
11979 + className + " from pid="
11980 + Binder.getCallingPid()
11981 + ", uid=" + Binder.getCallingPid()
11982 + " not allowed because package " + ii.packageName
11983 + " does not have a signature matching the target "
11984 + ii.targetPackage;
11985 reportStartInstrumentationFailure(watcher, className, msg);
11986 throw new SecurityException(msg);
11987 }
11988
11989 final long origId = Binder.clearCallingIdentity();
11990 uninstallPackageLocked(ii.targetPackage, -1, true);
11991 ProcessRecord app = addAppLocked(ai);
11992 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011993 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011994 app.instrumentationProfileFile = profileFile;
11995 app.instrumentationArguments = arguments;
11996 app.instrumentationWatcher = watcher;
11997 app.instrumentationResultClass = className;
11998 Binder.restoreCallingIdentity(origId);
11999 }
12000
12001 return true;
12002 }
12003
12004 /**
12005 * Report errors that occur while attempting to start Instrumentation. Always writes the
12006 * error to the logs, but if somebody is watching, send the report there too. This enables
12007 * the "am" command to report errors with more information.
12008 *
12009 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12010 * @param cn The component name of the instrumentation.
12011 * @param report The error report.
12012 */
12013 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12014 ComponentName cn, String report) {
12015 Log.w(TAG, report);
12016 try {
12017 if (watcher != null) {
12018 Bundle results = new Bundle();
12019 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12020 results.putString("Error", report);
12021 watcher.instrumentationStatus(cn, -1, results);
12022 }
12023 } catch (RemoteException e) {
12024 Log.w(TAG, e);
12025 }
12026 }
12027
12028 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12029 if (app.instrumentationWatcher != null) {
12030 try {
12031 // NOTE: IInstrumentationWatcher *must* be oneway here
12032 app.instrumentationWatcher.instrumentationFinished(
12033 app.instrumentationClass,
12034 resultCode,
12035 results);
12036 } catch (RemoteException e) {
12037 }
12038 }
12039 app.instrumentationWatcher = null;
12040 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012041 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012042 app.instrumentationProfileFile = null;
12043 app.instrumentationArguments = null;
12044
12045 uninstallPackageLocked(app.processName, -1, false);
12046 }
12047
12048 public void finishInstrumentation(IApplicationThread target,
12049 int resultCode, Bundle results) {
12050 // Refuse possible leaked file descriptors
12051 if (results != null && results.hasFileDescriptors()) {
12052 throw new IllegalArgumentException("File descriptors passed in Intent");
12053 }
12054
12055 synchronized(this) {
12056 ProcessRecord app = getRecordForAppLocked(target);
12057 if (app == null) {
12058 Log.w(TAG, "finishInstrumentation: no app for " + target);
12059 return;
12060 }
12061 final long origId = Binder.clearCallingIdentity();
12062 finishInstrumentationLocked(app, resultCode, results);
12063 Binder.restoreCallingIdentity(origId);
12064 }
12065 }
12066
12067 // =========================================================
12068 // CONFIGURATION
12069 // =========================================================
12070
12071 public ConfigurationInfo getDeviceConfigurationInfo() {
12072 ConfigurationInfo config = new ConfigurationInfo();
12073 synchronized (this) {
12074 config.reqTouchScreen = mConfiguration.touchscreen;
12075 config.reqKeyboardType = mConfiguration.keyboard;
12076 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012077 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12078 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012079 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12080 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012081 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12082 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012083 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12084 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012085 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012086 }
12087 return config;
12088 }
12089
12090 public Configuration getConfiguration() {
12091 Configuration ci;
12092 synchronized(this) {
12093 ci = new Configuration(mConfiguration);
12094 }
12095 return ci;
12096 }
12097
12098 public void updateConfiguration(Configuration values) {
12099 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12100 "updateConfiguration()");
12101
12102 synchronized(this) {
12103 if (values == null && mWindowManager != null) {
12104 // sentinel: fetch the current configuration from the window manager
12105 values = mWindowManager.computeNewConfiguration();
12106 }
12107
12108 final long origId = Binder.clearCallingIdentity();
12109 updateConfigurationLocked(values, null);
12110 Binder.restoreCallingIdentity(origId);
12111 }
12112 }
12113
12114 /**
12115 * Do either or both things: (1) change the current configuration, and (2)
12116 * make sure the given activity is running with the (now) current
12117 * configuration. Returns true if the activity has been left running, or
12118 * false if <var>starting</var> is being destroyed to match the new
12119 * configuration.
12120 */
12121 public boolean updateConfigurationLocked(Configuration values,
12122 HistoryRecord starting) {
12123 int changes = 0;
12124
12125 boolean kept = true;
12126
12127 if (values != null) {
12128 Configuration newConfig = new Configuration(mConfiguration);
12129 changes = newConfig.updateFrom(values);
12130 if (changes != 0) {
12131 if (DEBUG_SWITCH) {
12132 Log.i(TAG, "Updating configuration to: " + values);
12133 }
12134
12135 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12136
12137 if (values.locale != null) {
12138 saveLocaleLocked(values.locale,
12139 !values.locale.equals(mConfiguration.locale),
12140 values.userSetLocale);
12141 }
12142
12143 mConfiguration = newConfig;
12144
12145 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12146 msg.obj = new Configuration(mConfiguration);
12147 mHandler.sendMessage(msg);
12148
12149 final int N = mLRUProcesses.size();
12150 for (int i=0; i<N; i++) {
12151 ProcessRecord app = mLRUProcesses.get(i);
12152 try {
12153 if (app.thread != null) {
12154 app.thread.scheduleConfigurationChanged(mConfiguration);
12155 }
12156 } catch (Exception e) {
12157 }
12158 }
12159 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12160 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12161 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012162
12163 AttributeCache ac = AttributeCache.instance();
12164 if (ac != null) {
12165 ac.updateConfiguration(mConfiguration);
12166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012167 }
12168 }
12169
12170 if (changes != 0 && starting == null) {
12171 // If the configuration changed, and the caller is not already
12172 // in the process of starting an activity, then find the top
12173 // activity to check if its configuration needs to change.
12174 starting = topRunningActivityLocked(null);
12175 }
12176
12177 if (starting != null) {
12178 kept = ensureActivityConfigurationLocked(starting, changes);
12179 if (kept) {
12180 // If this didn't result in the starting activity being
12181 // destroyed, then we need to make sure at this point that all
12182 // other activities are made visible.
12183 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12184 + ", ensuring others are correct.");
12185 ensureActivitiesVisibleLocked(starting, changes);
12186 }
12187 }
12188
12189 return kept;
12190 }
12191
12192 private final boolean relaunchActivityLocked(HistoryRecord r,
12193 int changes, boolean andResume) {
12194 List<ResultInfo> results = null;
12195 List<Intent> newIntents = null;
12196 if (andResume) {
12197 results = r.results;
12198 newIntents = r.newIntents;
12199 }
12200 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12201 + " with results=" + results + " newIntents=" + newIntents
12202 + " andResume=" + andResume);
12203 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12204 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12205 r.task.taskId, r.shortComponentName);
12206
12207 r.startFreezingScreenLocked(r.app, 0);
12208
12209 try {
12210 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12211 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12212 changes, !andResume);
12213 // Note: don't need to call pauseIfSleepingLocked() here, because
12214 // the caller will only pass in 'andResume' if this activity is
12215 // currently resumed, which implies we aren't sleeping.
12216 } catch (RemoteException e) {
12217 return false;
12218 }
12219
12220 if (andResume) {
12221 r.results = null;
12222 r.newIntents = null;
12223 }
12224
12225 return true;
12226 }
12227
12228 /**
12229 * Make sure the given activity matches the current configuration. Returns
12230 * false if the activity had to be destroyed. Returns true if the
12231 * configuration is the same, or the activity will remain running as-is
12232 * for whatever reason. Ensures the HistoryRecord is updated with the
12233 * correct configuration and all other bookkeeping is handled.
12234 */
12235 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12236 int globalChanges) {
12237 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12238
12239 // Short circuit: if the two configurations are the exact same
12240 // object (the common case), then there is nothing to do.
12241 Configuration newConfig = mConfiguration;
12242 if (r.configuration == newConfig) {
12243 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12244 return true;
12245 }
12246
12247 // We don't worry about activities that are finishing.
12248 if (r.finishing) {
12249 if (DEBUG_SWITCH) Log.i(TAG,
12250 "Configuration doesn't matter in finishing " + r);
12251 r.stopFreezingScreenLocked(false);
12252 return true;
12253 }
12254
12255 // Okay we now are going to make this activity have the new config.
12256 // But then we need to figure out how it needs to deal with that.
12257 Configuration oldConfig = r.configuration;
12258 r.configuration = newConfig;
12259
12260 // If the activity isn't currently running, just leave the new
12261 // configuration and it will pick that up next time it starts.
12262 if (r.app == null || r.app.thread == null) {
12263 if (DEBUG_SWITCH) Log.i(TAG,
12264 "Configuration doesn't matter not running " + r);
12265 r.stopFreezingScreenLocked(false);
12266 return true;
12267 }
12268
12269 // If the activity isn't persistent, there is a chance we will
12270 // need to restart it.
12271 if (!r.persistent) {
12272
12273 // Figure out what has changed between the two configurations.
12274 int changes = oldConfig.diff(newConfig);
12275 if (DEBUG_SWITCH) {
12276 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12277 + Integer.toHexString(changes) + ", handles=0x"
12278 + Integer.toHexString(r.info.configChanges));
12279 }
12280 if ((changes&(~r.info.configChanges)) != 0) {
12281 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12282 r.configChangeFlags |= changes;
12283 r.startFreezingScreenLocked(r.app, globalChanges);
12284 if (r.app == null || r.app.thread == null) {
12285 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12286 destroyActivityLocked(r, true);
12287 } else if (r.state == ActivityState.PAUSING) {
12288 // A little annoying: we are waiting for this activity to
12289 // finish pausing. Let's not do anything now, but just
12290 // flag that it needs to be restarted when done pausing.
12291 r.configDestroy = true;
12292 return true;
12293 } else if (r.state == ActivityState.RESUMED) {
12294 // Try to optimize this case: the configuration is changing
12295 // and we need to restart the top, resumed activity.
12296 // Instead of doing the normal handshaking, just say
12297 // "restart!".
12298 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12299 relaunchActivityLocked(r, r.configChangeFlags, true);
12300 r.configChangeFlags = 0;
12301 } else {
12302 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12303 relaunchActivityLocked(r, r.configChangeFlags, false);
12304 r.configChangeFlags = 0;
12305 }
12306
12307 // All done... tell the caller we weren't able to keep this
12308 // activity around.
12309 return false;
12310 }
12311 }
12312
12313 // Default case: the activity can handle this new configuration, so
12314 // hand it over. Note that we don't need to give it the new
12315 // configuration, since we always send configuration changes to all
12316 // process when they happen so it can just use whatever configuration
12317 // it last got.
12318 if (r.app != null && r.app.thread != null) {
12319 try {
12320 r.app.thread.scheduleActivityConfigurationChanged(r);
12321 } catch (RemoteException e) {
12322 // If process died, whatever.
12323 }
12324 }
12325 r.stopFreezingScreenLocked(false);
12326
12327 return true;
12328 }
12329
12330 /**
12331 * Save the locale. You must be inside a synchronized (this) block.
12332 */
12333 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12334 if(isDiff) {
12335 SystemProperties.set("user.language", l.getLanguage());
12336 SystemProperties.set("user.region", l.getCountry());
12337 }
12338
12339 if(isPersist) {
12340 SystemProperties.set("persist.sys.language", l.getLanguage());
12341 SystemProperties.set("persist.sys.country", l.getCountry());
12342 SystemProperties.set("persist.sys.localevar", l.getVariant());
12343 }
12344 }
12345
12346 // =========================================================
12347 // LIFETIME MANAGEMENT
12348 // =========================================================
12349
12350 private final int computeOomAdjLocked(
12351 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12352 if (mAdjSeq == app.adjSeq) {
12353 // This adjustment has already been computed.
12354 return app.curAdj;
12355 }
12356
12357 if (app.thread == null) {
12358 app.adjSeq = mAdjSeq;
12359 return (app.curAdj=EMPTY_APP_ADJ);
12360 }
12361
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012362 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12363 // The max adjustment doesn't allow this app to be anything
12364 // below foreground, so it is not worth doing work for it.
12365 app.adjType = "fixed";
12366 app.adjSeq = mAdjSeq;
12367 app.curRawAdj = app.maxAdj;
12368 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12369 return (app.curAdj=app.maxAdj);
12370 }
12371
12372 app.adjSource = null;
12373 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012374
The Android Open Source Project4df24232009-03-05 14:34:35 -080012375 // Determine the importance of the process, starting with most
12376 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012377 int adj;
12378 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012379 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012380 // The last app on the list is the foreground app.
12381 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012382 app.adjType = "top";
12383 } else if (app.instrumentationClass != null) {
12384 // Don't want to kill running instrumentation.
12385 adj = FOREGROUND_APP_ADJ;
12386 app.adjType = "instr";
12387 } else if (app.persistentActivities > 0) {
12388 // Special persistent activities... shouldn't be used these days.
12389 adj = FOREGROUND_APP_ADJ;
12390 app.adjType = "pers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012391 } else if (app.curReceiver != null ||
12392 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12393 // An app that is currently receiving a broadcast also
12394 // counts as being in the foreground.
12395 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012396 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012397 } else if (app.executingServices.size() > 0) {
12398 // An app that is currently executing a service callback also
12399 // counts as being in the foreground.
12400 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012401 app.adjType = "exec-service";
12402 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012403 // The user is aware of this app, so make it visible.
12404 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012405 app.adjType = "foreground-service";
12406 } else if (app.forcingToForeground != null) {
12407 // The user is aware of this app, so make it visible.
12408 adj = VISIBLE_APP_ADJ;
12409 app.adjType = "force-foreground";
12410 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012411 } else if (app == mHomeProcess) {
12412 // This process is hosting what we currently consider to be the
12413 // home app, so we don't want to let it go into the background.
12414 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012415 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012416 } else if ((N=app.activities.size()) != 0) {
12417 // This app is in the background with paused activities.
12418 adj = hiddenAdj;
12419 for (int j=0; j<N; j++) {
12420 if (((HistoryRecord)app.activities.get(j)).visible) {
12421 // This app has a visible activity!
12422 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012423 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012424 break;
12425 }
12426 }
12427 } else {
12428 // A very not-needed process.
12429 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012430 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012431 }
12432
The Android Open Source Project4df24232009-03-05 14:34:35 -080012433 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012434 // there are applications dependent on our services or providers, but
12435 // this gives us a baseline and makes sure we don't get into an
12436 // infinite recursion.
12437 app.adjSeq = mAdjSeq;
12438 app.curRawAdj = adj;
12439 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12440
Christopher Tate6fa95972009-06-05 18:43:55 -070012441 if (mBackupTarget != null && app == mBackupTarget.app) {
12442 // If possible we want to avoid killing apps while they're being backed up
12443 if (adj > BACKUP_APP_ADJ) {
12444 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12445 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012446 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012447 }
12448 }
12449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012450 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12451 // If this process has active services running in it, we would
12452 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012453 // application from running. By default we put the process in
12454 // with the rest of the background processes; as we scan through
12455 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012456 if (adj > hiddenAdj) {
12457 adj = hiddenAdj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012458 app.adjType = "services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012459 }
12460 final long now = SystemClock.uptimeMillis();
12461 // This process is more important if the top activity is
12462 // bound to the service.
12463 Iterator jt = app.services.iterator();
12464 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12465 ServiceRecord s = (ServiceRecord)jt.next();
12466 if (s.startRequested) {
12467 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12468 // This service has seen some activity within
12469 // recent memory, so we will keep its process ahead
12470 // of the background processes.
12471 if (adj > SECONDARY_SERVER_ADJ) {
12472 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012473 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012474 }
12475 }
12476 }
12477 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12478 Iterator<ConnectionRecord> kt
12479 = s.connections.values().iterator();
12480 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12481 // XXX should compute this based on the max of
12482 // all connected clients.
12483 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012484 if (cr.binding.client == app) {
12485 // Binding to ourself is not interesting.
12486 continue;
12487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012488 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12489 ProcessRecord client = cr.binding.client;
12490 int myHiddenAdj = hiddenAdj;
12491 if (myHiddenAdj > client.hiddenAdj) {
12492 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12493 myHiddenAdj = client.hiddenAdj;
12494 } else {
12495 myHiddenAdj = VISIBLE_APP_ADJ;
12496 }
12497 }
12498 int clientAdj = computeOomAdjLocked(
12499 client, myHiddenAdj, TOP_APP);
12500 if (adj > clientAdj) {
12501 adj = clientAdj > VISIBLE_APP_ADJ
12502 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012503 app.adjType = "service";
12504 app.adjSource = cr.binding.client;
12505 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012506 }
12507 }
12508 HistoryRecord a = cr.activity;
12509 //if (a != null) {
12510 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12511 //}
12512 if (a != null && adj > FOREGROUND_APP_ADJ &&
12513 (a.state == ActivityState.RESUMED
12514 || a.state == ActivityState.PAUSING)) {
12515 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012516 app.adjType = "service";
12517 app.adjSource = a;
12518 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012519 }
12520 }
12521 }
12522 }
12523 }
12524
12525 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12526 // If this process has published any content providers, then
12527 // its adjustment makes it at least as important as any of the
12528 // processes using those providers, and no less important than
12529 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12530 if (adj > CONTENT_PROVIDER_ADJ) {
12531 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012532 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012533 }
12534 Iterator jt = app.pubProviders.values().iterator();
12535 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12536 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12537 if (cpr.clients.size() != 0) {
12538 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12539 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12540 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012541 if (client == app) {
12542 // Being our own client is not interesting.
12543 continue;
12544 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012545 int myHiddenAdj = hiddenAdj;
12546 if (myHiddenAdj > client.hiddenAdj) {
12547 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12548 myHiddenAdj = client.hiddenAdj;
12549 } else {
12550 myHiddenAdj = FOREGROUND_APP_ADJ;
12551 }
12552 }
12553 int clientAdj = computeOomAdjLocked(
12554 client, myHiddenAdj, TOP_APP);
12555 if (adj > clientAdj) {
12556 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012557 ? clientAdj : FOREGROUND_APP_ADJ;
12558 app.adjType = "provider";
12559 app.adjSource = client;
12560 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012561 }
12562 }
12563 }
12564 // If the provider has external (non-framework) process
12565 // dependencies, ensure that its adjustment is at least
12566 // FOREGROUND_APP_ADJ.
12567 if (cpr.externals != 0) {
12568 if (adj > FOREGROUND_APP_ADJ) {
12569 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012570 app.adjType = "provider";
12571 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012572 }
12573 }
12574 }
12575 }
12576
12577 app.curRawAdj = adj;
12578
12579 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12580 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12581 if (adj > app.maxAdj) {
12582 adj = app.maxAdj;
12583 }
12584
12585 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012586 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012587 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12588 : Process.THREAD_GROUP_DEFAULT;
12589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012590 return adj;
12591 }
12592
12593 /**
12594 * Ask a given process to GC right now.
12595 */
12596 final void performAppGcLocked(ProcessRecord app) {
12597 try {
12598 app.lastRequestedGc = SystemClock.uptimeMillis();
12599 if (app.thread != null) {
12600 app.thread.processInBackground();
12601 }
12602 } catch (Exception e) {
12603 // whatever.
12604 }
12605 }
12606
12607 /**
12608 * Returns true if things are idle enough to perform GCs.
12609 */
12610 private final boolean canGcNow() {
12611 return mParallelBroadcasts.size() == 0
12612 && mOrderedBroadcasts.size() == 0
12613 && (mSleeping || (mResumedActivity != null &&
12614 mResumedActivity.idle));
12615 }
12616
12617 /**
12618 * Perform GCs on all processes that are waiting for it, but only
12619 * if things are idle.
12620 */
12621 final void performAppGcsLocked() {
12622 final int N = mProcessesToGc.size();
12623 if (N <= 0) {
12624 return;
12625 }
12626 if (canGcNow()) {
12627 while (mProcessesToGc.size() > 0) {
12628 ProcessRecord proc = mProcessesToGc.remove(0);
12629 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12630 // To avoid spamming the system, we will GC processes one
12631 // at a time, waiting a few seconds between each.
12632 performAppGcLocked(proc);
12633 scheduleAppGcsLocked();
12634 return;
12635 }
12636 }
12637 }
12638 }
12639
12640 /**
12641 * If all looks good, perform GCs on all processes waiting for them.
12642 */
12643 final void performAppGcsIfAppropriateLocked() {
12644 if (canGcNow()) {
12645 performAppGcsLocked();
12646 return;
12647 }
12648 // Still not idle, wait some more.
12649 scheduleAppGcsLocked();
12650 }
12651
12652 /**
12653 * Schedule the execution of all pending app GCs.
12654 */
12655 final void scheduleAppGcsLocked() {
12656 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12657 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12658 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12659 }
12660
12661 /**
12662 * Set up to ask a process to GC itself. This will either do it
12663 * immediately, or put it on the list of processes to gc the next
12664 * time things are idle.
12665 */
12666 final void scheduleAppGcLocked(ProcessRecord app) {
12667 long now = SystemClock.uptimeMillis();
12668 if ((app.lastRequestedGc+5000) > now) {
12669 return;
12670 }
12671 if (!mProcessesToGc.contains(app)) {
12672 mProcessesToGc.add(app);
12673 scheduleAppGcsLocked();
12674 }
12675 }
12676
12677 private final boolean updateOomAdjLocked(
12678 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12679 app.hiddenAdj = hiddenAdj;
12680
12681 if (app.thread == null) {
12682 return true;
12683 }
12684
12685 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012687 if (app.pid != 0 && app.pid != MY_PID) {
12688 if (app.curRawAdj != app.setRawAdj) {
12689 if (app.curRawAdj > FOREGROUND_APP_ADJ
12690 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12691 // If this app is transitioning from foreground to
12692 // non-foreground, have it do a gc.
12693 scheduleAppGcLocked(app);
12694 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12695 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12696 // Likewise do a gc when an app is moving in to the
12697 // background (such as a service stopping).
12698 scheduleAppGcLocked(app);
12699 }
12700 app.setRawAdj = app.curRawAdj;
12701 }
12702 if (adj != app.setAdj) {
12703 if (Process.setOomAdj(app.pid, adj)) {
12704 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12705 TAG, "Set app " + app.processName +
12706 " oom adj to " + adj);
12707 app.setAdj = adj;
12708 } else {
12709 return false;
12710 }
12711 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012712 if (app.setSchedGroup != app.curSchedGroup) {
12713 app.setSchedGroup = app.curSchedGroup;
12714 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12715 "Setting process group of " + app.processName
12716 + " to " + app.curSchedGroup);
12717 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012718 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012719 try {
12720 Process.setProcessGroup(app.pid, app.curSchedGroup);
12721 } catch (Exception e) {
12722 Log.w(TAG, "Failed setting process group of " + app.pid
12723 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012724 e.printStackTrace();
12725 } finally {
12726 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012727 }
12728 }
12729 if (false) {
12730 if (app.thread != null) {
12731 try {
12732 app.thread.setSchedulingGroup(app.curSchedGroup);
12733 } catch (RemoteException e) {
12734 }
12735 }
12736 }
12737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012738 }
12739
12740 return true;
12741 }
12742
12743 private final HistoryRecord resumedAppLocked() {
12744 HistoryRecord resumedActivity = mResumedActivity;
12745 if (resumedActivity == null || resumedActivity.app == null) {
12746 resumedActivity = mPausingActivity;
12747 if (resumedActivity == null || resumedActivity.app == null) {
12748 resumedActivity = topRunningActivityLocked(null);
12749 }
12750 }
12751 return resumedActivity;
12752 }
12753
12754 private final boolean updateOomAdjLocked(ProcessRecord app) {
12755 final HistoryRecord TOP_ACT = resumedAppLocked();
12756 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12757 int curAdj = app.curAdj;
12758 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12759 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12760
12761 mAdjSeq++;
12762
12763 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12764 if (res) {
12765 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12766 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12767 if (nowHidden != wasHidden) {
12768 // Changed to/from hidden state, so apps after it in the LRU
12769 // list may also be changed.
12770 updateOomAdjLocked();
12771 }
12772 }
12773 return res;
12774 }
12775
12776 private final boolean updateOomAdjLocked() {
12777 boolean didOomAdj = true;
12778 final HistoryRecord TOP_ACT = resumedAppLocked();
12779 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12780
12781 if (false) {
12782 RuntimeException e = new RuntimeException();
12783 e.fillInStackTrace();
12784 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12785 }
12786
12787 mAdjSeq++;
12788
12789 // First try updating the OOM adjustment for each of the
12790 // application processes based on their current state.
12791 int i = mLRUProcesses.size();
12792 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12793 while (i > 0) {
12794 i--;
12795 ProcessRecord app = mLRUProcesses.get(i);
12796 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12797 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12798 && app.curAdj == curHiddenAdj) {
12799 curHiddenAdj++;
12800 }
12801 } else {
12802 didOomAdj = false;
12803 }
12804 }
12805
12806 // todo: for now pretend like OOM ADJ didn't work, because things
12807 // aren't behaving as expected on Linux -- it's not killing processes.
12808 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12809 }
12810
12811 private final void trimApplications() {
12812 synchronized (this) {
12813 int i;
12814
12815 // First remove any unused application processes whose package
12816 // has been removed.
12817 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12818 final ProcessRecord app = mRemovedProcesses.get(i);
12819 if (app.activities.size() == 0
12820 && app.curReceiver == null && app.services.size() == 0) {
12821 Log.i(
12822 TAG, "Exiting empty application process "
12823 + app.processName + " ("
12824 + (app.thread != null ? app.thread.asBinder() : null)
12825 + ")\n");
12826 if (app.pid > 0 && app.pid != MY_PID) {
12827 Process.killProcess(app.pid);
12828 } else {
12829 try {
12830 app.thread.scheduleExit();
12831 } catch (Exception e) {
12832 // Ignore exceptions.
12833 }
12834 }
12835 cleanUpApplicationRecordLocked(app, false, -1);
12836 mRemovedProcesses.remove(i);
12837
12838 if (app.persistent) {
12839 if (app.persistent) {
12840 addAppLocked(app.info);
12841 }
12842 }
12843 }
12844 }
12845
12846 // Now try updating the OOM adjustment for each of the
12847 // application processes based on their current state.
12848 // If the setOomAdj() API is not supported, then go with our
12849 // back-up plan...
12850 if (!updateOomAdjLocked()) {
12851
12852 // Count how many processes are running services.
12853 int numServiceProcs = 0;
12854 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12855 final ProcessRecord app = mLRUProcesses.get(i);
12856
12857 if (app.persistent || app.services.size() != 0
12858 || app.curReceiver != null
12859 || app.persistentActivities > 0) {
12860 // Don't count processes holding services against our
12861 // maximum process count.
12862 if (localLOGV) Log.v(
12863 TAG, "Not trimming app " + app + " with services: "
12864 + app.services);
12865 numServiceProcs++;
12866 }
12867 }
12868
12869 int curMaxProcs = mProcessLimit;
12870 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12871 if (mAlwaysFinishActivities) {
12872 curMaxProcs = 1;
12873 }
12874 curMaxProcs += numServiceProcs;
12875
12876 // Quit as many processes as we can to get down to the desired
12877 // process count. First remove any processes that no longer
12878 // have activites running in them.
12879 for ( i=0;
12880 i<mLRUProcesses.size()
12881 && mLRUProcesses.size() > curMaxProcs;
12882 i++) {
12883 final ProcessRecord app = mLRUProcesses.get(i);
12884 // Quit an application only if it is not currently
12885 // running any activities.
12886 if (!app.persistent && app.activities.size() == 0
12887 && app.curReceiver == null && app.services.size() == 0) {
12888 Log.i(
12889 TAG, "Exiting empty application process "
12890 + app.processName + " ("
12891 + (app.thread != null ? app.thread.asBinder() : null)
12892 + ")\n");
12893 if (app.pid > 0 && app.pid != MY_PID) {
12894 Process.killProcess(app.pid);
12895 } else {
12896 try {
12897 app.thread.scheduleExit();
12898 } catch (Exception e) {
12899 // Ignore exceptions.
12900 }
12901 }
12902 // todo: For now we assume the application is not buggy
12903 // or evil, and will quit as a result of our request.
12904 // Eventually we need to drive this off of the death
12905 // notification, and kill the process if it takes too long.
12906 cleanUpApplicationRecordLocked(app, false, i);
12907 i--;
12908 }
12909 }
12910
12911 // If we still have too many processes, now from the least
12912 // recently used process we start finishing activities.
12913 if (Config.LOGV) Log.v(
12914 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12915 " of " + curMaxProcs + " processes");
12916 for ( i=0;
12917 i<mLRUProcesses.size()
12918 && mLRUProcesses.size() > curMaxProcs;
12919 i++) {
12920 final ProcessRecord app = mLRUProcesses.get(i);
12921 // Quit the application only if we have a state saved for
12922 // all of its activities.
12923 boolean canQuit = !app.persistent && app.curReceiver == null
12924 && app.services.size() == 0
12925 && app.persistentActivities == 0;
12926 int NUMA = app.activities.size();
12927 int j;
12928 if (Config.LOGV) Log.v(
12929 TAG, "Looking to quit " + app.processName);
12930 for (j=0; j<NUMA && canQuit; j++) {
12931 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12932 if (Config.LOGV) Log.v(
12933 TAG, " " + r.intent.getComponent().flattenToShortString()
12934 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12935 canQuit = (r.haveState || !r.stateNotNeeded)
12936 && !r.visible && r.stopped;
12937 }
12938 if (canQuit) {
12939 // Finish all of the activities, and then the app itself.
12940 for (j=0; j<NUMA; j++) {
12941 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12942 if (!r.finishing) {
12943 destroyActivityLocked(r, false);
12944 }
12945 r.resultTo = null;
12946 }
12947 Log.i(TAG, "Exiting application process "
12948 + app.processName + " ("
12949 + (app.thread != null ? app.thread.asBinder() : null)
12950 + ")\n");
12951 if (app.pid > 0 && app.pid != MY_PID) {
12952 Process.killProcess(app.pid);
12953 } else {
12954 try {
12955 app.thread.scheduleExit();
12956 } catch (Exception e) {
12957 // Ignore exceptions.
12958 }
12959 }
12960 // todo: For now we assume the application is not buggy
12961 // or evil, and will quit as a result of our request.
12962 // Eventually we need to drive this off of the death
12963 // notification, and kill the process if it takes too long.
12964 cleanUpApplicationRecordLocked(app, false, i);
12965 i--;
12966 //dump();
12967 }
12968 }
12969
12970 }
12971
12972 int curMaxActivities = MAX_ACTIVITIES;
12973 if (mAlwaysFinishActivities) {
12974 curMaxActivities = 1;
12975 }
12976
12977 // Finally, if there are too many activities now running, try to
12978 // finish as many as we can to get back down to the limit.
12979 for ( i=0;
12980 i<mLRUActivities.size()
12981 && mLRUActivities.size() > curMaxActivities;
12982 i++) {
12983 final HistoryRecord r
12984 = (HistoryRecord)mLRUActivities.get(i);
12985
12986 // We can finish this one if we have its icicle saved and
12987 // it is not persistent.
12988 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12989 && r.stopped && !r.persistent && !r.finishing) {
12990 final int origSize = mLRUActivities.size();
12991 destroyActivityLocked(r, true);
12992
12993 // This will remove it from the LRU list, so keep
12994 // our index at the same value. Note that this check to
12995 // see if the size changes is just paranoia -- if
12996 // something unexpected happens, we don't want to end up
12997 // in an infinite loop.
12998 if (origSize > mLRUActivities.size()) {
12999 i--;
13000 }
13001 }
13002 }
13003 }
13004 }
13005
13006 /** This method sends the specified signal to each of the persistent apps */
13007 public void signalPersistentProcesses(int sig) throws RemoteException {
13008 if (sig != Process.SIGNAL_USR1) {
13009 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13010 }
13011
13012 synchronized (this) {
13013 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13014 != PackageManager.PERMISSION_GRANTED) {
13015 throw new SecurityException("Requires permission "
13016 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13017 }
13018
13019 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13020 ProcessRecord r = mLRUProcesses.get(i);
13021 if (r.thread != null && r.persistent) {
13022 Process.sendSignal(r.pid, sig);
13023 }
13024 }
13025 }
13026 }
13027
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013028 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013029 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013030
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013031 try {
13032 synchronized (this) {
13033 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13034 // its own permission.
13035 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13036 != PackageManager.PERMISSION_GRANTED) {
13037 throw new SecurityException("Requires permission "
13038 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013039 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013040
13041 if (start && fd == null) {
13042 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013043 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013044
13045 ProcessRecord proc = null;
13046 try {
13047 int pid = Integer.parseInt(process);
13048 synchronized (mPidsSelfLocked) {
13049 proc = mPidsSelfLocked.get(pid);
13050 }
13051 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013052 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013053
13054 if (proc == null) {
13055 HashMap<String, SparseArray<ProcessRecord>> all
13056 = mProcessNames.getMap();
13057 SparseArray<ProcessRecord> procs = all.get(process);
13058 if (procs != null && procs.size() > 0) {
13059 proc = procs.valueAt(0);
13060 }
13061 }
13062
13063 if (proc == null || proc.thread == null) {
13064 throw new IllegalArgumentException("Unknown process: " + process);
13065 }
13066
13067 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13068 if (isSecure) {
13069 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13070 throw new SecurityException("Process not debuggable: " + proc);
13071 }
13072 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013073
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013074 proc.thread.profilerControl(start, path, fd);
13075 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013076 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013077 }
13078 } catch (RemoteException e) {
13079 throw new IllegalStateException("Process disappeared");
13080 } finally {
13081 if (fd != null) {
13082 try {
13083 fd.close();
13084 } catch (IOException e) {
13085 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013086 }
13087 }
13088 }
13089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013090 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13091 public void monitor() {
13092 synchronized (this) { }
13093 }
13094}