blob: 2fe4dd4c310925c2e7fec029cdc9f722af47e244 [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;
35import android.app.IActivityWatcher;
36import android.app.IApplicationThread;
37import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.IServiceConnection;
39import android.app.IThumbnailReceiver;
40import android.app.Instrumentation;
41import android.app.PendingIntent;
42import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070043import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020044import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.content.ComponentName;
46import android.content.ContentResolver;
47import android.content.Context;
48import android.content.Intent;
49import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070050import android.content.IIntentReceiver;
51import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.content.pm.ActivityInfo;
53import android.content.pm.ApplicationInfo;
54import android.content.pm.ConfigurationInfo;
55import android.content.pm.IPackageDataObserver;
56import android.content.pm.IPackageManager;
57import android.content.pm.InstrumentationInfo;
58import android.content.pm.PackageManager;
59import android.content.pm.ProviderInfo;
60import android.content.pm.ResolveInfo;
61import android.content.pm.ServiceInfo;
62import android.content.res.Configuration;
63import android.graphics.Bitmap;
64import android.net.Uri;
65import android.os.Binder;
66import android.os.Bundle;
67import android.os.Environment;
68import android.os.FileUtils;
69import android.os.Handler;
70import android.os.IBinder;
71import android.os.IPermissionController;
72import android.os.Looper;
73import android.os.Message;
74import android.os.Parcel;
75import android.os.ParcelFileDescriptor;
76import android.os.PowerManager;
77import android.os.Process;
78import android.os.RemoteException;
79import android.os.ServiceManager;
80import android.os.SystemClock;
81import android.os.SystemProperties;
82import android.provider.Checkin;
83import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020084import android.server.data.CrashData;
85import android.server.data.StackTraceElementData;
86import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.text.TextUtils;
88import android.util.Config;
89import android.util.EventLog;
90import android.util.Log;
91import android.util.PrintWriterPrinter;
92import android.util.SparseArray;
93import android.view.Gravity;
94import android.view.LayoutInflater;
95import android.view.View;
96import android.view.WindowManager;
97import android.view.WindowManagerPolicy;
98
99import dalvik.system.Zygote;
100
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200101import java.io.ByteArrayInputStream;
102import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import java.io.File;
104import java.io.FileDescriptor;
105import java.io.FileInputStream;
106import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200107import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.PrintWriter;
109import java.lang.IllegalStateException;
110import java.lang.ref.WeakReference;
111import java.util.ArrayList;
112import java.util.HashMap;
113import java.util.HashSet;
114import java.util.Iterator;
115import java.util.List;
116import java.util.Locale;
117import java.util.Map;
118
119public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
120 static final String TAG = "ActivityManager";
121 static final boolean DEBUG = false;
122 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
123 static final boolean DEBUG_SWITCH = localLOGV || false;
124 static final boolean DEBUG_TASKS = localLOGV || false;
125 static final boolean DEBUG_PAUSE = localLOGV || false;
126 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
127 static final boolean DEBUG_TRANSITION = localLOGV || false;
128 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700129 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 static final boolean DEBUG_SERVICE = localLOGV || false;
131 static final boolean DEBUG_VISBILITY = localLOGV || false;
132 static final boolean DEBUG_PROCESSES = localLOGV || false;
133 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700134 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700135 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean VALIDATE_TOKENS = false;
137 static final boolean SHOW_ACTIVITY_START_TIME = true;
138
139 // Control over CPU and battery monitoring.
140 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
141 static final boolean MONITOR_CPU_USAGE = true;
142 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
143 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
144 static final boolean MONITOR_THREAD_CPU_USAGE = false;
145
146 // Event log tags
147 static final int LOG_CONFIGURATION_CHANGED = 2719;
148 static final int LOG_CPU = 2721;
149 static final int LOG_AM_FINISH_ACTIVITY = 30001;
150 static final int LOG_TASK_TO_FRONT = 30002;
151 static final int LOG_AM_NEW_INTENT = 30003;
152 static final int LOG_AM_CREATE_TASK = 30004;
153 static final int LOG_AM_CREATE_ACTIVITY = 30005;
154 static final int LOG_AM_RESTART_ACTIVITY = 30006;
155 static final int LOG_AM_RESUME_ACTIVITY = 30007;
156 static final int LOG_ANR = 30008;
157 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
158 static final int LOG_AM_PROCESS_BOUND = 30010;
159 static final int LOG_AM_PROCESS_DIED = 30011;
160 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
161 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
162 static final int LOG_AM_PROCESS_START = 30014;
163 static final int LOG_AM_PROCESS_BAD = 30015;
164 static final int LOG_AM_PROCESS_GOOD = 30016;
165 static final int LOG_AM_LOW_MEMORY = 30017;
166 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
167 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
168 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
169 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
170 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
171 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
172 static final int LOG_AM_CREATE_SERVICE = 30030;
173 static final int LOG_AM_DESTROY_SERVICE = 30031;
174 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
175 static final int LOG_AM_DROP_PROCESS = 30033;
176 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
177 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
178 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
179
180 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
181 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
182
Dianne Hackborn1655be42009-05-08 14:29:01 -0700183 // The flags that are set for all calls we make to the package manager.
184 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700185 | PackageManager.GET_SUPPORTS_DENSITIES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 private static final String SYSTEM_SECURE = "ro.secure";
188
189 // This is the maximum number of application processes we would like
190 // to have running. Due to the asynchronous nature of things, we can
191 // temporarily go beyond this limit.
192 static final int MAX_PROCESSES = 2;
193
194 // Set to false to leave processes running indefinitely, relying on
195 // the kernel killing them as resources are required.
196 static final boolean ENFORCE_PROCESS_LIMIT = false;
197
198 // This is the maximum number of activities that we would like to have
199 // running at a given time.
200 static final int MAX_ACTIVITIES = 20;
201
202 // Maximum number of recent tasks that we can remember.
203 static final int MAX_RECENT_TASKS = 20;
204
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700205 // Amount of time after a call to stopAppSwitches() during which we will
206 // prevent further untrusted switches from happening.
207 static final long APP_SWITCH_DELAY_TIME = 5*1000;
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 // How long until we reset a task when the user returns to it. Currently
210 // 30 minutes.
211 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
212
213 // Set to true to disable the icon that is shown while a new activity
214 // is being started.
215 static final boolean SHOW_APP_STARTING_ICON = true;
216
217 // How long we wait until giving up on the last activity to pause. This
218 // is short because it directly impacts the responsiveness of starting the
219 // next activity.
220 static final int PAUSE_TIMEOUT = 500;
221
222 /**
223 * How long we can hold the launch wake lock before giving up.
224 */
225 static final int LAUNCH_TIMEOUT = 10*1000;
226
227 // How long we wait for a launched process to attach to the activity manager
228 // before we decide it's never going to come up for real.
229 static final int PROC_START_TIMEOUT = 10*1000;
230
231 // How long we wait until giving up on the last activity telling us it
232 // is idle.
233 static final int IDLE_TIMEOUT = 10*1000;
234
235 // How long to wait after going idle before forcing apps to GC.
236 static final int GC_TIMEOUT = 5*1000;
237
238 // How long we wait until giving up on an activity telling us it has
239 // finished destroying itself.
240 static final int DESTROY_TIMEOUT = 10*1000;
241
242 // How long we allow a receiver to run before giving up on it.
243 static final int BROADCAST_TIMEOUT = 10*1000;
244
245 // How long we wait for a service to finish executing.
246 static final int SERVICE_TIMEOUT = 20*1000;
247
248 // How long a service needs to be running until restarting its process
249 // is no longer considered to be a relaunch of the service.
250 static final int SERVICE_RESTART_DURATION = 5*1000;
251
252 // Maximum amount of time for there to be no activity on a service before
253 // we consider it non-essential and allow its process to go on the
254 // LRU background list.
255 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
256
257 // How long we wait until we timeout on key dispatching.
258 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
259
260 // The minimum time we allow between crashes, for us to consider this
261 // application to be bad and stop and its services and reject broadcasts.
262 static final int MIN_CRASH_INTERVAL = 60*1000;
263
264 // How long we wait until we timeout on key dispatching during instrumentation.
265 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
266
267 // OOM adjustments for processes in various states:
268
269 // This is a process without anything currently running in it. Definitely
270 // the first to go! Value set in system/rootdir/init.rc on startup.
271 // This value is initalized in the constructor, careful when refering to
272 // this static variable externally.
273 static int EMPTY_APP_ADJ;
274
275 // This is a process with a content provider that does not have any clients
276 // attached to it. If it did have any clients, its adjustment would be the
277 // one for the highest-priority of those processes.
278 static int CONTENT_PROVIDER_ADJ;
279
280 // This is a process only hosting activities that are not visible,
281 // so it can be killed without any disruption. Value set in
282 // system/rootdir/init.rc on startup.
283 final int HIDDEN_APP_MAX_ADJ;
284 static int HIDDEN_APP_MIN_ADJ;
285
The Android Open Source Project4df24232009-03-05 14:34:35 -0800286 // This is a process holding the home application -- we want to try
287 // avoiding killing it, even if it would normally be in the background,
288 // because the user interacts with it so much.
289 final int HOME_APP_ADJ;
290
Christopher Tate6fa95972009-06-05 18:43:55 -0700291 // This is a process currently hosting a backup operation. Killing it
292 // is not entirely fatal but is generally a bad idea.
293 final int BACKUP_APP_ADJ;
294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 // This is a process holding a secondary server -- killing it will not
296 // have much of an impact as far as the user is concerned. Value set in
297 // system/rootdir/init.rc on startup.
298 final int SECONDARY_SERVER_ADJ;
299
300 // This is a process only hosting activities that are visible to the
301 // user, so we'd prefer they don't disappear. Value set in
302 // system/rootdir/init.rc on startup.
303 final int VISIBLE_APP_ADJ;
304
305 // This is the process running the current foreground app. We'd really
306 // rather not kill it! Value set in system/rootdir/init.rc on startup.
307 final int FOREGROUND_APP_ADJ;
308
309 // This is a process running a core server, such as telephony. Definitely
310 // don't want to kill it, but doing so is not completely fatal.
311 static final int CORE_SERVER_ADJ = -12;
312
313 // The system process runs at the default adjustment.
314 static final int SYSTEM_ADJ = -16;
315
316 // Memory pages are 4K.
317 static final int PAGE_SIZE = 4*1024;
318
319 // Corresponding memory levels for above adjustments.
320 final int EMPTY_APP_MEM;
321 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800322 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700323 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 final int SECONDARY_SERVER_MEM;
325 final int VISIBLE_APP_MEM;
326 final int FOREGROUND_APP_MEM;
327
328 final int MY_PID;
329
330 static final String[] EMPTY_STRING_ARRAY = new String[0];
331
332 enum ActivityState {
333 INITIALIZING,
334 RESUMED,
335 PAUSING,
336 PAUSED,
337 STOPPING,
338 STOPPED,
339 FINISHING,
340 DESTROYING,
341 DESTROYED
342 }
343
344 /**
345 * The back history of all previous (and possibly still
346 * running) activities. It contains HistoryRecord objects.
347 */
348 final ArrayList mHistory = new ArrayList();
349
350 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700351 * Description of a request to start a new activity, which has been held
352 * due to app switches being disabled.
353 */
354 class PendingActivityLaunch {
355 HistoryRecord r;
356 HistoryRecord sourceRecord;
357 Uri[] grantedUriPermissions;
358 int grantedMode;
359 boolean onlyIfNeeded;
360 }
361
362 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
363 = new ArrayList<PendingActivityLaunch>();
364
365 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 * List of all active broadcasts that are to be executed immediately
367 * (without waiting for another broadcast to finish). Currently this only
368 * contains broadcasts to registered receivers, to avoid spinning up
369 * a bunch of processes to execute IntentReceiver components.
370 */
371 final ArrayList<BroadcastRecord> mParallelBroadcasts
372 = new ArrayList<BroadcastRecord>();
373
374 /**
375 * List of all active broadcasts that are to be executed one at a time.
376 * The object at the top of the list is the currently activity broadcasts;
377 * those after it are waiting for the top to finish..
378 */
379 final ArrayList<BroadcastRecord> mOrderedBroadcasts
380 = new ArrayList<BroadcastRecord>();
381
382 /**
383 * Set when we current have a BROADCAST_INTENT_MSG in flight.
384 */
385 boolean mBroadcastsScheduled = false;
386
387 /**
388 * Set to indicate whether to issue an onUserLeaving callback when a
389 * newly launched activity is being brought in front of us.
390 */
391 boolean mUserLeaving = false;
392
393 /**
394 * When we are in the process of pausing an activity, before starting the
395 * next one, this variable holds the activity that is currently being paused.
396 */
397 HistoryRecord mPausingActivity = null;
398
399 /**
400 * Current activity that is resumed, or null if there is none.
401 */
402 HistoryRecord mResumedActivity = null;
403
404 /**
405 * Activity we have told the window manager to have key focus.
406 */
407 HistoryRecord mFocusedActivity = null;
408
409 /**
410 * This is the last activity that we put into the paused state. This is
411 * used to determine if we need to do an activity transition while sleeping,
412 * when we normally hold the top activity paused.
413 */
414 HistoryRecord mLastPausedActivity = null;
415
416 /**
417 * List of activities that are waiting for a new activity
418 * to become visible before completing whatever operation they are
419 * supposed to do.
420 */
421 final ArrayList mWaitingVisibleActivities = new ArrayList();
422
423 /**
424 * List of activities that are ready to be stopped, but waiting
425 * for the next activity to settle down before doing so. It contains
426 * HistoryRecord objects.
427 */
428 final ArrayList<HistoryRecord> mStoppingActivities
429 = new ArrayList<HistoryRecord>();
430
431 /**
432 * List of intents that were used to start the most recent tasks.
433 */
434 final ArrayList<TaskRecord> mRecentTasks
435 = new ArrayList<TaskRecord>();
436
437 /**
438 * List of activities that are ready to be finished, but waiting
439 * for the previous activity to settle down before doing so. It contains
440 * HistoryRecord objects.
441 */
442 final ArrayList mFinishingActivities = new ArrayList();
443
444 /**
445 * All of the applications we currently have running organized by name.
446 * The keys are strings of the application package name (as
447 * returned by the package manager), and the keys are ApplicationRecord
448 * objects.
449 */
450 final ProcessMap<ProcessRecord> mProcessNames
451 = new ProcessMap<ProcessRecord>();
452
453 /**
454 * The last time that various processes have crashed.
455 */
456 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
457
458 /**
459 * Set of applications that we consider to be bad, and will reject
460 * incoming broadcasts from (which the user has no control over).
461 * Processes are added to this set when they have crashed twice within
462 * a minimum amount of time; they are removed from it when they are
463 * later restarted (hopefully due to some user action). The value is the
464 * time it was added to the list.
465 */
466 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
467
468 /**
469 * All of the processes we currently have running organized by pid.
470 * The keys are the pid running the application.
471 *
472 * <p>NOTE: This object is protected by its own lock, NOT the global
473 * activity manager lock!
474 */
475 final SparseArray<ProcessRecord> mPidsSelfLocked
476 = new SparseArray<ProcessRecord>();
477
478 /**
479 * All of the processes that have been forced to be foreground. The key
480 * is the pid of the caller who requested it (we hold a death
481 * link on it).
482 */
483 abstract class ForegroundToken implements IBinder.DeathRecipient {
484 int pid;
485 IBinder token;
486 }
487 final SparseArray<ForegroundToken> mForegroundProcesses
488 = new SparseArray<ForegroundToken>();
489
490 /**
491 * List of records for processes that someone had tried to start before the
492 * system was ready. We don't start them at that point, but ensure they
493 * are started by the time booting is complete.
494 */
495 final ArrayList<ProcessRecord> mProcessesOnHold
496 = new ArrayList<ProcessRecord>();
497
498 /**
499 * List of records for processes that we have started and are waiting
500 * for them to call back. This is really only needed when running in
501 * single processes mode, in which case we do not have a unique pid for
502 * each process.
503 */
504 final ArrayList<ProcessRecord> mStartingProcesses
505 = new ArrayList<ProcessRecord>();
506
507 /**
508 * List of persistent applications that are in the process
509 * of being started.
510 */
511 final ArrayList<ProcessRecord> mPersistentStartingProcesses
512 = new ArrayList<ProcessRecord>();
513
514 /**
515 * Processes that are being forcibly torn down.
516 */
517 final ArrayList<ProcessRecord> mRemovedProcesses
518 = new ArrayList<ProcessRecord>();
519
520 /**
521 * List of running applications, sorted by recent usage.
522 * The first entry in the list is the least recently used.
523 * It contains ApplicationRecord objects. This list does NOT include
524 * any persistent application records (since we never want to exit them).
525 */
526 final ArrayList<ProcessRecord> mLRUProcesses
527 = new ArrayList<ProcessRecord>();
528
529 /**
530 * List of processes that should gc as soon as things are idle.
531 */
532 final ArrayList<ProcessRecord> mProcessesToGc
533 = new ArrayList<ProcessRecord>();
534
535 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800536 * This is the process holding what we currently consider to be
537 * the "home" activity.
538 */
539 private ProcessRecord mHomeProcess;
540
541 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 * List of running activities, sorted by recent usage.
543 * The first entry in the list is the least recently used.
544 * It contains HistoryRecord objects.
545 */
546 private final ArrayList mLRUActivities = new ArrayList();
547
548 /**
549 * Set of PendingResultRecord objects that are currently active.
550 */
551 final HashSet mPendingResultRecords = new HashSet();
552
553 /**
554 * Set of IntentSenderRecord objects that are currently active.
555 */
556 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
557 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
558
559 /**
560 * Intent broadcast that we have tried to start, but are
561 * waiting for its application's process to be created. We only
562 * need one (instead of a list) because we always process broadcasts
563 * one at a time, so no others can be started while waiting for this
564 * one.
565 */
566 BroadcastRecord mPendingBroadcast = null;
567
568 /**
569 * Keeps track of all IIntentReceivers that have been registered for
570 * broadcasts. Hash keys are the receiver IBinder, hash value is
571 * a ReceiverList.
572 */
573 final HashMap mRegisteredReceivers = new HashMap();
574
575 /**
576 * Resolver for broadcast intents to registered receivers.
577 * Holds BroadcastFilter (subclass of IntentFilter).
578 */
579 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
580 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
581 @Override
582 protected boolean allowFilterResult(
583 BroadcastFilter filter, List<BroadcastFilter> dest) {
584 IBinder target = filter.receiverList.receiver.asBinder();
585 for (int i=dest.size()-1; i>=0; i--) {
586 if (dest.get(i).receiverList.receiver.asBinder() == target) {
587 return false;
588 }
589 }
590 return true;
591 }
592 };
593
594 /**
595 * State of all active sticky broadcasts. Keys are the action of the
596 * sticky Intent, values are an ArrayList of all broadcasted intents with
597 * that action (which should usually be one).
598 */
599 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
600 new HashMap<String, ArrayList<Intent>>();
601
602 /**
603 * All currently running services.
604 */
605 final HashMap<ComponentName, ServiceRecord> mServices =
606 new HashMap<ComponentName, ServiceRecord>();
607
608 /**
609 * All currently running services indexed by the Intent used to start them.
610 */
611 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
612 new HashMap<Intent.FilterComparison, ServiceRecord>();
613
614 /**
615 * All currently bound service connections. Keys are the IBinder of
616 * the client's IServiceConnection.
617 */
618 final HashMap<IBinder, ConnectionRecord> mServiceConnections
619 = new HashMap<IBinder, ConnectionRecord>();
620
621 /**
622 * List of services that we have been asked to start,
623 * but haven't yet been able to. It is used to hold start requests
624 * while waiting for their corresponding application thread to get
625 * going.
626 */
627 final ArrayList<ServiceRecord> mPendingServices
628 = new ArrayList<ServiceRecord>();
629
630 /**
631 * List of services that are scheduled to restart following a crash.
632 */
633 final ArrayList<ServiceRecord> mRestartingServices
634 = new ArrayList<ServiceRecord>();
635
636 /**
637 * List of services that are in the process of being stopped.
638 */
639 final ArrayList<ServiceRecord> mStoppingServices
640 = new ArrayList<ServiceRecord>();
641
642 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700643 * Backup/restore process management
644 */
645 String mBackupAppName = null;
646 BackupRecord mBackupTarget = null;
647
648 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 * List of PendingThumbnailsRecord objects of clients who are still
650 * waiting to receive all of the thumbnails for a task.
651 */
652 final ArrayList mPendingThumbnails = new ArrayList();
653
654 /**
655 * List of HistoryRecord objects that have been finished and must
656 * still report back to a pending thumbnail receiver.
657 */
658 final ArrayList mCancelledThumbnails = new ArrayList();
659
660 /**
661 * All of the currently running global content providers. Keys are a
662 * string containing the provider name and values are a
663 * ContentProviderRecord object containing the data about it. Note
664 * that a single provider may be published under multiple names, so
665 * there may be multiple entries here for a single one in mProvidersByClass.
666 */
667 final HashMap mProvidersByName = new HashMap();
668
669 /**
670 * All of the currently running global content providers. Keys are a
671 * string containing the provider's implementation class and values are a
672 * ContentProviderRecord object containing the data about it.
673 */
674 final HashMap mProvidersByClass = new HashMap();
675
676 /**
677 * List of content providers who have clients waiting for them. The
678 * application is currently being launched and the provider will be
679 * removed from this list once it is published.
680 */
681 final ArrayList mLaunchingProviders = new ArrayList();
682
683 /**
684 * Global set of specific Uri permissions that have been granted.
685 */
686 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
687 = new SparseArray<HashMap<Uri, UriPermission>>();
688
689 /**
690 * Thread-local storage used to carry caller permissions over through
691 * indirect content-provider access.
692 * @see #ActivityManagerService.openContentUri()
693 */
694 private class Identity {
695 public int pid;
696 public int uid;
697
698 Identity(int _pid, int _uid) {
699 pid = _pid;
700 uid = _uid;
701 }
702 }
703 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
704
705 /**
706 * All information we have collected about the runtime performance of
707 * any user id that can impact battery performance.
708 */
709 final BatteryStatsService mBatteryStatsService;
710
711 /**
712 * information about component usage
713 */
714 final UsageStatsService mUsageStatsService;
715
716 /**
717 * Current configuration information. HistoryRecord objects are given
718 * a reference to this object to indicate which configuration they are
719 * currently running in, so this object must be kept immutable.
720 */
721 Configuration mConfiguration = new Configuration();
722
723 /**
724 * List of initialization arguments to pass to all processes when binding applications to them.
725 * For example, references to the commonly used services.
726 */
727 HashMap<String, IBinder> mAppBindArgs;
728
729 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700730 * Temporary to avoid allocations. Protected by main lock.
731 */
732 final StringBuilder mStringBuilder = new StringBuilder(256);
733
734 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 * Used to control how we initialize the service.
736 */
737 boolean mStartRunning = false;
738 ComponentName mTopComponent;
739 String mTopAction;
740 String mTopData;
741 boolean mSystemReady = false;
742 boolean mBooting = false;
743
744 Context mContext;
745
746 int mFactoryTest;
747
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700748 boolean mCheckedForSetup;
749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700751 * The time at which we will allow normal application switches again,
752 * after a call to {@link #stopAppSwitches()}.
753 */
754 long mAppSwitchesAllowedTime;
755
756 /**
757 * This is set to true after the first switch after mAppSwitchesAllowedTime
758 * is set; any switches after that will clear the time.
759 */
760 boolean mDidAppSwitch;
761
762 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 * Set while we are wanting to sleep, to prevent any
764 * activities from being started/resumed.
765 */
766 boolean mSleeping = false;
767
768 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700769 * Set if we are shutting down the system, similar to sleeping.
770 */
771 boolean mShuttingDown = false;
772
773 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * Set when the system is going to sleep, until we have
775 * successfully paused the current activity and released our wake lock.
776 * At that point the system is allowed to actually sleep.
777 */
778 PowerManager.WakeLock mGoingToSleep;
779
780 /**
781 * We don't want to allow the device to go to sleep while in the process
782 * of launching an activity. This is primarily to allow alarm intent
783 * receivers to launch an activity and get that to run before the device
784 * goes back to sleep.
785 */
786 PowerManager.WakeLock mLaunchingActivity;
787
788 /**
789 * Task identifier that activities are currently being started
790 * in. Incremented each time a new task is created.
791 * todo: Replace this with a TokenSpace class that generates non-repeating
792 * integers that won't wrap.
793 */
794 int mCurTask = 1;
795
796 /**
797 * Current sequence id for oom_adj computation traversal.
798 */
799 int mAdjSeq = 0;
800
801 /**
802 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
803 * is set, indicating the user wants processes started in such a way
804 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
805 * running in each process (thus no pre-initialized process, etc).
806 */
807 boolean mSimpleProcessManagement = false;
808
809 /**
810 * System monitoring: number of processes that died since the last
811 * N procs were started.
812 */
813 int[] mProcDeaths = new int[20];
814
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700815 /**
816 * This is set if we had to do a delayed dexopt of an app before launching
817 * it, to increasing the ANR timeouts in that case.
818 */
819 boolean mDidDexOpt;
820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 String mDebugApp = null;
822 boolean mWaitForDebugger = false;
823 boolean mDebugTransient = false;
824 String mOrigDebugApp = null;
825 boolean mOrigWaitForDebugger = false;
826 boolean mAlwaysFinishActivities = false;
827 IActivityWatcher mWatcher = null;
828
829 /**
830 * Callback of last caller to {@link #requestPss}.
831 */
832 Runnable mRequestPssCallback;
833
834 /**
835 * Remaining processes for which we are waiting results from the last
836 * call to {@link #requestPss}.
837 */
838 final ArrayList<ProcessRecord> mRequestPssList
839 = new ArrayList<ProcessRecord>();
840
841 /**
842 * Runtime statistics collection thread. This object's lock is used to
843 * protect all related state.
844 */
845 final Thread mProcessStatsThread;
846
847 /**
848 * Used to collect process stats when showing not responding dialog.
849 * Protected by mProcessStatsThread.
850 */
851 final ProcessStats mProcessStats = new ProcessStats(
852 MONITOR_THREAD_CPU_USAGE);
853 long mLastCpuTime = 0;
854 long mLastWriteTime = 0;
855
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700856 long mInitialStartTime = 0;
857
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 /**
859 * Set to true after the system has finished booting.
860 */
861 boolean mBooted = false;
862
863 int mProcessLimit = 0;
864
865 WindowManagerService mWindowManager;
866
867 static ActivityManagerService mSelf;
868 static ActivityThread mSystemThread;
869
870 private final class AppDeathRecipient implements IBinder.DeathRecipient {
871 final ProcessRecord mApp;
872 final int mPid;
873 final IApplicationThread mAppThread;
874
875 AppDeathRecipient(ProcessRecord app, int pid,
876 IApplicationThread thread) {
877 if (localLOGV) Log.v(
878 TAG, "New death recipient " + this
879 + " for thread " + thread.asBinder());
880 mApp = app;
881 mPid = pid;
882 mAppThread = thread;
883 }
884
885 public void binderDied() {
886 if (localLOGV) Log.v(
887 TAG, "Death received in " + this
888 + " for thread " + mAppThread.asBinder());
889 removeRequestedPss(mApp);
890 synchronized(ActivityManagerService.this) {
891 appDiedLocked(mApp, mPid, mAppThread);
892 }
893 }
894 }
895
896 static final int SHOW_ERROR_MSG = 1;
897 static final int SHOW_NOT_RESPONDING_MSG = 2;
898 static final int SHOW_FACTORY_ERROR_MSG = 3;
899 static final int UPDATE_CONFIGURATION_MSG = 4;
900 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
901 static final int WAIT_FOR_DEBUGGER_MSG = 6;
902 static final int BROADCAST_INTENT_MSG = 7;
903 static final int BROADCAST_TIMEOUT_MSG = 8;
904 static final int PAUSE_TIMEOUT_MSG = 9;
905 static final int IDLE_TIMEOUT_MSG = 10;
906 static final int IDLE_NOW_MSG = 11;
907 static final int SERVICE_TIMEOUT_MSG = 12;
908 static final int UPDATE_TIME_ZONE = 13;
909 static final int SHOW_UID_ERROR_MSG = 14;
910 static final int IM_FEELING_LUCKY_MSG = 15;
911 static final int LAUNCH_TIMEOUT_MSG = 16;
912 static final int DESTROY_TIMEOUT_MSG = 17;
913 static final int SERVICE_ERROR_MSG = 18;
914 static final int RESUME_TOP_ACTIVITY_MSG = 19;
915 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700916 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917
918 AlertDialog mUidAlert;
919
920 final Handler mHandler = new Handler() {
921 //public Handler() {
922 // if (localLOGV) Log.v(TAG, "Handler started!");
923 //}
924
925 public void handleMessage(Message msg) {
926 switch (msg.what) {
927 case SHOW_ERROR_MSG: {
928 HashMap data = (HashMap) msg.obj;
929 byte[] crashData = (byte[])data.get("crashData");
930 if (crashData != null) {
931 // This needs to be *un*synchronized to avoid deadlock.
932 ContentResolver resolver = mContext.getContentResolver();
933 Checkin.reportCrash(resolver, crashData);
934 }
935 synchronized (ActivityManagerService.this) {
936 ProcessRecord proc = (ProcessRecord)data.get("app");
937 if (proc != null && proc.crashDialog != null) {
938 Log.e(TAG, "App already has crash dialog: " + proc);
939 return;
940 }
941 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700942 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 Dialog d = new AppErrorDialog(
944 mContext, res, proc,
945 (Integer)data.get("flags"),
946 (String)data.get("shortMsg"),
947 (String)data.get("longMsg"));
948 d.show();
949 proc.crashDialog = d;
950 } else {
951 // The device is asleep, so just pretend that the user
952 // saw a crash dialog and hit "force quit".
953 res.set(0);
954 }
955 }
956 } break;
957 case SHOW_NOT_RESPONDING_MSG: {
958 synchronized (ActivityManagerService.this) {
959 HashMap data = (HashMap) msg.obj;
960 ProcessRecord proc = (ProcessRecord)data.get("app");
961 if (proc != null && proc.anrDialog != null) {
962 Log.e(TAG, "App already has anr dialog: " + proc);
963 return;
964 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800965
966 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
967 null, null, 0, null, null, null,
968 false, false, MY_PID, Process.SYSTEM_UID);
969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
971 mContext, proc, (HistoryRecord)data.get("activity"));
972 d.show();
973 proc.anrDialog = d;
974 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700975
976 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 } break;
978 case SHOW_FACTORY_ERROR_MSG: {
979 Dialog d = new FactoryErrorDialog(
980 mContext, msg.getData().getCharSequence("msg"));
981 d.show();
982 enableScreenAfterBoot();
983 } break;
984 case UPDATE_CONFIGURATION_MSG: {
985 final ContentResolver resolver = mContext.getContentResolver();
986 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
987 } break;
988 case GC_BACKGROUND_PROCESSES_MSG: {
989 synchronized (ActivityManagerService.this) {
990 performAppGcsIfAppropriateLocked();
991 }
992 } break;
993 case WAIT_FOR_DEBUGGER_MSG: {
994 synchronized (ActivityManagerService.this) {
995 ProcessRecord app = (ProcessRecord)msg.obj;
996 if (msg.arg1 != 0) {
997 if (!app.waitedForDebugger) {
998 Dialog d = new AppWaitingForDebuggerDialog(
999 ActivityManagerService.this,
1000 mContext, app);
1001 app.waitDialog = d;
1002 app.waitedForDebugger = true;
1003 d.show();
1004 }
1005 } else {
1006 if (app.waitDialog != null) {
1007 app.waitDialog.dismiss();
1008 app.waitDialog = null;
1009 }
1010 }
1011 }
1012 } break;
1013 case BROADCAST_INTENT_MSG: {
1014 if (DEBUG_BROADCAST) Log.v(
1015 TAG, "Received BROADCAST_INTENT_MSG");
1016 processNextBroadcast(true);
1017 } break;
1018 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001019 if (mDidDexOpt) {
1020 mDidDexOpt = false;
1021 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1022 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1023 return;
1024 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 broadcastTimeout();
1026 } break;
1027 case PAUSE_TIMEOUT_MSG: {
1028 IBinder token = (IBinder)msg.obj;
1029 // We don't at this point know if the activity is fullscreen,
1030 // so we need to be conservative and assume it isn't.
1031 Log.w(TAG, "Activity pause timeout for " + token);
1032 activityPaused(token, null, true);
1033 } break;
1034 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001035 if (mDidDexOpt) {
1036 mDidDexOpt = false;
1037 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1038 nmsg.obj = msg.obj;
1039 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1040 return;
1041 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 // We don't at this point know if the activity is fullscreen,
1043 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001044 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001045 Log.w(TAG, "Activity idle timeout for " + token);
1046 activityIdleInternal(token, true);
1047 } break;
1048 case DESTROY_TIMEOUT_MSG: {
1049 IBinder token = (IBinder)msg.obj;
1050 // We don't at this point know if the activity is fullscreen,
1051 // so we need to be conservative and assume it isn't.
1052 Log.w(TAG, "Activity destroy timeout for " + token);
1053 activityDestroyed(token);
1054 } break;
1055 case IDLE_NOW_MSG: {
1056 IBinder token = (IBinder)msg.obj;
1057 activityIdle(token);
1058 } break;
1059 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001060 if (mDidDexOpt) {
1061 mDidDexOpt = false;
1062 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1063 nmsg.obj = msg.obj;
1064 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1065 return;
1066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 serviceTimeout((ProcessRecord)msg.obj);
1068 } break;
1069 case UPDATE_TIME_ZONE: {
1070 synchronized (ActivityManagerService.this) {
1071 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1072 ProcessRecord r = mLRUProcesses.get(i);
1073 if (r.thread != null) {
1074 try {
1075 r.thread.updateTimeZone();
1076 } catch (RemoteException ex) {
1077 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1078 }
1079 }
1080 }
1081 }
1082 break;
1083 }
1084 case SHOW_UID_ERROR_MSG: {
1085 // XXX This is a temporary dialog, no need to localize.
1086 AlertDialog d = new BaseErrorDialog(mContext);
1087 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1088 d.setCancelable(false);
1089 d.setTitle("System UIDs Inconsistent");
1090 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1091 d.setButton("I'm Feeling Lucky",
1092 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1093 mUidAlert = d;
1094 d.show();
1095 } break;
1096 case IM_FEELING_LUCKY_MSG: {
1097 if (mUidAlert != null) {
1098 mUidAlert.dismiss();
1099 mUidAlert = null;
1100 }
1101 } break;
1102 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001103 if (mDidDexOpt) {
1104 mDidDexOpt = false;
1105 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1106 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1107 return;
1108 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 synchronized (ActivityManagerService.this) {
1110 if (mLaunchingActivity.isHeld()) {
1111 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1112 mLaunchingActivity.release();
1113 }
1114 }
1115 } break;
1116 case SERVICE_ERROR_MSG: {
1117 ServiceRecord srv = (ServiceRecord)msg.obj;
1118 // This needs to be *un*synchronized to avoid deadlock.
1119 Checkin.logEvent(mContext.getContentResolver(),
1120 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1121 srv.name.toShortString());
1122 } break;
1123 case RESUME_TOP_ACTIVITY_MSG: {
1124 synchronized (ActivityManagerService.this) {
1125 resumeTopActivityLocked(null);
1126 }
1127 }
1128 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001129 if (mDidDexOpt) {
1130 mDidDexOpt = false;
1131 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1132 nmsg.obj = msg.obj;
1133 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1134 return;
1135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 ProcessRecord app = (ProcessRecord)msg.obj;
1137 synchronized (ActivityManagerService.this) {
1138 processStartTimedOutLocked(app);
1139 }
1140 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001141 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1142 synchronized (ActivityManagerService.this) {
1143 doPendingActivityLaunchesLocked(true);
1144 }
1145 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 }
1147 }
1148 };
1149
1150 public static void setSystemProcess() {
1151 try {
1152 ActivityManagerService m = mSelf;
1153
1154 ServiceManager.addService("activity", m);
1155 ServiceManager.addService("meminfo", new MemBinder(m));
1156 if (MONITOR_CPU_USAGE) {
1157 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1158 }
1159 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1160 ServiceManager.addService("activity.services", new ServicesBinder(m));
1161 ServiceManager.addService("activity.senders", new SendersBinder(m));
1162 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1163 ServiceManager.addService("permission", new PermissionController(m));
1164
1165 ApplicationInfo info =
1166 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001167 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 synchronized (mSelf) {
1169 ProcessRecord app = mSelf.newProcessRecordLocked(
1170 mSystemThread.getApplicationThread(), info,
1171 info.processName);
1172 app.persistent = true;
1173 app.pid = Process.myPid();
1174 app.maxAdj = SYSTEM_ADJ;
1175 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1176 synchronized (mSelf.mPidsSelfLocked) {
1177 mSelf.mPidsSelfLocked.put(app.pid, app);
1178 }
1179 mSelf.updateLRUListLocked(app, true);
1180 }
1181 } catch (PackageManager.NameNotFoundException e) {
1182 throw new RuntimeException(
1183 "Unable to find android system package", e);
1184 }
1185 }
1186
1187 public void setWindowManager(WindowManagerService wm) {
1188 mWindowManager = wm;
1189 }
1190
1191 public static final Context main(int factoryTest) {
1192 AThread thr = new AThread();
1193 thr.start();
1194
1195 synchronized (thr) {
1196 while (thr.mService == null) {
1197 try {
1198 thr.wait();
1199 } catch (InterruptedException e) {
1200 }
1201 }
1202 }
1203
1204 ActivityManagerService m = thr.mService;
1205 mSelf = m;
1206 ActivityThread at = ActivityThread.systemMain();
1207 mSystemThread = at;
1208 Context context = at.getSystemContext();
1209 m.mContext = context;
1210 m.mFactoryTest = factoryTest;
1211 PowerManager pm =
1212 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1213 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1214 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1215 m.mLaunchingActivity.setReferenceCounted(false);
1216
1217 m.mBatteryStatsService.publish(context);
1218 m.mUsageStatsService.publish(context);
1219
1220 synchronized (thr) {
1221 thr.mReady = true;
1222 thr.notifyAll();
1223 }
1224
1225 m.startRunning(null, null, null, null);
1226
1227 return context;
1228 }
1229
1230 public static ActivityManagerService self() {
1231 return mSelf;
1232 }
1233
1234 static class AThread extends Thread {
1235 ActivityManagerService mService;
1236 boolean mReady = false;
1237
1238 public AThread() {
1239 super("ActivityManager");
1240 }
1241
1242 public void run() {
1243 Looper.prepare();
1244
1245 android.os.Process.setThreadPriority(
1246 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1247
1248 ActivityManagerService m = new ActivityManagerService();
1249
1250 synchronized (this) {
1251 mService = m;
1252 notifyAll();
1253 }
1254
1255 synchronized (this) {
1256 while (!mReady) {
1257 try {
1258 wait();
1259 } catch (InterruptedException e) {
1260 }
1261 }
1262 }
1263
1264 Looper.loop();
1265 }
1266 }
1267
1268 static class BroadcastsBinder extends Binder {
1269 ActivityManagerService mActivityManagerService;
1270 BroadcastsBinder(ActivityManagerService activityManagerService) {
1271 mActivityManagerService = activityManagerService;
1272 }
1273
1274 @Override
1275 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1276 mActivityManagerService.dumpBroadcasts(pw);
1277 }
1278 }
1279
1280 static class ServicesBinder extends Binder {
1281 ActivityManagerService mActivityManagerService;
1282 ServicesBinder(ActivityManagerService activityManagerService) {
1283 mActivityManagerService = activityManagerService;
1284 }
1285
1286 @Override
1287 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1288 mActivityManagerService.dumpServices(pw);
1289 }
1290 }
1291
1292 static class SendersBinder extends Binder {
1293 ActivityManagerService mActivityManagerService;
1294 SendersBinder(ActivityManagerService activityManagerService) {
1295 mActivityManagerService = activityManagerService;
1296 }
1297
1298 @Override
1299 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1300 mActivityManagerService.dumpSenders(pw);
1301 }
1302 }
1303
1304 static class ProvidersBinder extends Binder {
1305 ActivityManagerService mActivityManagerService;
1306 ProvidersBinder(ActivityManagerService activityManagerService) {
1307 mActivityManagerService = activityManagerService;
1308 }
1309
1310 @Override
1311 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1312 mActivityManagerService.dumpProviders(pw);
1313 }
1314 }
1315
1316 static class MemBinder extends Binder {
1317 ActivityManagerService mActivityManagerService;
1318 MemBinder(ActivityManagerService activityManagerService) {
1319 mActivityManagerService = activityManagerService;
1320 }
1321
1322 @Override
1323 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1324 ActivityManagerService service = mActivityManagerService;
1325 ArrayList<ProcessRecord> procs;
1326 synchronized (mActivityManagerService) {
1327 if (args != null && args.length > 0
1328 && args[0].charAt(0) != '-') {
1329 procs = new ArrayList<ProcessRecord>();
1330 int pid = -1;
1331 try {
1332 pid = Integer.parseInt(args[0]);
1333 } catch (NumberFormatException e) {
1334
1335 }
1336 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1337 ProcessRecord proc = service.mLRUProcesses.get(i);
1338 if (proc.pid == pid) {
1339 procs.add(proc);
1340 } else if (proc.processName.equals(args[0])) {
1341 procs.add(proc);
1342 }
1343 }
1344 if (procs.size() <= 0) {
1345 pw.println("No process found for: " + args[0]);
1346 return;
1347 }
1348 } else {
1349 procs = service.mLRUProcesses;
1350 }
1351 }
1352 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1353 }
1354 }
1355
1356 static class CpuBinder extends Binder {
1357 ActivityManagerService mActivityManagerService;
1358 CpuBinder(ActivityManagerService activityManagerService) {
1359 mActivityManagerService = activityManagerService;
1360 }
1361
1362 @Override
1363 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1364 synchronized (mActivityManagerService.mProcessStatsThread) {
1365 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1366 }
1367 }
1368 }
1369
1370 private ActivityManagerService() {
1371 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1372 if (v != null && Integer.getInteger(v) != 0) {
1373 mSimpleProcessManagement = true;
1374 }
1375 v = System.getenv("ANDROID_DEBUG_APP");
1376 if (v != null) {
1377 mSimpleProcessManagement = true;
1378 }
1379
1380 MY_PID = Process.myPid();
1381
1382 File dataDir = Environment.getDataDirectory();
1383 File systemDir = new File(dataDir, "system");
1384 systemDir.mkdirs();
1385 mBatteryStatsService = new BatteryStatsService(new File(
1386 systemDir, "batterystats.bin").toString());
1387 mBatteryStatsService.getActiveStatistics().readLocked();
1388 mBatteryStatsService.getActiveStatistics().writeLocked();
1389
1390 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001391 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392
1393 mConfiguration.makeDefault();
1394 mProcessStats.init();
1395
1396 // Add ourself to the Watchdog monitors.
1397 Watchdog.getInstance().addMonitor(this);
1398
1399 // These values are set in system/rootdir/init.rc on startup.
1400 FOREGROUND_APP_ADJ =
1401 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1402 VISIBLE_APP_ADJ =
1403 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1404 SECONDARY_SERVER_ADJ =
1405 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001406 BACKUP_APP_ADJ =
1407 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001408 HOME_APP_ADJ =
1409 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 HIDDEN_APP_MIN_ADJ =
1411 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1412 CONTENT_PROVIDER_ADJ =
1413 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1414 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1415 EMPTY_APP_ADJ =
1416 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1417 FOREGROUND_APP_MEM =
1418 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1419 VISIBLE_APP_MEM =
1420 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1421 SECONDARY_SERVER_MEM =
1422 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001423 BACKUP_APP_MEM =
1424 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001425 HOME_APP_MEM =
1426 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 HIDDEN_APP_MEM =
1428 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1429 EMPTY_APP_MEM =
1430 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1431
1432 mProcessStatsThread = new Thread("ProcessStats") {
1433 public void run() {
1434 while (true) {
1435 try {
1436 try {
1437 synchronized(this) {
1438 final long now = SystemClock.uptimeMillis();
1439 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1440 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1441 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1442 // + ", write delay=" + nextWriteDelay);
1443 if (nextWriteDelay < nextCpuDelay) {
1444 nextCpuDelay = nextWriteDelay;
1445 }
1446 if (nextCpuDelay > 0) {
1447 this.wait(nextCpuDelay);
1448 }
1449 }
1450 } catch (InterruptedException e) {
1451 }
1452
1453 updateCpuStatsNow();
1454 } catch (Exception e) {
1455 Log.e(TAG, "Unexpected exception collecting process stats", e);
1456 }
1457 }
1458 }
1459 };
1460 mProcessStatsThread.start();
1461 }
1462
1463 @Override
1464 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1465 throws RemoteException {
1466 try {
1467 return super.onTransact(code, data, reply, flags);
1468 } catch (RuntimeException e) {
1469 // The activity manager only throws security exceptions, so let's
1470 // log all others.
1471 if (!(e instanceof SecurityException)) {
1472 Log.e(TAG, "Activity Manager Crash", e);
1473 }
1474 throw e;
1475 }
1476 }
1477
1478 void updateCpuStats() {
1479 synchronized (mProcessStatsThread) {
1480 final long now = SystemClock.uptimeMillis();
1481 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1482 mProcessStatsThread.notify();
1483 }
1484 }
1485 }
1486
1487 void updateCpuStatsNow() {
1488 synchronized (mProcessStatsThread) {
1489 final long now = SystemClock.uptimeMillis();
1490 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 if (MONITOR_CPU_USAGE &&
1493 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1494 mLastCpuTime = now;
1495 haveNewCpuStats = true;
1496 mProcessStats.update();
1497 //Log.i(TAG, mProcessStats.printCurrentState());
1498 //Log.i(TAG, "Total CPU usage: "
1499 // + mProcessStats.getTotalCpuPercent() + "%");
1500
1501 // Log the cpu usage if the property is set.
1502 if ("true".equals(SystemProperties.get("events.cpu"))) {
1503 int user = mProcessStats.getLastUserTime();
1504 int system = mProcessStats.getLastSystemTime();
1505 int iowait = mProcessStats.getLastIoWaitTime();
1506 int irq = mProcessStats.getLastIrqTime();
1507 int softIrq = mProcessStats.getLastSoftIrqTime();
1508 int idle = mProcessStats.getLastIdleTime();
1509
1510 int total = user + system + iowait + irq + softIrq + idle;
1511 if (total == 0) total = 1;
1512
1513 EventLog.writeEvent(LOG_CPU,
1514 ((user+system+iowait+irq+softIrq) * 100) / total,
1515 (user * 100) / total,
1516 (system * 100) / total,
1517 (iowait * 100) / total,
1518 (irq * 100) / total,
1519 (softIrq * 100) / total);
1520 }
1521 }
1522
Amith Yamasani819f9282009-06-24 23:18:15 -07001523 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001524 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 synchronized(mPidsSelfLocked) {
1526 if (haveNewCpuStats) {
1527 if (mBatteryStatsService.isOnBattery()) {
1528 final int N = mProcessStats.countWorkingStats();
1529 for (int i=0; i<N; i++) {
1530 ProcessStats.Stats st
1531 = mProcessStats.getWorkingStats(i);
1532 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1533 if (pr != null) {
1534 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1535 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001536 } else {
1537 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001538 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001539 if (ps != null) {
1540 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 }
1543 }
1544 }
1545 }
1546 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1549 mLastWriteTime = now;
1550 mBatteryStatsService.getActiveStatistics().writeLocked();
1551 }
1552 }
1553 }
1554 }
1555
1556 /**
1557 * Initialize the application bind args. These are passed to each
1558 * process when the bindApplication() IPC is sent to the process. They're
1559 * lazily setup to make sure the services are running when they're asked for.
1560 */
1561 private HashMap<String, IBinder> getCommonServicesLocked() {
1562 if (mAppBindArgs == null) {
1563 mAppBindArgs = new HashMap<String, IBinder>();
1564
1565 // Setup the application init args
1566 mAppBindArgs.put("package", ServiceManager.getService("package"));
1567 mAppBindArgs.put("window", ServiceManager.getService("window"));
1568 mAppBindArgs.put(Context.ALARM_SERVICE,
1569 ServiceManager.getService(Context.ALARM_SERVICE));
1570 }
1571 return mAppBindArgs;
1572 }
1573
1574 private final void setFocusedActivityLocked(HistoryRecord r) {
1575 if (mFocusedActivity != r) {
1576 mFocusedActivity = r;
1577 mWindowManager.setFocusedApp(r, true);
1578 }
1579 }
1580
1581 private final void updateLRUListLocked(ProcessRecord app,
1582 boolean oomAdj) {
1583 // put it on the LRU to keep track of when it should be exited.
1584 int lrui = mLRUProcesses.indexOf(app);
1585 if (lrui >= 0) mLRUProcesses.remove(lrui);
1586 mLRUProcesses.add(app);
1587 //Log.i(TAG, "Putting proc to front: " + app.processName);
1588 if (oomAdj) {
1589 updateOomAdjLocked();
1590 }
1591 }
1592
1593 private final boolean updateLRUListLocked(HistoryRecord r) {
1594 final boolean hadit = mLRUActivities.remove(r);
1595 mLRUActivities.add(r);
1596 return hadit;
1597 }
1598
1599 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1600 int i = mHistory.size()-1;
1601 while (i >= 0) {
1602 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1603 if (!r.finishing && r != notTop) {
1604 return r;
1605 }
1606 i--;
1607 }
1608 return null;
1609 }
1610
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001611 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1612 int i = mHistory.size()-1;
1613 while (i >= 0) {
1614 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1615 if (!r.finishing && !r.delayedResume && r != notTop) {
1616 return r;
1617 }
1618 i--;
1619 }
1620 return null;
1621 }
1622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 /**
1624 * This is a simplified version of topRunningActivityLocked that provides a number of
1625 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1626 *
1627 * @param token If non-null, any history records matching this token will be skipped.
1628 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1629 *
1630 * @return Returns the HistoryRecord of the next activity on the stack.
1631 */
1632 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1633 int i = mHistory.size()-1;
1634 while (i >= 0) {
1635 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1636 // Note: the taskId check depends on real taskId fields being non-zero
1637 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1638 return r;
1639 }
1640 i--;
1641 }
1642 return null;
1643 }
1644
1645 private final ProcessRecord getProcessRecordLocked(
1646 String processName, int uid) {
1647 if (uid == Process.SYSTEM_UID) {
1648 // The system gets to run in any process. If there are multiple
1649 // processes with the same uid, just pick the first (this
1650 // should never happen).
1651 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1652 processName);
1653 return procs != null ? procs.valueAt(0) : null;
1654 }
1655 ProcessRecord proc = mProcessNames.get(processName, uid);
1656 return proc;
1657 }
1658
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001659 private void ensurePackageDexOpt(String packageName) {
1660 IPackageManager pm = ActivityThread.getPackageManager();
1661 try {
1662 if (pm.performDexOpt(packageName)) {
1663 mDidDexOpt = true;
1664 }
1665 } catch (RemoteException e) {
1666 }
1667 }
1668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 private boolean isNextTransitionForward() {
1670 int transit = mWindowManager.getPendingAppTransition();
1671 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1672 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1673 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1674 }
1675
1676 private final boolean realStartActivityLocked(HistoryRecord r,
1677 ProcessRecord app, boolean andResume, boolean checkConfig)
1678 throws RemoteException {
1679
1680 r.startFreezingScreenLocked(app, 0);
1681 mWindowManager.setAppVisibility(r, true);
1682
1683 // Have the window manager re-evaluate the orientation of
1684 // the screen based on the new activity order. Note that
1685 // as a result of this, it can call back into the activity
1686 // manager with a new orientation. We don't care about that,
1687 // because the activity is not currently running so we are
1688 // just restarting it anyway.
1689 if (checkConfig) {
1690 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001691 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 r.mayFreezeScreenLocked(app) ? r : null);
1693 updateConfigurationLocked(config, r);
1694 }
1695
1696 r.app = app;
1697
1698 if (localLOGV) Log.v(TAG, "Launching: " + r);
1699
1700 int idx = app.activities.indexOf(r);
1701 if (idx < 0) {
1702 app.activities.add(r);
1703 }
1704 updateLRUListLocked(app, true);
1705
1706 try {
1707 if (app.thread == null) {
1708 throw new RemoteException();
1709 }
1710 List<ResultInfo> results = null;
1711 List<Intent> newIntents = null;
1712 if (andResume) {
1713 results = r.results;
1714 newIntents = r.newIntents;
1715 }
1716 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1717 + " icicle=" + r.icicle
1718 + " with results=" + results + " newIntents=" + newIntents
1719 + " andResume=" + andResume);
1720 if (andResume) {
1721 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1722 System.identityHashCode(r),
1723 r.task.taskId, r.shortComponentName);
1724 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001725 if (r.isHomeActivity) {
1726 mHomeProcess = app;
1727 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001728 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1730 r.info, r.icicle, results, newIntents, !andResume,
1731 isNextTransitionForward());
1732 // Update usage stats for launched activity
1733 updateUsageStats(r, true);
1734 } catch (RemoteException e) {
1735 if (r.launchFailed) {
1736 // This is the second time we failed -- finish activity
1737 // and give up.
1738 Log.e(TAG, "Second failure launching "
1739 + r.intent.getComponent().flattenToShortString()
1740 + ", giving up", e);
1741 appDiedLocked(app, app.pid, app.thread);
1742 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1743 "2nd-crash");
1744 return false;
1745 }
1746
1747 // This is the first time we failed -- restart process and
1748 // retry.
1749 app.activities.remove(r);
1750 throw e;
1751 }
1752
1753 r.launchFailed = false;
1754 if (updateLRUListLocked(r)) {
1755 Log.w(TAG, "Activity " + r
1756 + " being launched, but already in LRU list");
1757 }
1758
1759 if (andResume) {
1760 // As part of the process of launching, ActivityThread also performs
1761 // a resume.
1762 r.state = ActivityState.RESUMED;
1763 r.icicle = null;
1764 r.haveState = false;
1765 r.stopped = false;
1766 mResumedActivity = r;
1767 r.task.touchActiveTime();
1768 completeResumeLocked(r);
1769 pauseIfSleepingLocked();
1770 } else {
1771 // This activity is not starting in the resumed state... which
1772 // should look like we asked it to pause+stop (but remain visible),
1773 // and it has done so and reported back the current icicle and
1774 // other state.
1775 r.state = ActivityState.STOPPED;
1776 r.stopped = true;
1777 }
1778
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001779 // Launch the new version setup screen if needed. We do this -after-
1780 // launching the initial activity (that is, home), so that it can have
1781 // a chance to initialize itself while in the background, making the
1782 // switch back to it faster and look better.
1783 startSetupActivityLocked();
1784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 return true;
1786 }
1787
1788 private final void startSpecificActivityLocked(HistoryRecord r,
1789 boolean andResume, boolean checkConfig) {
1790 // Is this activity's application already running?
1791 ProcessRecord app = getProcessRecordLocked(r.processName,
1792 r.info.applicationInfo.uid);
1793
1794 if (r.startTime == 0) {
1795 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001796 if (mInitialStartTime == 0) {
1797 mInitialStartTime = r.startTime;
1798 }
1799 } else if (mInitialStartTime == 0) {
1800 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 }
1802
1803 if (app != null && app.thread != null) {
1804 try {
1805 realStartActivityLocked(r, app, andResume, checkConfig);
1806 return;
1807 } catch (RemoteException e) {
1808 Log.w(TAG, "Exception when starting activity "
1809 + r.intent.getComponent().flattenToShortString(), e);
1810 }
1811
1812 // If a dead object exception was thrown -- fall through to
1813 // restart the application.
1814 }
1815
1816 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1817 "activity", r.intent.getComponent());
1818 }
1819
1820 private final ProcessRecord startProcessLocked(String processName,
1821 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1822 String hostingType, ComponentName hostingName) {
1823 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1824 // We don't have to do anything more if:
1825 // (1) There is an existing application record; and
1826 // (2) The caller doesn't think it is dead, OR there is no thread
1827 // object attached to it so we know it couldn't have crashed; and
1828 // (3) There is a pid assigned to it, so it is either starting or
1829 // already running.
1830 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1831 + " app=" + app + " knownToBeDead=" + knownToBeDead
1832 + " thread=" + (app != null ? app.thread : null)
1833 + " pid=" + (app != null ? app.pid : -1));
1834 if (app != null &&
1835 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1836 return app;
1837 }
1838
1839 String hostingNameStr = hostingName != null
1840 ? hostingName.flattenToShortString() : null;
1841
1842 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1843 // If we are in the background, then check to see if this process
1844 // is bad. If so, we will just silently fail.
1845 if (mBadProcesses.get(info.processName, info.uid) != null) {
1846 return null;
1847 }
1848 } else {
1849 // When the user is explicitly starting a process, then clear its
1850 // crash count so that we won't make it bad until they see at
1851 // least one crash dialog again, and make the process good again
1852 // if it had been bad.
1853 mProcessCrashTimes.remove(info.processName, info.uid);
1854 if (mBadProcesses.get(info.processName, info.uid) != null) {
1855 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1856 info.processName);
1857 mBadProcesses.remove(info.processName, info.uid);
1858 if (app != null) {
1859 app.bad = false;
1860 }
1861 }
1862 }
1863
1864 if (app == null) {
1865 app = newProcessRecordLocked(null, info, processName);
1866 mProcessNames.put(processName, info.uid, app);
1867 } else {
1868 // If this is a new package in the process, add the package to the list
1869 app.addPackage(info.packageName);
1870 }
1871
1872 // If the system is not ready yet, then hold off on starting this
1873 // process until it is.
1874 if (!mSystemReady
1875 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1876 if (!mProcessesOnHold.contains(app)) {
1877 mProcessesOnHold.add(app);
1878 }
1879 return app;
1880 }
1881
1882 startProcessLocked(app, hostingType, hostingNameStr);
1883 return (app.pid != 0) ? app : null;
1884 }
1885
1886 private final void startProcessLocked(ProcessRecord app,
1887 String hostingType, String hostingNameStr) {
1888 if (app.pid > 0 && app.pid != MY_PID) {
1889 synchronized (mPidsSelfLocked) {
1890 mPidsSelfLocked.remove(app.pid);
1891 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1892 }
1893 app.pid = 0;
1894 }
1895
1896 mProcessesOnHold.remove(app);
1897
1898 updateCpuStats();
1899
1900 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1901 mProcDeaths[0] = 0;
1902
1903 try {
1904 int uid = app.info.uid;
1905 int[] gids = null;
1906 try {
1907 gids = mContext.getPackageManager().getPackageGids(
1908 app.info.packageName);
1909 } catch (PackageManager.NameNotFoundException e) {
1910 Log.w(TAG, "Unable to retrieve gids", e);
1911 }
1912 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1913 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1914 && mTopComponent != null
1915 && app.processName.equals(mTopComponent.getPackageName())) {
1916 uid = 0;
1917 }
1918 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1919 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1920 uid = 0;
1921 }
1922 }
1923 int debugFlags = 0;
1924 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1925 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1926 }
1927 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1928 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1929 }
1930 if ("1".equals(SystemProperties.get("debug.assert"))) {
1931 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1932 }
1933 int pid = Process.start("android.app.ActivityThread",
1934 mSimpleProcessManagement ? app.processName : null, uid, uid,
1935 gids, debugFlags, null);
1936 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1937 synchronized (bs) {
1938 if (bs.isOnBattery()) {
1939 app.batteryStats.incStartsLocked();
1940 }
1941 }
1942
1943 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1944 app.processName, hostingType,
1945 hostingNameStr != null ? hostingNameStr : "");
1946
1947 if (app.persistent) {
1948 Watchdog.getInstance().processStarted(app, app.processName, pid);
1949 }
1950
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001951 StringBuilder buf = mStringBuilder;
1952 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 buf.append("Start proc ");
1954 buf.append(app.processName);
1955 buf.append(" for ");
1956 buf.append(hostingType);
1957 if (hostingNameStr != null) {
1958 buf.append(" ");
1959 buf.append(hostingNameStr);
1960 }
1961 buf.append(": pid=");
1962 buf.append(pid);
1963 buf.append(" uid=");
1964 buf.append(uid);
1965 buf.append(" gids={");
1966 if (gids != null) {
1967 for (int gi=0; gi<gids.length; gi++) {
1968 if (gi != 0) buf.append(", ");
1969 buf.append(gids[gi]);
1970
1971 }
1972 }
1973 buf.append("}");
1974 Log.i(TAG, buf.toString());
1975 if (pid == 0 || pid == MY_PID) {
1976 // Processes are being emulated with threads.
1977 app.pid = MY_PID;
1978 app.removed = false;
1979 mStartingProcesses.add(app);
1980 } else if (pid > 0) {
1981 app.pid = pid;
1982 app.removed = false;
1983 synchronized (mPidsSelfLocked) {
1984 this.mPidsSelfLocked.put(pid, app);
1985 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1986 msg.obj = app;
1987 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1988 }
1989 } else {
1990 app.pid = 0;
1991 RuntimeException e = new RuntimeException(
1992 "Failure starting process " + app.processName
1993 + ": returned pid=" + pid);
1994 Log.e(TAG, e.getMessage(), e);
1995 }
1996 } catch (RuntimeException e) {
1997 // XXX do better error recovery.
1998 app.pid = 0;
1999 Log.e(TAG, "Failure starting process " + app.processName, e);
2000 }
2001 }
2002
2003 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2004 if (mPausingActivity != null) {
2005 RuntimeException e = new RuntimeException();
2006 Log.e(TAG, "Trying to pause when pause is already pending for "
2007 + mPausingActivity, e);
2008 }
2009 HistoryRecord prev = mResumedActivity;
2010 if (prev == null) {
2011 RuntimeException e = new RuntimeException();
2012 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2013 resumeTopActivityLocked(null);
2014 return;
2015 }
2016 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2017 mResumedActivity = null;
2018 mPausingActivity = prev;
2019 mLastPausedActivity = prev;
2020 prev.state = ActivityState.PAUSING;
2021 prev.task.touchActiveTime();
2022
2023 updateCpuStats();
2024
2025 if (prev.app != null && prev.app.thread != null) {
2026 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2027 try {
2028 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2029 System.identityHashCode(prev),
2030 prev.shortComponentName);
2031 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2032 prev.configChangeFlags);
2033 updateUsageStats(prev, false);
2034 } catch (Exception e) {
2035 // Ignore exception, if process died other code will cleanup.
2036 Log.w(TAG, "Exception thrown during pause", e);
2037 mPausingActivity = null;
2038 mLastPausedActivity = null;
2039 }
2040 } else {
2041 mPausingActivity = null;
2042 mLastPausedActivity = null;
2043 }
2044
2045 // If we are not going to sleep, we want to ensure the device is
2046 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002047 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 mLaunchingActivity.acquire();
2049 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2050 // To be safe, don't allow the wake lock to be held for too long.
2051 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2052 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2053 }
2054 }
2055
2056
2057 if (mPausingActivity != null) {
2058 // Have the window manager pause its key dispatching until the new
2059 // activity has started. If we're pausing the activity just because
2060 // the screen is being turned off and the UI is sleeping, don't interrupt
2061 // key dispatch; the same activity will pick it up again on wakeup.
2062 if (!uiSleeping) {
2063 prev.pauseKeyDispatchingLocked();
2064 } else {
2065 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2066 }
2067
2068 // Schedule a pause timeout in case the app doesn't respond.
2069 // We don't give it much time because this directly impacts the
2070 // responsiveness seen by the user.
2071 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2072 msg.obj = prev;
2073 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2074 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2075 } else {
2076 // This activity failed to schedule the
2077 // pause, so just treat it as being paused now.
2078 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2079 resumeTopActivityLocked(null);
2080 }
2081 }
2082
2083 private final void completePauseLocked() {
2084 HistoryRecord prev = mPausingActivity;
2085 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2086
2087 if (prev != null) {
2088 if (prev.finishing) {
2089 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2090 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2091 } else if (prev.app != null) {
2092 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2093 if (prev.waitingVisible) {
2094 prev.waitingVisible = false;
2095 mWaitingVisibleActivities.remove(prev);
2096 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2097 TAG, "Complete pause, no longer waiting: " + prev);
2098 }
2099 if (prev.configDestroy) {
2100 // The previous is being paused because the configuration
2101 // is changing, which means it is actually stopping...
2102 // To juggle the fact that we are also starting a new
2103 // instance right now, we need to first completely stop
2104 // the current instance before starting the new one.
2105 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2106 destroyActivityLocked(prev, true);
2107 } else {
2108 mStoppingActivities.add(prev);
2109 if (mStoppingActivities.size() > 3) {
2110 // If we already have a few activities waiting to stop,
2111 // then give up on things going idle and start clearing
2112 // them out.
2113 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2114 Message msg = Message.obtain();
2115 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2116 mHandler.sendMessage(msg);
2117 }
2118 }
2119 } else {
2120 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2121 prev = null;
2122 }
2123 mPausingActivity = null;
2124 }
2125
Dianne Hackborn55280a92009-05-07 15:53:46 -07002126 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 resumeTopActivityLocked(prev);
2128 } else {
2129 if (mGoingToSleep.isHeld()) {
2130 mGoingToSleep.release();
2131 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002132 if (mShuttingDown) {
2133 notifyAll();
2134 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135 }
2136
2137 if (prev != null) {
2138 prev.resumeKeyDispatchingLocked();
2139 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002140
2141 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2142 long diff = 0;
2143 synchronized (mProcessStatsThread) {
2144 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2145 }
2146 if (diff > 0) {
2147 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2148 synchronized (bsi) {
2149 BatteryStatsImpl.Uid.Proc ps =
2150 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2151 prev.info.packageName);
2152 if (ps != null) {
2153 ps.addForegroundTimeLocked(diff);
2154 }
2155 }
2156 }
2157 }
2158 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 }
2160
2161 /**
2162 * Once we know that we have asked an application to put an activity in
2163 * the resumed state (either by launching it or explicitly telling it),
2164 * this function updates the rest of our state to match that fact.
2165 */
2166 private final void completeResumeLocked(HistoryRecord next) {
2167 next.idle = false;
2168 next.results = null;
2169 next.newIntents = null;
2170
2171 // schedule an idle timeout in case the app doesn't do it for us.
2172 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2173 msg.obj = next;
2174 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2175
2176 if (false) {
2177 // The activity was never told to pause, so just keep
2178 // things going as-is. To maintain our own state,
2179 // we need to emulate it coming back and saying it is
2180 // idle.
2181 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2182 msg.obj = next;
2183 mHandler.sendMessage(msg);
2184 }
2185
2186 next.thumbnail = null;
2187 setFocusedActivityLocked(next);
2188 next.resumeKeyDispatchingLocked();
2189 ensureActivitiesVisibleLocked(null, 0);
2190 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002191
2192 // Mark the point when the activity is resuming
2193 // TODO: To be more accurate, the mark should be before the onCreate,
2194 // not after the onResume. But for subsequent starts, onResume is fine.
2195 if (next.app != null) {
2196 synchronized (mProcessStatsThread) {
2197 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2198 }
2199 } else {
2200 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 }
2203
2204 /**
2205 * Make sure that all activities that need to be visible (that is, they
2206 * currently can be seen by the user) actually are.
2207 */
2208 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2209 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2210 if (DEBUG_VISBILITY) Log.v(
2211 TAG, "ensureActivitiesVisible behind " + top
2212 + " configChanges=0x" + Integer.toHexString(configChanges));
2213
2214 // If the top activity is not fullscreen, then we need to
2215 // make sure any activities under it are now visible.
2216 final int count = mHistory.size();
2217 int i = count-1;
2218 while (mHistory.get(i) != top) {
2219 i--;
2220 }
2221 HistoryRecord r;
2222 boolean behindFullscreen = false;
2223 for (; i>=0; i--) {
2224 r = (HistoryRecord)mHistory.get(i);
2225 if (DEBUG_VISBILITY) Log.v(
2226 TAG, "Make visible? " + r + " finishing=" + r.finishing
2227 + " state=" + r.state);
2228 if (r.finishing) {
2229 continue;
2230 }
2231
2232 final boolean doThisProcess = onlyThisProcess == null
2233 || onlyThisProcess.equals(r.processName);
2234
2235 // First: if this is not the current activity being started, make
2236 // sure it matches the current configuration.
2237 if (r != starting && doThisProcess) {
2238 ensureActivityConfigurationLocked(r, 0);
2239 }
2240
2241 if (r.app == null || r.app.thread == null) {
2242 if (onlyThisProcess == null
2243 || onlyThisProcess.equals(r.processName)) {
2244 // This activity needs to be visible, but isn't even
2245 // running... get it started, but don't resume it
2246 // at this point.
2247 if (DEBUG_VISBILITY) Log.v(
2248 TAG, "Start and freeze screen for " + r);
2249 if (r != starting) {
2250 r.startFreezingScreenLocked(r.app, configChanges);
2251 }
2252 if (!r.visible) {
2253 if (DEBUG_VISBILITY) Log.v(
2254 TAG, "Starting and making visible: " + r);
2255 mWindowManager.setAppVisibility(r, true);
2256 }
2257 if (r != starting) {
2258 startSpecificActivityLocked(r, false, false);
2259 }
2260 }
2261
2262 } else if (r.visible) {
2263 // If this activity is already visible, then there is nothing
2264 // else to do here.
2265 if (DEBUG_VISBILITY) Log.v(
2266 TAG, "Skipping: already visible at " + r);
2267 r.stopFreezingScreenLocked(false);
2268
2269 } else if (onlyThisProcess == null) {
2270 // This activity is not currently visible, but is running.
2271 // Tell it to become visible.
2272 r.visible = true;
2273 if (r.state != ActivityState.RESUMED && r != starting) {
2274 // If this activity is paused, tell it
2275 // to now show its window.
2276 if (DEBUG_VISBILITY) Log.v(
2277 TAG, "Making visible and scheduling visibility: " + r);
2278 try {
2279 mWindowManager.setAppVisibility(r, true);
2280 r.app.thread.scheduleWindowVisibility(r, true);
2281 r.stopFreezingScreenLocked(false);
2282 } catch (Exception e) {
2283 // Just skip on any failure; we'll make it
2284 // visible when it next restarts.
2285 Log.w(TAG, "Exception thrown making visibile: "
2286 + r.intent.getComponent(), e);
2287 }
2288 }
2289 }
2290
2291 // Aggregate current change flags.
2292 configChanges |= r.configChangeFlags;
2293
2294 if (r.fullscreen) {
2295 // At this point, nothing else needs to be shown
2296 if (DEBUG_VISBILITY) Log.v(
2297 TAG, "Stopping: fullscreen at " + r);
2298 behindFullscreen = true;
2299 i--;
2300 break;
2301 }
2302 }
2303
2304 // Now for any activities that aren't visible to the user, make
2305 // sure they no longer are keeping the screen frozen.
2306 while (i >= 0) {
2307 r = (HistoryRecord)mHistory.get(i);
2308 if (DEBUG_VISBILITY) Log.v(
2309 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2310 + " state=" + r.state
2311 + " behindFullscreen=" + behindFullscreen);
2312 if (!r.finishing) {
2313 if (behindFullscreen) {
2314 if (r.visible) {
2315 if (DEBUG_VISBILITY) Log.v(
2316 TAG, "Making invisible: " + r);
2317 r.visible = false;
2318 try {
2319 mWindowManager.setAppVisibility(r, false);
2320 if ((r.state == ActivityState.STOPPING
2321 || r.state == ActivityState.STOPPED)
2322 && r.app != null && r.app.thread != null) {
2323 if (DEBUG_VISBILITY) Log.v(
2324 TAG, "Scheduling invisibility: " + r);
2325 r.app.thread.scheduleWindowVisibility(r, false);
2326 }
2327 } catch (Exception e) {
2328 // Just skip on any failure; we'll make it
2329 // visible when it next restarts.
2330 Log.w(TAG, "Exception thrown making hidden: "
2331 + r.intent.getComponent(), e);
2332 }
2333 } else {
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Already invisible: " + r);
2336 }
2337 } else if (r.fullscreen) {
2338 if (DEBUG_VISBILITY) Log.v(
2339 TAG, "Now behindFullscreen: " + r);
2340 behindFullscreen = true;
2341 }
2342 }
2343 i--;
2344 }
2345 }
2346
2347 /**
2348 * Version of ensureActivitiesVisible that can easily be called anywhere.
2349 */
2350 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2351 int configChanges) {
2352 HistoryRecord r = topRunningActivityLocked(null);
2353 if (r != null) {
2354 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2355 }
2356 }
2357
2358 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2359 if (resumed) {
2360 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2361 } else {
2362 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2363 }
2364 }
2365
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002366 private boolean startHomeActivityLocked() {
2367 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2368 && mTopAction == null) {
2369 // We are running in factory test mode, but unable to find
2370 // the factory test app, so just sit around displaying the
2371 // error message and don't try to start anything.
2372 return false;
2373 }
2374 Intent intent = new Intent(
2375 mTopAction,
2376 mTopData != null ? Uri.parse(mTopData) : null);
2377 intent.setComponent(mTopComponent);
2378 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2379 intent.addCategory(Intent.CATEGORY_HOME);
2380 }
2381 ActivityInfo aInfo =
2382 intent.resolveActivityInfo(mContext.getPackageManager(),
2383 STOCK_PM_FLAGS);
2384 if (aInfo != null) {
2385 intent.setComponent(new ComponentName(
2386 aInfo.applicationInfo.packageName, aInfo.name));
2387 // Don't do this if the home app is currently being
2388 // instrumented.
2389 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2390 aInfo.applicationInfo.uid);
2391 if (app == null || app.instrumentationClass == null) {
2392 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2393 startActivityLocked(null, intent, null, null, 0, aInfo,
2394 null, null, 0, 0, 0, false, false);
2395 }
2396 }
2397
2398
2399 return true;
2400 }
2401
2402 /**
2403 * Starts the "new version setup screen" if appropriate.
2404 */
2405 private void startSetupActivityLocked() {
2406 // Only do this once per boot.
2407 if (mCheckedForSetup) {
2408 return;
2409 }
2410
2411 // We will show this screen if the current one is a different
2412 // version than the last one shown, and we are not running in
2413 // low-level factory test mode.
2414 final ContentResolver resolver = mContext.getContentResolver();
2415 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2416 Settings.Secure.getInt(resolver,
2417 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2418 mCheckedForSetup = true;
2419
2420 // See if we should be showing the platform update setup UI.
2421 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2422 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2423 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2424
2425 // We don't allow third party apps to replace this.
2426 ResolveInfo ri = null;
2427 for (int i=0; ris != null && i<ris.size(); i++) {
2428 if ((ris.get(i).activityInfo.applicationInfo.flags
2429 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2430 ri = ris.get(i);
2431 break;
2432 }
2433 }
2434
2435 if (ri != null) {
2436 String vers = ri.activityInfo.metaData != null
2437 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2438 : null;
2439 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2440 vers = ri.activityInfo.applicationInfo.metaData.getString(
2441 Intent.METADATA_SETUP_VERSION);
2442 }
2443 String lastVers = Settings.Secure.getString(
2444 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2445 if (vers != null && !vers.equals(lastVers)) {
2446 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2447 intent.setComponent(new ComponentName(
2448 ri.activityInfo.packageName, ri.activityInfo.name));
2449 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2450 null, null, 0, 0, 0, false, false);
2451 }
2452 }
2453 }
2454 }
2455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002456 /**
2457 * Ensure that the top activity in the stack is resumed.
2458 *
2459 * @param prev The previously resumed activity, for when in the process
2460 * of pausing; can be null to call from elsewhere.
2461 *
2462 * @return Returns true if something is being resumed, or false if
2463 * nothing happened.
2464 */
2465 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2466 // Find the first activity that is not finishing.
2467 HistoryRecord next = topRunningActivityLocked(null);
2468
2469 // Remember how we'll process this pause/resume situation, and ensure
2470 // that the state is reset however we wind up proceeding.
2471 final boolean userLeaving = mUserLeaving;
2472 mUserLeaving = false;
2473
2474 if (next == null) {
2475 // There are no more activities! Let's just start up the
2476 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002477 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 }
2479
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002480 next.delayedResume = false;
2481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002482 // If the top activity is the resumed one, nothing to do.
2483 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2484 // Make sure we have executed any pending transitions, since there
2485 // should be nothing left to do at this point.
2486 mWindowManager.executeAppTransition();
2487 return false;
2488 }
2489
2490 // If we are sleeping, and there is no resumed activity, and the top
2491 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002492 if ((mSleeping || mShuttingDown)
2493 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002494 // Make sure we have executed any pending transitions, since there
2495 // should be nothing left to do at this point.
2496 mWindowManager.executeAppTransition();
2497 return false;
2498 }
2499
2500 // The activity may be waiting for stop, but that is no longer
2501 // appropriate for it.
2502 mStoppingActivities.remove(next);
2503 mWaitingVisibleActivities.remove(next);
2504
2505 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2506
2507 // If we are currently pausing an activity, then don't do anything
2508 // until that is done.
2509 if (mPausingActivity != null) {
2510 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2511 return false;
2512 }
2513
2514 // We need to start pausing the current activity so the top one
2515 // can be resumed...
2516 if (mResumedActivity != null) {
2517 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2518 startPausingLocked(userLeaving, false);
2519 return true;
2520 }
2521
2522 if (prev != null && prev != next) {
2523 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2524 prev.waitingVisible = true;
2525 mWaitingVisibleActivities.add(prev);
2526 if (DEBUG_SWITCH) Log.v(
2527 TAG, "Resuming top, waiting visible to hide: " + prev);
2528 } else {
2529 // The next activity is already visible, so hide the previous
2530 // activity's windows right now so we can show the new one ASAP.
2531 // We only do this if the previous is finishing, which should mean
2532 // it is on top of the one being resumed so hiding it quickly
2533 // is good. Otherwise, we want to do the normal route of allowing
2534 // the resumed activity to be shown so we can decide if the
2535 // previous should actually be hidden depending on whether the
2536 // new one is found to be full-screen or not.
2537 if (prev.finishing) {
2538 mWindowManager.setAppVisibility(prev, false);
2539 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2540 + prev + ", waitingVisible="
2541 + (prev != null ? prev.waitingVisible : null)
2542 + ", nowVisible=" + next.nowVisible);
2543 } else {
2544 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2545 + prev + ", waitingVisible="
2546 + (prev != null ? prev.waitingVisible : null)
2547 + ", nowVisible=" + next.nowVisible);
2548 }
2549 }
2550 }
2551
2552 // We are starting up the next activity, so tell the window manager
2553 // that the previous one will be hidden soon. This way it can know
2554 // to ignore it when computing the desired screen orientation.
2555 if (prev != null) {
2556 if (prev.finishing) {
2557 if (DEBUG_TRANSITION) Log.v(TAG,
2558 "Prepare close transition: prev=" + prev);
2559 mWindowManager.prepareAppTransition(prev.task == next.task
2560 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2561 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2562 mWindowManager.setAppWillBeHidden(prev);
2563 mWindowManager.setAppVisibility(prev, false);
2564 } else {
2565 if (DEBUG_TRANSITION) Log.v(TAG,
2566 "Prepare open transition: prev=" + prev);
2567 mWindowManager.prepareAppTransition(prev.task == next.task
2568 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2569 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2570 }
2571 if (false) {
2572 mWindowManager.setAppWillBeHidden(prev);
2573 mWindowManager.setAppVisibility(prev, false);
2574 }
2575 } else if (mHistory.size() > 1) {
2576 if (DEBUG_TRANSITION) Log.v(TAG,
2577 "Prepare open transition: no previous");
2578 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2579 }
2580
2581 if (next.app != null && next.app.thread != null) {
2582 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2583
2584 // This activity is now becoming visible.
2585 mWindowManager.setAppVisibility(next, true);
2586
2587 HistoryRecord lastResumedActivity = mResumedActivity;
2588 ActivityState lastState = next.state;
2589
2590 updateCpuStats();
2591
2592 next.state = ActivityState.RESUMED;
2593 mResumedActivity = next;
2594 next.task.touchActiveTime();
2595 updateLRUListLocked(next.app, true);
2596 updateLRUListLocked(next);
2597
2598 // Have the window manager re-evaluate the orientation of
2599 // the screen based on the new activity order.
2600 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002601 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002602 next.mayFreezeScreenLocked(next.app) ? next : null);
2603 if (config != null) {
2604 next.frozenBeforeDestroy = true;
2605 }
2606 if (!updateConfigurationLocked(config, next)) {
2607 // The configuration update wasn't able to keep the existing
2608 // instance of the activity, and instead started a new one.
2609 // We should be all done, but let's just make sure our activity
2610 // is still at the top and schedule another run if something
2611 // weird happened.
2612 HistoryRecord nextNext = topRunningActivityLocked(null);
2613 if (DEBUG_SWITCH) Log.i(TAG,
2614 "Activity config changed during resume: " + next
2615 + ", new next: " + nextNext);
2616 if (nextNext != next) {
2617 // Do over!
2618 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2619 }
2620 mWindowManager.executeAppTransition();
2621 return true;
2622 }
2623
2624 try {
2625 // Deliver all pending results.
2626 ArrayList a = next.results;
2627 if (a != null) {
2628 final int N = a.size();
2629 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002630 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002631 TAG, "Delivering results to " + next
2632 + ": " + a);
2633 next.app.thread.scheduleSendResult(next, a);
2634 }
2635 }
2636
2637 if (next.newIntents != null) {
2638 next.app.thread.scheduleNewIntent(next.newIntents, next);
2639 }
2640
2641 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2642 System.identityHashCode(next),
2643 next.task.taskId, next.shortComponentName);
2644 updateUsageStats(next, true);
2645
2646 next.app.thread.scheduleResumeActivity(next,
2647 isNextTransitionForward());
2648 pauseIfSleepingLocked();
2649
2650 } catch (Exception e) {
2651 // Whoops, need to restart this activity!
2652 next.state = lastState;
2653 mResumedActivity = lastResumedActivity;
2654 if (Config.LOGD) Log.d(TAG,
2655 "Restarting because process died: " + next);
2656 if (!next.hasBeenLaunched) {
2657 next.hasBeenLaunched = true;
2658 } else {
2659 if (SHOW_APP_STARTING_ICON) {
2660 mWindowManager.setAppStartingWindow(
2661 next, next.packageName, next.theme,
2662 next.nonLocalizedLabel,
2663 next.labelRes, next.icon, null, true);
2664 }
2665 }
2666 startSpecificActivityLocked(next, true, false);
2667 return true;
2668 }
2669
2670 // From this point on, if something goes wrong there is no way
2671 // to recover the activity.
2672 try {
2673 next.visible = true;
2674 completeResumeLocked(next);
2675 } catch (Exception e) {
2676 // If any exception gets thrown, toss away this
2677 // activity and try the next one.
2678 Log.w(TAG, "Exception thrown during resume of " + next, e);
2679 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2680 "resume-exception");
2681 return true;
2682 }
2683
2684 // Didn't need to use the icicle, and it is now out of date.
2685 next.icicle = null;
2686 next.haveState = false;
2687 next.stopped = false;
2688
2689 } else {
2690 // Whoops, need to restart this activity!
2691 if (!next.hasBeenLaunched) {
2692 next.hasBeenLaunched = true;
2693 } else {
2694 if (SHOW_APP_STARTING_ICON) {
2695 mWindowManager.setAppStartingWindow(
2696 next, next.packageName, next.theme,
2697 next.nonLocalizedLabel,
2698 next.labelRes, next.icon, null, true);
2699 }
2700 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2701 }
2702 startSpecificActivityLocked(next, true, true);
2703 }
2704
2705 return true;
2706 }
2707
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002708 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2709 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 final int NH = mHistory.size();
2711
2712 int addPos = -1;
2713
2714 if (!newTask) {
2715 // If starting in an existing task, find where that is...
2716 HistoryRecord next = null;
2717 boolean startIt = true;
2718 for (int i = NH-1; i >= 0; i--) {
2719 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2720 if (p.finishing) {
2721 continue;
2722 }
2723 if (p.task == r.task) {
2724 // Here it is! Now, if this is not yet visible to the
2725 // user, then just add it without starting; it will
2726 // get started when the user navigates back to it.
2727 addPos = i+1;
2728 if (!startIt) {
2729 mHistory.add(addPos, r);
2730 r.inHistory = true;
2731 r.task.numActivities++;
2732 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2733 r.info.screenOrientation, r.fullscreen);
2734 if (VALIDATE_TOKENS) {
2735 mWindowManager.validateAppTokens(mHistory);
2736 }
2737 return;
2738 }
2739 break;
2740 }
2741 if (p.fullscreen) {
2742 startIt = false;
2743 }
2744 next = p;
2745 }
2746 }
2747
2748 // Place a new activity at top of stack, so it is next to interact
2749 // with the user.
2750 if (addPos < 0) {
2751 addPos = mHistory.size();
2752 }
2753
2754 // If we are not placing the new activity frontmost, we do not want
2755 // to deliver the onUserLeaving callback to the actual frontmost
2756 // activity
2757 if (addPos < NH) {
2758 mUserLeaving = false;
2759 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2760 }
2761
2762 // Slot the activity into the history stack and proceed
2763 mHistory.add(addPos, r);
2764 r.inHistory = true;
2765 r.frontOfTask = newTask;
2766 r.task.numActivities++;
2767 if (NH > 0) {
2768 // We want to show the starting preview window if we are
2769 // switching to a new task, or the next activity's process is
2770 // not currently running.
2771 boolean showStartingIcon = newTask;
2772 ProcessRecord proc = r.app;
2773 if (proc == null) {
2774 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2775 }
2776 if (proc == null || proc.thread == null) {
2777 showStartingIcon = true;
2778 }
2779 if (DEBUG_TRANSITION) Log.v(TAG,
2780 "Prepare open transition: starting " + r);
2781 mWindowManager.prepareAppTransition(newTask
2782 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2783 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2784 mWindowManager.addAppToken(
2785 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2786 boolean doShow = true;
2787 if (newTask) {
2788 // Even though this activity is starting fresh, we still need
2789 // to reset it to make sure we apply affinities to move any
2790 // existing activities from other tasks in to it.
2791 // If the caller has requested that the target task be
2792 // reset, then do so.
2793 if ((r.intent.getFlags()
2794 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2795 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002796 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002797 }
2798 }
2799 if (SHOW_APP_STARTING_ICON && doShow) {
2800 // Figure out if we are transitioning from another activity that is
2801 // "has the same starting icon" as the next one. This allows the
2802 // window manager to keep the previous window it had previously
2803 // created, if it still had one.
2804 HistoryRecord prev = mResumedActivity;
2805 if (prev != null) {
2806 // We don't want to reuse the previous starting preview if:
2807 // (1) The current activity is in a different task.
2808 if (prev.task != r.task) prev = null;
2809 // (2) The current activity is already displayed.
2810 else if (prev.nowVisible) prev = null;
2811 }
2812 mWindowManager.setAppStartingWindow(
2813 r, r.packageName, r.theme, r.nonLocalizedLabel,
2814 r.labelRes, r.icon, prev, showStartingIcon);
2815 }
2816 } else {
2817 // If this is the first activity, don't do any fancy animations,
2818 // because there is nothing for it to animate on top of.
2819 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2820 r.info.screenOrientation, r.fullscreen);
2821 }
2822 if (VALIDATE_TOKENS) {
2823 mWindowManager.validateAppTokens(mHistory);
2824 }
2825
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002826 if (doResume) {
2827 resumeTopActivityLocked(null);
2828 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002829 }
2830
2831 /**
2832 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002833 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2834 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002835 * an instance of that activity in the stack and, if found, finish all
2836 * activities on top of it and return the instance.
2837 *
2838 * @param newR Description of the new activity being started.
2839 * @return Returns the old activity that should be continue to be used,
2840 * or null if none was found.
2841 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002842 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 HistoryRecord newR, boolean doClear) {
2844 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002845
2846 // First find the requested task.
2847 while (i > 0) {
2848 i--;
2849 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2850 if (r.task.taskId == taskId) {
2851 i++;
2852 break;
2853 }
2854 }
2855
2856 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 while (i > 0) {
2858 i--;
2859 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2860 if (r.finishing) {
2861 continue;
2862 }
2863 if (r.task.taskId != taskId) {
2864 return null;
2865 }
2866 if (r.realActivity.equals(newR.realActivity)) {
2867 // Here it is! Now finish everything in front...
2868 HistoryRecord ret = r;
2869 if (doClear) {
2870 while (i < (mHistory.size()-1)) {
2871 i++;
2872 r = (HistoryRecord)mHistory.get(i);
2873 if (r.finishing) {
2874 continue;
2875 }
2876 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2877 null, "clear")) {
2878 i--;
2879 }
2880 }
2881 }
2882
2883 // Finally, if this is a normal launch mode (that is, not
2884 // expecting onNewIntent()), then we will finish the current
2885 // instance of the activity so a new fresh one can be started.
2886 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2887 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002888 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002889 if (index >= 0) {
2890 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2891 null, "clear");
2892 }
2893 return null;
2894 }
2895 }
2896
2897 return ret;
2898 }
2899 }
2900
2901 return null;
2902 }
2903
2904 /**
2905 * Find the activity in the history stack within the given task. Returns
2906 * the index within the history at which it's found, or < 0 if not found.
2907 */
2908 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2909 int i = mHistory.size();
2910 while (i > 0) {
2911 i--;
2912 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2913 if (candidate.task.taskId != task) {
2914 break;
2915 }
2916 if (candidate.realActivity.equals(r.realActivity)) {
2917 return i;
2918 }
2919 }
2920
2921 return -1;
2922 }
2923
2924 /**
2925 * Reorder the history stack so that the activity at the given index is
2926 * brought to the front.
2927 */
2928 private final HistoryRecord moveActivityToFrontLocked(int where) {
2929 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2930 int top = mHistory.size();
2931 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2932 mHistory.add(top, newTop);
2933 oldTop.frontOfTask = false;
2934 newTop.frontOfTask = true;
2935 return newTop;
2936 }
2937
2938 /**
2939 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2940 * method will be called at the proper time.
2941 */
2942 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2943 boolean sent = false;
2944 if (r.state == ActivityState.RESUMED
2945 && r.app != null && r.app.thread != null) {
2946 try {
2947 ArrayList<Intent> ar = new ArrayList<Intent>();
2948 ar.add(new Intent(intent));
2949 r.app.thread.scheduleNewIntent(ar, r);
2950 sent = true;
2951 } catch (Exception e) {
2952 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2953 }
2954 }
2955 if (!sent) {
2956 r.addNewIntentLocked(new Intent(intent));
2957 }
2958 }
2959
2960 private final void logStartActivity(int tag, HistoryRecord r,
2961 TaskRecord task) {
2962 EventLog.writeEvent(tag,
2963 System.identityHashCode(r), task.taskId,
2964 r.shortComponentName, r.intent.getAction(),
2965 r.intent.getType(), r.intent.getDataString(),
2966 r.intent.getFlags());
2967 }
2968
2969 private final int startActivityLocked(IApplicationThread caller,
2970 Intent intent, String resolvedType,
2971 Uri[] grantedUriPermissions,
2972 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2973 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002974 int callingPid, int callingUid, boolean onlyIfNeeded,
2975 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976 Log.i(TAG, "Starting activity: " + intent);
2977
2978 HistoryRecord sourceRecord = null;
2979 HistoryRecord resultRecord = null;
2980 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002981 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07002982 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2984 if (index >= 0) {
2985 sourceRecord = (HistoryRecord)mHistory.get(index);
2986 if (requestCode >= 0 && !sourceRecord.finishing) {
2987 resultRecord = sourceRecord;
2988 }
2989 }
2990 }
2991
2992 int launchFlags = intent.getFlags();
2993
2994 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2995 && sourceRecord != null) {
2996 // Transfer the result target from the source activity to the new
2997 // one being started, including any failures.
2998 if (requestCode >= 0) {
2999 return START_FORWARD_AND_REQUEST_CONFLICT;
3000 }
3001 resultRecord = sourceRecord.resultTo;
3002 resultWho = sourceRecord.resultWho;
3003 requestCode = sourceRecord.requestCode;
3004 sourceRecord.resultTo = null;
3005 if (resultRecord != null) {
3006 resultRecord.removeResultsLocked(
3007 sourceRecord, resultWho, requestCode);
3008 }
3009 }
3010
3011 int err = START_SUCCESS;
3012
3013 if (intent.getComponent() == null) {
3014 // We couldn't find a class that can handle the given Intent.
3015 // That's the end of that!
3016 err = START_INTENT_NOT_RESOLVED;
3017 }
3018
3019 if (err == START_SUCCESS && aInfo == null) {
3020 // We couldn't find the specific class specified in the Intent.
3021 // Also the end of the line.
3022 err = START_CLASS_NOT_FOUND;
3023 }
3024
3025 ProcessRecord callerApp = null;
3026 if (err == START_SUCCESS && caller != null) {
3027 callerApp = getRecordForAppLocked(caller);
3028 if (callerApp != null) {
3029 callingPid = callerApp.pid;
3030 callingUid = callerApp.info.uid;
3031 } else {
3032 Log.w(TAG, "Unable to find app for caller " + caller
3033 + " (pid=" + callingPid + ") when starting: "
3034 + intent.toString());
3035 err = START_PERMISSION_DENIED;
3036 }
3037 }
3038
3039 if (err != START_SUCCESS) {
3040 if (resultRecord != null) {
3041 sendActivityResultLocked(-1,
3042 resultRecord, resultWho, requestCode,
3043 Activity.RESULT_CANCELED, null);
3044 }
3045 return err;
3046 }
3047
3048 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3049 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3050 if (perm != PackageManager.PERMISSION_GRANTED) {
3051 if (resultRecord != null) {
3052 sendActivityResultLocked(-1,
3053 resultRecord, resultWho, requestCode,
3054 Activity.RESULT_CANCELED, null);
3055 }
3056 String msg = "Permission Denial: starting " + intent.toString()
3057 + " from " + callerApp + " (pid=" + callingPid
3058 + ", uid=" + callingUid + ")"
3059 + " requires " + aInfo.permission;
3060 Log.w(TAG, msg);
3061 throw new SecurityException(msg);
3062 }
3063
3064 if (mWatcher != null) {
3065 boolean abort = false;
3066 try {
3067 // The Intent we give to the watcher has the extra data
3068 // stripped off, since it can contain private information.
3069 Intent watchIntent = intent.cloneFilter();
3070 abort = !mWatcher.activityStarting(watchIntent,
3071 aInfo.applicationInfo.packageName);
3072 } catch (RemoteException e) {
3073 mWatcher = null;
3074 }
3075
3076 if (abort) {
3077 if (resultRecord != null) {
3078 sendActivityResultLocked(-1,
3079 resultRecord, resultWho, requestCode,
3080 Activity.RESULT_CANCELED, null);
3081 }
3082 // We pretend to the caller that it was really started, but
3083 // they will just get a cancel result.
3084 return START_SUCCESS;
3085 }
3086 }
3087
3088 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3089 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003090 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003092 if (mResumedActivity == null
3093 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3094 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3095 PendingActivityLaunch pal = new PendingActivityLaunch();
3096 pal.r = r;
3097 pal.sourceRecord = sourceRecord;
3098 pal.grantedUriPermissions = grantedUriPermissions;
3099 pal.grantedMode = grantedMode;
3100 pal.onlyIfNeeded = onlyIfNeeded;
3101 mPendingActivityLaunches.add(pal);
3102 return START_SWITCHES_CANCELED;
3103 }
3104 }
3105
3106 if (mDidAppSwitch) {
3107 // This is the second allowed switch since we stopped switches,
3108 // so now just generally allow switches. Use case: user presses
3109 // home (switches disabled, switch to home, mDidAppSwitch now true);
3110 // user taps a home icon (coming from home so allowed, we hit here
3111 // and now allow anyone to switch again).
3112 mAppSwitchesAllowedTime = 0;
3113 } else {
3114 mDidAppSwitch = true;
3115 }
3116
3117 doPendingActivityLaunchesLocked(false);
3118
3119 return startActivityUncheckedLocked(r, sourceRecord,
3120 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3121 }
3122
3123 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3124 final int N = mPendingActivityLaunches.size();
3125 if (N <= 0) {
3126 return;
3127 }
3128 for (int i=0; i<N; i++) {
3129 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3130 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3131 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3132 doResume && i == (N-1));
3133 }
3134 mPendingActivityLaunches.clear();
3135 }
3136
3137 private final int startActivityUncheckedLocked(HistoryRecord r,
3138 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3139 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3140 final Intent intent = r.intent;
3141 final int callingUid = r.launchedFromUid;
3142
3143 int launchFlags = intent.getFlags();
3144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 // We'll invoke onUserLeaving before onPause only if the launching
3146 // activity did not explicitly state that this is an automated launch.
3147 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3148 if (DEBUG_USER_LEAVING) Log.v(TAG,
3149 "startActivity() => mUserLeaving=" + mUserLeaving);
3150
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003151 // If the caller has asked not to resume at this point, we make note
3152 // of this in the record so that we can skip it when trying to find
3153 // the top running activity.
3154 if (!doResume) {
3155 r.delayedResume = true;
3156 }
3157
3158 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3159 != 0 ? r : null;
3160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 // If the onlyIfNeeded flag is set, then we can do this if the activity
3162 // being launched is the same as the one making the call... or, as
3163 // a special case, if we do not know the caller then we count the
3164 // current top activity as the caller.
3165 if (onlyIfNeeded) {
3166 HistoryRecord checkedCaller = sourceRecord;
3167 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003168 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003169 }
3170 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3171 // Caller is not the same as launcher, so always needed.
3172 onlyIfNeeded = false;
3173 }
3174 }
3175
3176 if (grantedUriPermissions != null && callingUid > 0) {
3177 for (int i=0; i<grantedUriPermissions.length; i++) {
3178 grantUriPermissionLocked(callingUid, r.packageName,
3179 grantedUriPermissions[i], grantedMode, r);
3180 }
3181 }
3182
3183 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3184 intent, r);
3185
3186 if (sourceRecord == null) {
3187 // This activity is not being started from another... in this
3188 // case we -always- start a new task.
3189 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3190 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3191 + intent);
3192 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3193 }
3194 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3195 // The original activity who is starting us is running as a single
3196 // instance... this new activity it is starting must go on its
3197 // own task.
3198 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3199 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3200 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3201 // The activity being started is a single instance... it always
3202 // gets launched into its own task.
3203 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3204 }
3205
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003206 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 // For whatever reason this activity is being launched into a new
3208 // task... yet the caller has requested a result back. Well, that
3209 // is pretty messed up, so instead immediately send back a cancel
3210 // and let the new task continue launched as normal without a
3211 // dependency on its originator.
3212 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3213 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003214 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003215 Activity.RESULT_CANCELED, null);
3216 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 }
3218
3219 boolean addingToTask = false;
3220 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3221 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3222 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3223 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3224 // If bring to front is requested, and no result is requested, and
3225 // we can find a task that was started with this same
3226 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003227 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003228 // See if there is a task to bring to the front. If this is
3229 // a SINGLE_INSTANCE activity, there can be one and only one
3230 // instance of it in the history, and it is always in its own
3231 // unique task, so we do a special search.
3232 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3233 ? findTaskLocked(intent, r.info)
3234 : findActivityLocked(intent, r.info);
3235 if (taskTop != null) {
3236 if (taskTop.task.intent == null) {
3237 // This task was started because of movement of
3238 // the activity based on affinity... now that we
3239 // are actually launching it, we can assign the
3240 // base intent.
3241 taskTop.task.setIntent(intent, r.info);
3242 }
3243 // If the target task is not in the front, then we need
3244 // to bring it to the front... except... well, with
3245 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3246 // to have the same behavior as if a new instance was
3247 // being started, which means not bringing it to the front
3248 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003249 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003250 if (curTop.task != taskTop.task) {
3251 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3252 boolean callerAtFront = sourceRecord == null
3253 || curTop.task == sourceRecord.task;
3254 if (callerAtFront) {
3255 // We really do want to push this one into the
3256 // user's face, right now.
3257 moveTaskToFrontLocked(taskTop.task);
3258 }
3259 }
3260 // If the caller has requested that the target task be
3261 // reset, then do so.
3262 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3263 taskTop = resetTaskIfNeededLocked(taskTop, r);
3264 }
3265 if (onlyIfNeeded) {
3266 // We don't need to start a new activity, and
3267 // the client said not to do anything if that
3268 // is the case, so this is it! And for paranoia, make
3269 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003270 if (doResume) {
3271 resumeTopActivityLocked(null);
3272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003273 return START_RETURN_INTENT_TO_CALLER;
3274 }
3275 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3276 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3277 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3278 // In this situation we want to remove all activities
3279 // from the task up to the one being started. In most
3280 // cases this means we are resetting the task to its
3281 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003282 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 taskTop.task.taskId, r, true);
3284 if (top != null) {
3285 if (top.frontOfTask) {
3286 // Activity aliases may mean we use different
3287 // intents for the top activity, so make sure
3288 // the task now has the identity of the new
3289 // intent.
3290 top.task.setIntent(r.intent, r.info);
3291 }
3292 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3293 deliverNewIntentLocked(top, r.intent);
3294 } else {
3295 // A special case: we need to
3296 // start the activity because it is not currently
3297 // running, and the caller has asked to clear the
3298 // current task to have this activity at the top.
3299 addingToTask = true;
3300 // Now pretend like this activity is being started
3301 // by the top of its task, so it is put in the
3302 // right place.
3303 sourceRecord = taskTop;
3304 }
3305 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3306 // In this case the top activity on the task is the
3307 // same as the one being launched, so we take that
3308 // as a request to bring the task to the foreground.
3309 // If the top activity in the task is the root
3310 // activity, deliver this new intent to it if it
3311 // desires.
3312 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3313 && taskTop.realActivity.equals(r.realActivity)) {
3314 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3315 if (taskTop.frontOfTask) {
3316 taskTop.task.setIntent(r.intent, r.info);
3317 }
3318 deliverNewIntentLocked(taskTop, r.intent);
3319 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3320 // In this case we are launching the root activity
3321 // of the task, but with a different intent. We
3322 // should start a new instance on top.
3323 addingToTask = true;
3324 sourceRecord = taskTop;
3325 }
3326 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3327 // In this case an activity is being launched in to an
3328 // existing task, without resetting that task. This
3329 // is typically the situation of launching an activity
3330 // from a notification or shortcut. We want to place
3331 // the new activity on top of the current task.
3332 addingToTask = true;
3333 sourceRecord = taskTop;
3334 } else if (!taskTop.task.rootWasReset) {
3335 // In this case we are launching in to an existing task
3336 // that has not yet been started from its front door.
3337 // The current task has been brought to the front.
3338 // Ideally, we'd probably like to place this new task
3339 // at the bottom of its stack, but that's a little hard
3340 // to do with the current organization of the code so
3341 // for now we'll just drop it.
3342 taskTop.task.setIntent(r.intent, r.info);
3343 }
3344 if (!addingToTask) {
3345 // We didn't do anything... but it was needed (a.k.a., client
3346 // don't use that intent!) And for paranoia, make
3347 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003348 if (doResume) {
3349 resumeTopActivityLocked(null);
3350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 return START_TASK_TO_FRONT;
3352 }
3353 }
3354 }
3355 }
3356
3357 //String uri = r.intent.toURI();
3358 //Intent intent2 = new Intent(uri);
3359 //Log.i(TAG, "Given intent: " + r.intent);
3360 //Log.i(TAG, "URI is: " + uri);
3361 //Log.i(TAG, "To intent: " + intent2);
3362
3363 if (r.packageName != null) {
3364 // If the activity being launched is the same as the one currently
3365 // at the top, then we need to check if it should only be launched
3366 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003367 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3368 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 if (top.realActivity.equals(r.realActivity)) {
3370 if (top.app != null && top.app.thread != null) {
3371 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3372 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3373 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3374 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3375 // For paranoia, make sure we have correctly
3376 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003377 if (doResume) {
3378 resumeTopActivityLocked(null);
3379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380 if (onlyIfNeeded) {
3381 // We don't need to start a new activity, and
3382 // the client said not to do anything if that
3383 // is the case, so this is it!
3384 return START_RETURN_INTENT_TO_CALLER;
3385 }
3386 deliverNewIntentLocked(top, r.intent);
3387 return START_DELIVERED_TO_TOP;
3388 }
3389 }
3390 }
3391 }
3392
3393 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003394 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003396 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003397 Activity.RESULT_CANCELED, null);
3398 }
3399 return START_CLASS_NOT_FOUND;
3400 }
3401
3402 boolean newTask = false;
3403
3404 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003405 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3407 // todo: should do better management of integers.
3408 mCurTask++;
3409 if (mCurTask <= 0) {
3410 mCurTask = 1;
3411 }
3412 r.task = new TaskRecord(mCurTask, r.info, intent,
3413 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3414 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3415 + " in new task " + r.task);
3416 newTask = true;
3417 addRecentTask(r.task);
3418
3419 } else if (sourceRecord != null) {
3420 if (!addingToTask &&
3421 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3422 // In this case, we are adding the activity to an existing
3423 // task, but the caller has asked to clear that task if the
3424 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003425 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003426 sourceRecord.task.taskId, r, true);
3427 if (top != null) {
3428 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3429 deliverNewIntentLocked(top, r.intent);
3430 // For paranoia, make sure we have correctly
3431 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003432 if (doResume) {
3433 resumeTopActivityLocked(null);
3434 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 return START_DELIVERED_TO_TOP;
3436 }
3437 } else if (!addingToTask &&
3438 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3439 // In this case, we are launching an activity in our own task
3440 // that may already be running somewhere in the history, and
3441 // we want to shuffle it to the front of the stack if so.
3442 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3443 if (where >= 0) {
3444 HistoryRecord top = moveActivityToFrontLocked(where);
3445 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3446 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003447 if (doResume) {
3448 resumeTopActivityLocked(null);
3449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003450 return START_DELIVERED_TO_TOP;
3451 }
3452 }
3453 // An existing activity is starting this new activity, so we want
3454 // to keep the new one in the same task as the one that is starting
3455 // it.
3456 r.task = sourceRecord.task;
3457 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3458 + " in existing task " + r.task);
3459
3460 } else {
3461 // This not being started from an existing activity, and not part
3462 // of a new task... just put it in the top task, though these days
3463 // this case should never happen.
3464 final int N = mHistory.size();
3465 HistoryRecord prev =
3466 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3467 r.task = prev != null
3468 ? prev.task
3469 : new TaskRecord(mCurTask, r.info, intent,
3470 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3471 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3472 + " in new guessed " + r.task);
3473 }
3474 if (newTask) {
3475 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3476 }
3477 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003478 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003479 return START_SUCCESS;
3480 }
3481
3482 public final int startActivity(IApplicationThread caller,
3483 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3484 int grantedMode, IBinder resultTo,
3485 String resultWho, int requestCode, boolean onlyIfNeeded,
3486 boolean debug) {
3487 // Refuse possible leaked file descriptors
3488 if (intent != null && intent.hasFileDescriptors()) {
3489 throw new IllegalArgumentException("File descriptors passed in Intent");
3490 }
3491
The Android Open Source Project4df24232009-03-05 14:34:35 -08003492 final boolean componentSpecified = intent.getComponent() != null;
3493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 // Don't modify the client's object!
3495 intent = new Intent(intent);
3496
3497 // Collect information about the target of the Intent.
3498 // Must do this before locking, because resolving the intent
3499 // may require launching a process to run its content provider.
3500 ActivityInfo aInfo;
3501 try {
3502 ResolveInfo rInfo =
3503 ActivityThread.getPackageManager().resolveIntent(
3504 intent, resolvedType,
3505 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003506 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 aInfo = rInfo != null ? rInfo.activityInfo : null;
3508 } catch (RemoteException e) {
3509 aInfo = null;
3510 }
3511
3512 if (aInfo != null) {
3513 // Store the found target back into the intent, because now that
3514 // we have it we never want to do this again. For example, if the
3515 // user navigates back to this point in the history, we should
3516 // always restart the exact same activity.
3517 intent.setComponent(new ComponentName(
3518 aInfo.applicationInfo.packageName, aInfo.name));
3519
3520 // Don't debug things in the system process
3521 if (debug) {
3522 if (!aInfo.processName.equals("system")) {
3523 setDebugApp(aInfo.processName, true, false);
3524 }
3525 }
3526 }
3527
3528 synchronized(this) {
3529 final long origId = Binder.clearCallingIdentity();
3530 int res = startActivityLocked(caller, intent, resolvedType,
3531 grantedUriPermissions, grantedMode, aInfo,
3532 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003533 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 Binder.restoreCallingIdentity(origId);
3535 return res;
3536 }
3537 }
3538
3539 public boolean startNextMatchingActivity(IBinder callingActivity,
3540 Intent intent) {
3541 // Refuse possible leaked file descriptors
3542 if (intent != null && intent.hasFileDescriptors() == true) {
3543 throw new IllegalArgumentException("File descriptors passed in Intent");
3544 }
3545
3546 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003547 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003548 if (index < 0) {
3549 return false;
3550 }
3551 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3552 if (r.app == null || r.app.thread == null) {
3553 // The caller is not running... d'oh!
3554 return false;
3555 }
3556 intent = new Intent(intent);
3557 // The caller is not allowed to change the data.
3558 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3559 // And we are resetting to find the next component...
3560 intent.setComponent(null);
3561
3562 ActivityInfo aInfo = null;
3563 try {
3564 List<ResolveInfo> resolves =
3565 ActivityThread.getPackageManager().queryIntentActivities(
3566 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003567 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568
3569 // Look for the original activity in the list...
3570 final int N = resolves != null ? resolves.size() : 0;
3571 for (int i=0; i<N; i++) {
3572 ResolveInfo rInfo = resolves.get(i);
3573 if (rInfo.activityInfo.packageName.equals(r.packageName)
3574 && rInfo.activityInfo.name.equals(r.info.name)) {
3575 // We found the current one... the next matching is
3576 // after it.
3577 i++;
3578 if (i<N) {
3579 aInfo = resolves.get(i).activityInfo;
3580 }
3581 break;
3582 }
3583 }
3584 } catch (RemoteException e) {
3585 }
3586
3587 if (aInfo == null) {
3588 // Nobody who is next!
3589 return false;
3590 }
3591
3592 intent.setComponent(new ComponentName(
3593 aInfo.applicationInfo.packageName, aInfo.name));
3594 intent.setFlags(intent.getFlags()&~(
3595 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3596 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3597 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3598 Intent.FLAG_ACTIVITY_NEW_TASK));
3599
3600 // Okay now we need to start the new activity, replacing the
3601 // currently running activity. This is a little tricky because
3602 // we want to start the new one as if the current one is finished,
3603 // but not finish the current one first so that there is no flicker.
3604 // And thus...
3605 final boolean wasFinishing = r.finishing;
3606 r.finishing = true;
3607
3608 // Propagate reply information over to the new activity.
3609 final HistoryRecord resultTo = r.resultTo;
3610 final String resultWho = r.resultWho;
3611 final int requestCode = r.requestCode;
3612 r.resultTo = null;
3613 if (resultTo != null) {
3614 resultTo.removeResultsLocked(r, resultWho, requestCode);
3615 }
3616
3617 final long origId = Binder.clearCallingIdentity();
3618 // XXX we are not dealing with propagating grantedUriPermissions...
3619 // those are not yet exposed to user code, so there is no need.
3620 int res = startActivityLocked(r.app.thread, intent,
3621 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003622 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623 Binder.restoreCallingIdentity(origId);
3624
3625 r.finishing = wasFinishing;
3626 if (res != START_SUCCESS) {
3627 return false;
3628 }
3629 return true;
3630 }
3631 }
3632
3633 final int startActivityInPackage(int uid,
3634 Intent intent, String resolvedType, IBinder resultTo,
3635 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003636 final boolean componentSpecified = intent.getComponent() != null;
3637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003638 // Don't modify the client's object!
3639 intent = new Intent(intent);
3640
3641 // Collect information about the target of the Intent.
3642 // Must do this before locking, because resolving the intent
3643 // may require launching a process to run its content provider.
3644 ActivityInfo aInfo;
3645 try {
3646 ResolveInfo rInfo =
3647 ActivityThread.getPackageManager().resolveIntent(
3648 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003649 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 aInfo = rInfo != null ? rInfo.activityInfo : null;
3651 } catch (RemoteException e) {
3652 aInfo = null;
3653 }
3654
3655 if (aInfo != null) {
3656 // Store the found target back into the intent, because now that
3657 // we have it we never want to do this again. For example, if the
3658 // user navigates back to this point in the history, we should
3659 // always restart the exact same activity.
3660 intent.setComponent(new ComponentName(
3661 aInfo.applicationInfo.packageName, aInfo.name));
3662 }
3663
3664 synchronized(this) {
3665 return startActivityLocked(null, intent, resolvedType,
3666 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003667 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668 }
3669 }
3670
3671 private final void addRecentTask(TaskRecord task) {
3672 // Remove any existing entries that are the same kind of task.
3673 int N = mRecentTasks.size();
3674 for (int i=0; i<N; i++) {
3675 TaskRecord tr = mRecentTasks.get(i);
3676 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3677 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3678 mRecentTasks.remove(i);
3679 i--;
3680 N--;
3681 if (task.intent == null) {
3682 // If the new recent task we are adding is not fully
3683 // specified, then replace it with the existing recent task.
3684 task = tr;
3685 }
3686 }
3687 }
3688 if (N >= MAX_RECENT_TASKS) {
3689 mRecentTasks.remove(N-1);
3690 }
3691 mRecentTasks.add(0, task);
3692 }
3693
3694 public void setRequestedOrientation(IBinder token,
3695 int requestedOrientation) {
3696 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003697 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003698 if (index < 0) {
3699 return;
3700 }
3701 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3702 final long origId = Binder.clearCallingIdentity();
3703 mWindowManager.setAppOrientation(r, requestedOrientation);
3704 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003705 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 r.mayFreezeScreenLocked(r.app) ? r : null);
3707 if (config != null) {
3708 r.frozenBeforeDestroy = true;
3709 if (!updateConfigurationLocked(config, r)) {
3710 resumeTopActivityLocked(null);
3711 }
3712 }
3713 Binder.restoreCallingIdentity(origId);
3714 }
3715 }
3716
3717 public int getRequestedOrientation(IBinder token) {
3718 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003719 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003720 if (index < 0) {
3721 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3722 }
3723 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3724 return mWindowManager.getAppOrientation(r);
3725 }
3726 }
3727
3728 private final void stopActivityLocked(HistoryRecord r) {
3729 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3730 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3731 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3732 if (!r.finishing) {
3733 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3734 "no-history");
3735 }
3736 } else if (r.app != null && r.app.thread != null) {
3737 if (mFocusedActivity == r) {
3738 setFocusedActivityLocked(topRunningActivityLocked(null));
3739 }
3740 r.resumeKeyDispatchingLocked();
3741 try {
3742 r.stopped = false;
3743 r.state = ActivityState.STOPPING;
3744 if (DEBUG_VISBILITY) Log.v(
3745 TAG, "Stopping visible=" + r.visible + " for " + r);
3746 if (!r.visible) {
3747 mWindowManager.setAppVisibility(r, false);
3748 }
3749 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3750 } catch (Exception e) {
3751 // Maybe just ignore exceptions here... if the process
3752 // has crashed, our death notification will clean things
3753 // up.
3754 Log.w(TAG, "Exception thrown during pause", e);
3755 // Just in case, assume it to be stopped.
3756 r.stopped = true;
3757 r.state = ActivityState.STOPPED;
3758 if (r.configDestroy) {
3759 destroyActivityLocked(r, true);
3760 }
3761 }
3762 }
3763 }
3764
3765 /**
3766 * @return Returns true if the activity is being finished, false if for
3767 * some reason it is being left as-is.
3768 */
3769 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3770 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003771 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003772 TAG, "Finishing activity: token=" + token
3773 + ", result=" + resultCode + ", data=" + resultData);
3774
Dianne Hackborn75b03852009-06-12 15:43:26 -07003775 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 if (index < 0) {
3777 return false;
3778 }
3779 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3780
3781 // Is this the last activity left?
3782 boolean lastActivity = true;
3783 for (int i=mHistory.size()-1; i>=0; i--) {
3784 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3785 if (!p.finishing && p != r) {
3786 lastActivity = false;
3787 break;
3788 }
3789 }
3790
3791 // If this is the last activity, but it is the home activity, then
3792 // just don't finish it.
3793 if (lastActivity) {
3794 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3795 return false;
3796 }
3797 }
3798
3799 finishActivityLocked(r, index, resultCode, resultData, reason);
3800 return true;
3801 }
3802
3803 /**
3804 * @return Returns true if this activity has been removed from the history
3805 * list, or false if it is still in the list and will be removed later.
3806 */
3807 private final boolean finishActivityLocked(HistoryRecord r, int index,
3808 int resultCode, Intent resultData, String reason) {
3809 if (r.finishing) {
3810 Log.w(TAG, "Duplicate finish request for " + r);
3811 return false;
3812 }
3813
3814 r.finishing = true;
3815 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3816 System.identityHashCode(r),
3817 r.task.taskId, r.shortComponentName, reason);
3818 r.task.numActivities--;
3819 if (r.frontOfTask && index < (mHistory.size()-1)) {
3820 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3821 if (next.task == r.task) {
3822 next.frontOfTask = true;
3823 }
3824 }
3825
3826 r.pauseKeyDispatchingLocked();
3827 if (mFocusedActivity == r) {
3828 setFocusedActivityLocked(topRunningActivityLocked(null));
3829 }
3830
3831 // send the result
3832 HistoryRecord resultTo = r.resultTo;
3833 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003834 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3835 + " who=" + r.resultWho + " req=" + r.requestCode
3836 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 if (r.info.applicationInfo.uid > 0) {
3838 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3839 r.packageName, resultData, r);
3840 }
3841 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3842 resultData);
3843 r.resultTo = null;
3844 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003845 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846
3847 // Make sure this HistoryRecord is not holding on to other resources,
3848 // because clients have remote IPC references to this object so we
3849 // can't assume that will go away and want to avoid circular IPC refs.
3850 r.results = null;
3851 r.pendingResults = null;
3852 r.newIntents = null;
3853 r.icicle = null;
3854
3855 if (mPendingThumbnails.size() > 0) {
3856 // There are clients waiting to receive thumbnails so, in case
3857 // this is an activity that someone is waiting for, add it
3858 // to the pending list so we can correctly update the clients.
3859 mCancelledThumbnails.add(r);
3860 }
3861
3862 if (mResumedActivity == r) {
3863 boolean endTask = index <= 0
3864 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3865 if (DEBUG_TRANSITION) Log.v(TAG,
3866 "Prepare close transition: finishing " + r);
3867 mWindowManager.prepareAppTransition(endTask
3868 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3869 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3870
3871 // Tell window manager to prepare for this one to be removed.
3872 mWindowManager.setAppVisibility(r, false);
3873
3874 if (mPausingActivity == null) {
3875 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3876 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3877 startPausingLocked(false, false);
3878 }
3879
3880 } else if (r.state != ActivityState.PAUSING) {
3881 // If the activity is PAUSING, we will complete the finish once
3882 // it is done pausing; else we can just directly finish it here.
3883 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3884 return finishCurrentActivityLocked(r, index,
3885 FINISH_AFTER_PAUSE) == null;
3886 } else {
3887 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3888 }
3889
3890 return false;
3891 }
3892
3893 private static final int FINISH_IMMEDIATELY = 0;
3894 private static final int FINISH_AFTER_PAUSE = 1;
3895 private static final int FINISH_AFTER_VISIBLE = 2;
3896
3897 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3898 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003899 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003900 if (index < 0) {
3901 return null;
3902 }
3903
3904 return finishCurrentActivityLocked(r, index, mode);
3905 }
3906
3907 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3908 int index, int mode) {
3909 // First things first: if this activity is currently visible,
3910 // and the resumed activity is not yet visible, then hold off on
3911 // finishing until the resumed one becomes visible.
3912 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3913 if (!mStoppingActivities.contains(r)) {
3914 mStoppingActivities.add(r);
3915 if (mStoppingActivities.size() > 3) {
3916 // If we already have a few activities waiting to stop,
3917 // then give up on things going idle and start clearing
3918 // them out.
3919 Message msg = Message.obtain();
3920 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3921 mHandler.sendMessage(msg);
3922 }
3923 }
3924 r.state = ActivityState.STOPPING;
3925 updateOomAdjLocked();
3926 return r;
3927 }
3928
3929 // make sure the record is cleaned out of other places.
3930 mStoppingActivities.remove(r);
3931 mWaitingVisibleActivities.remove(r);
3932 if (mResumedActivity == r) {
3933 mResumedActivity = null;
3934 }
3935 final ActivityState prevState = r.state;
3936 r.state = ActivityState.FINISHING;
3937
3938 if (mode == FINISH_IMMEDIATELY
3939 || prevState == ActivityState.STOPPED
3940 || prevState == ActivityState.INITIALIZING) {
3941 // If this activity is already stopped, we can just finish
3942 // it right now.
3943 return destroyActivityLocked(r, true) ? null : r;
3944 } else {
3945 // Need to go through the full pause cycle to get this
3946 // activity into the stopped state and then finish it.
3947 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3948 mFinishingActivities.add(r);
3949 resumeTopActivityLocked(null);
3950 }
3951 return r;
3952 }
3953
3954 /**
3955 * This is the internal entry point for handling Activity.finish().
3956 *
3957 * @param token The Binder token referencing the Activity we want to finish.
3958 * @param resultCode Result code, if any, from this Activity.
3959 * @param resultData Result data (Intent), if any, from this Activity.
3960 *
3961 * @result Returns true if the activity successfully finished, or false if it is still running.
3962 */
3963 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3964 // Refuse possible leaked file descriptors
3965 if (resultData != null && resultData.hasFileDescriptors() == true) {
3966 throw new IllegalArgumentException("File descriptors passed in Intent");
3967 }
3968
3969 synchronized(this) {
3970 if (mWatcher != null) {
3971 // Find the first activity that is not finishing.
3972 HistoryRecord next = topRunningActivityLocked(token, 0);
3973 if (next != null) {
3974 // ask watcher if this is allowed
3975 boolean resumeOK = true;
3976 try {
3977 resumeOK = mWatcher.activityResuming(next.packageName);
3978 } catch (RemoteException e) {
3979 mWatcher = null;
3980 }
3981
3982 if (!resumeOK) {
3983 return false;
3984 }
3985 }
3986 }
3987 final long origId = Binder.clearCallingIdentity();
3988 boolean res = requestFinishActivityLocked(token, resultCode,
3989 resultData, "app-request");
3990 Binder.restoreCallingIdentity(origId);
3991 return res;
3992 }
3993 }
3994
3995 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3996 String resultWho, int requestCode, int resultCode, Intent data) {
3997
3998 if (callingUid > 0) {
3999 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4000 data, r);
4001 }
4002
The Android Open Source Project10592532009-03-18 17:39:46 -07004003 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4004 + " : who=" + resultWho + " req=" + requestCode
4005 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004006 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4007 try {
4008 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4009 list.add(new ResultInfo(resultWho, requestCode,
4010 resultCode, data));
4011 r.app.thread.scheduleSendResult(r, list);
4012 return;
4013 } catch (Exception e) {
4014 Log.w(TAG, "Exception thrown sending result to " + r, e);
4015 }
4016 }
4017
4018 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4019 }
4020
4021 public final void finishSubActivity(IBinder token, String resultWho,
4022 int requestCode) {
4023 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004024 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004025 if (index < 0) {
4026 return;
4027 }
4028 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4029
4030 final long origId = Binder.clearCallingIdentity();
4031
4032 int i;
4033 for (i=mHistory.size()-1; i>=0; i--) {
4034 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4035 if (r.resultTo == self && r.requestCode == requestCode) {
4036 if ((r.resultWho == null && resultWho == null) ||
4037 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4038 finishActivityLocked(r, i,
4039 Activity.RESULT_CANCELED, null, "request-sub");
4040 }
4041 }
4042 }
4043
4044 Binder.restoreCallingIdentity(origId);
4045 }
4046 }
4047
4048 /**
4049 * Perform clean-up of service connections in an activity record.
4050 */
4051 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4052 // Throw away any services that have been bound by this activity.
4053 if (r.connections != null) {
4054 Iterator<ConnectionRecord> it = r.connections.iterator();
4055 while (it.hasNext()) {
4056 ConnectionRecord c = it.next();
4057 removeConnectionLocked(c, null, r);
4058 }
4059 r.connections = null;
4060 }
4061 }
4062
4063 /**
4064 * Perform the common clean-up of an activity record. This is called both
4065 * as part of destroyActivityLocked() (when destroying the client-side
4066 * representation) and cleaning things up as a result of its hosting
4067 * processing going away, in which case there is no remaining client-side
4068 * state to destroy so only the cleanup here is needed.
4069 */
4070 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4071 if (mResumedActivity == r) {
4072 mResumedActivity = null;
4073 }
4074 if (mFocusedActivity == r) {
4075 mFocusedActivity = null;
4076 }
4077
4078 r.configDestroy = false;
4079 r.frozenBeforeDestroy = false;
4080
4081 // Make sure this record is no longer in the pending finishes list.
4082 // This could happen, for example, if we are trimming activities
4083 // down to the max limit while they are still waiting to finish.
4084 mFinishingActivities.remove(r);
4085 mWaitingVisibleActivities.remove(r);
4086
4087 // Remove any pending results.
4088 if (r.finishing && r.pendingResults != null) {
4089 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4090 PendingIntentRecord rec = apr.get();
4091 if (rec != null) {
4092 cancelIntentSenderLocked(rec, false);
4093 }
4094 }
4095 r.pendingResults = null;
4096 }
4097
4098 if (cleanServices) {
4099 cleanUpActivityServicesLocked(r);
4100 }
4101
4102 if (mPendingThumbnails.size() > 0) {
4103 // There are clients waiting to receive thumbnails so, in case
4104 // this is an activity that someone is waiting for, add it
4105 // to the pending list so we can correctly update the clients.
4106 mCancelledThumbnails.add(r);
4107 }
4108
4109 // Get rid of any pending idle timeouts.
4110 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4111 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4112 }
4113
4114 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4115 if (r.state != ActivityState.DESTROYED) {
4116 mHistory.remove(r);
4117 r.inHistory = false;
4118 r.state = ActivityState.DESTROYED;
4119 mWindowManager.removeAppToken(r);
4120 if (VALIDATE_TOKENS) {
4121 mWindowManager.validateAppTokens(mHistory);
4122 }
4123 cleanUpActivityServicesLocked(r);
4124 removeActivityUriPermissionsLocked(r);
4125 }
4126 }
4127
4128 /**
4129 * Destroy the current CLIENT SIDE instance of an activity. This may be
4130 * called both when actually finishing an activity, or when performing
4131 * a configuration switch where we destroy the current client-side object
4132 * but then create a new client-side object for this same HistoryRecord.
4133 */
4134 private final boolean destroyActivityLocked(HistoryRecord r,
4135 boolean removeFromApp) {
4136 if (DEBUG_SWITCH) Log.v(
4137 TAG, "Removing activity: token=" + r
4138 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4139 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4140 System.identityHashCode(r),
4141 r.task.taskId, r.shortComponentName);
4142
4143 boolean removedFromHistory = false;
4144
4145 cleanUpActivityLocked(r, false);
4146
4147 if (r.app != null) {
4148 if (removeFromApp) {
4149 int idx = r.app.activities.indexOf(r);
4150 if (idx >= 0) {
4151 r.app.activities.remove(idx);
4152 }
4153 if (r.persistent) {
4154 decPersistentCountLocked(r.app);
4155 }
4156 }
4157
4158 boolean skipDestroy = false;
4159
4160 try {
4161 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4162 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4163 r.configChangeFlags);
4164 } catch (Exception e) {
4165 // We can just ignore exceptions here... if the process
4166 // has crashed, our death notification will clean things
4167 // up.
4168 //Log.w(TAG, "Exception thrown during finish", e);
4169 if (r.finishing) {
4170 removeActivityFromHistoryLocked(r);
4171 removedFromHistory = true;
4172 skipDestroy = true;
4173 }
4174 }
4175
4176 r.app = null;
4177 r.nowVisible = false;
4178
4179 if (r.finishing && !skipDestroy) {
4180 r.state = ActivityState.DESTROYING;
4181 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4182 msg.obj = r;
4183 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4184 } else {
4185 r.state = ActivityState.DESTROYED;
4186 }
4187 } else {
4188 // remove this record from the history.
4189 if (r.finishing) {
4190 removeActivityFromHistoryLocked(r);
4191 removedFromHistory = true;
4192 } else {
4193 r.state = ActivityState.DESTROYED;
4194 }
4195 }
4196
4197 r.configChangeFlags = 0;
4198
4199 if (!mLRUActivities.remove(r)) {
4200 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4201 }
4202
4203 return removedFromHistory;
4204 }
4205
4206 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4207 ProcessRecord app)
4208 {
4209 int i = list.size();
4210 if (localLOGV) Log.v(
4211 TAG, "Removing app " + app + " from list " + list
4212 + " with " + i + " entries");
4213 while (i > 0) {
4214 i--;
4215 HistoryRecord r = (HistoryRecord)list.get(i);
4216 if (localLOGV) Log.v(
4217 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4218 if (r.app == app) {
4219 if (localLOGV) Log.v(TAG, "Removing this entry!");
4220 list.remove(i);
4221 }
4222 }
4223 }
4224
4225 /**
4226 * Main function for removing an existing process from the activity manager
4227 * as a result of that process going away. Clears out all connections
4228 * to the process.
4229 */
4230 private final void handleAppDiedLocked(ProcessRecord app,
4231 boolean restarting) {
4232 cleanUpApplicationRecordLocked(app, restarting, -1);
4233 if (!restarting) {
4234 mLRUProcesses.remove(app);
4235 }
4236
4237 // Just in case...
4238 if (mPausingActivity != null && mPausingActivity.app == app) {
4239 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4240 mPausingActivity = null;
4241 }
4242 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4243 mLastPausedActivity = null;
4244 }
4245
4246 // Remove this application's activities from active lists.
4247 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4248 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4249 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4250 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4251
4252 boolean atTop = true;
4253 boolean hasVisibleActivities = false;
4254
4255 // Clean out the history list.
4256 int i = mHistory.size();
4257 if (localLOGV) Log.v(
4258 TAG, "Removing app " + app + " from history with " + i + " entries");
4259 while (i > 0) {
4260 i--;
4261 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4262 if (localLOGV) Log.v(
4263 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4264 if (r.app == app) {
4265 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4266 if (localLOGV) Log.v(
4267 TAG, "Removing this entry! frozen=" + r.haveState
4268 + " finishing=" + r.finishing);
4269 mHistory.remove(i);
4270
4271 r.inHistory = false;
4272 mWindowManager.removeAppToken(r);
4273 if (VALIDATE_TOKENS) {
4274 mWindowManager.validateAppTokens(mHistory);
4275 }
4276 removeActivityUriPermissionsLocked(r);
4277
4278 } else {
4279 // We have the current state for this activity, so
4280 // it can be restarted later when needed.
4281 if (localLOGV) Log.v(
4282 TAG, "Keeping entry, setting app to null");
4283 if (r.visible) {
4284 hasVisibleActivities = true;
4285 }
4286 r.app = null;
4287 r.nowVisible = false;
4288 if (!r.haveState) {
4289 r.icicle = null;
4290 }
4291 }
4292
4293 cleanUpActivityLocked(r, true);
4294 r.state = ActivityState.STOPPED;
4295 }
4296 atTop = false;
4297 }
4298
4299 app.activities.clear();
4300
4301 if (app.instrumentationClass != null) {
4302 Log.w(TAG, "Crash of app " + app.processName
4303 + " running instrumentation " + app.instrumentationClass);
4304 Bundle info = new Bundle();
4305 info.putString("shortMsg", "Process crashed.");
4306 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4307 }
4308
4309 if (!restarting) {
4310 if (!resumeTopActivityLocked(null)) {
4311 // If there was nothing to resume, and we are not already
4312 // restarting this process, but there is a visible activity that
4313 // is hosted by the process... then make sure all visible
4314 // activities are running, taking care of restarting this
4315 // process.
4316 if (hasVisibleActivities) {
4317 ensureActivitiesVisibleLocked(null, 0);
4318 }
4319 }
4320 }
4321 }
4322
4323 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4324 IBinder threadBinder = thread.asBinder();
4325
4326 // Find the application record.
4327 int count = mLRUProcesses.size();
4328 int i;
4329 for (i=0; i<count; i++) {
4330 ProcessRecord rec = mLRUProcesses.get(i);
4331 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4332 return i;
4333 }
4334 }
4335 return -1;
4336 }
4337
4338 private final ProcessRecord getRecordForAppLocked(
4339 IApplicationThread thread) {
4340 if (thread == null) {
4341 return null;
4342 }
4343
4344 int appIndex = getLRURecordIndexForAppLocked(thread);
4345 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4346 }
4347
4348 private final void appDiedLocked(ProcessRecord app, int pid,
4349 IApplicationThread thread) {
4350
4351 mProcDeaths[0]++;
4352
4353 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4354 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4355 + ") has died.");
4356 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4357 if (localLOGV) Log.v(
4358 TAG, "Dying app: " + app + ", pid: " + pid
4359 + ", thread: " + thread.asBinder());
4360 boolean doLowMem = app.instrumentationClass == null;
4361 handleAppDiedLocked(app, false);
4362
4363 if (doLowMem) {
4364 // If there are no longer any background processes running,
4365 // and the app that died was not running instrumentation,
4366 // then tell everyone we are now low on memory.
4367 boolean haveBg = false;
4368 int count = mLRUProcesses.size();
4369 int i;
4370 for (i=0; i<count; i++) {
4371 ProcessRecord rec = mLRUProcesses.get(i);
4372 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4373 haveBg = true;
4374 break;
4375 }
4376 }
4377
4378 if (!haveBg) {
4379 Log.i(TAG, "Low Memory: No more background processes.");
4380 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4381 for (i=0; i<count; i++) {
4382 ProcessRecord rec = mLRUProcesses.get(i);
4383 if (rec.thread != null) {
4384 rec.lastRequestedGc = SystemClock.uptimeMillis();
4385 try {
4386 rec.thread.scheduleLowMemory();
4387 } catch (RemoteException e) {
4388 // Don't care if the process is gone.
4389 }
4390 }
4391 }
4392 }
4393 }
4394 } else if (Config.LOGD) {
4395 Log.d(TAG, "Received spurious death notification for thread "
4396 + thread.asBinder());
4397 }
4398 }
4399
4400 final String readFile(String filename) {
4401 try {
4402 FileInputStream fs = new FileInputStream(filename);
4403 byte[] inp = new byte[8192];
4404 int size = fs.read(inp);
4405 fs.close();
4406 return new String(inp, 0, 0, size);
4407 } catch (java.io.IOException e) {
4408 }
4409 return "";
4410 }
4411
4412 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4413 final String annotation) {
4414 if (app.notResponding || app.crashing) {
4415 return;
4416 }
4417
4418 // Log the ANR to the event log.
4419 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4420
4421 // If we are on a secure build and the application is not interesting to the user (it is
4422 // not visible or in the background), just kill it instead of displaying a dialog.
4423 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4424 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4425 Process.killProcess(app.pid);
4426 return;
4427 }
4428
4429 // DeviceMonitor.start();
4430
4431 String processInfo = null;
4432 if (MONITOR_CPU_USAGE) {
4433 updateCpuStatsNow();
4434 synchronized (mProcessStatsThread) {
4435 processInfo = mProcessStats.printCurrentState();
4436 }
4437 }
4438
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004439 StringBuilder info = mStringBuilder;
4440 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004441 info.append("ANR (application not responding) in process: ");
4442 info.append(app.processName);
4443 if (annotation != null) {
4444 info.append("\nAnnotation: ");
4445 info.append(annotation);
4446 }
4447 if (MONITOR_CPU_USAGE) {
4448 info.append("\nCPU usage:\n");
4449 info.append(processInfo);
4450 }
4451 Log.i(TAG, info.toString());
4452
4453 // The application is not responding. Dump as many thread traces as we can.
4454 boolean fileDump = prepareTraceFile(true);
4455 if (!fileDump) {
4456 // Dumping traces to the log, just dump the process that isn't responding so
4457 // we don't overflow the log
4458 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4459 } else {
4460 // Dumping traces to a file so dump all active processes we know about
4461 synchronized (this) {
4462 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4463 ProcessRecord r = mLRUProcesses.get(i);
4464 if (r.thread != null) {
4465 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4466 }
4467 }
4468 }
4469 }
4470
4471 if (mWatcher != null) {
4472 try {
4473 int res = mWatcher.appNotResponding(app.processName,
4474 app.pid, info.toString());
4475 if (res != 0) {
4476 if (res < 0) {
4477 // wait until the SIGQUIT has had a chance to process before killing the
4478 // process.
4479 try {
4480 wait(2000);
4481 } catch (InterruptedException e) {
4482 }
4483
4484 Process.killProcess(app.pid);
4485 return;
4486 }
4487 }
4488 } catch (RemoteException e) {
4489 mWatcher = null;
4490 }
4491 }
4492
4493 makeAppNotRespondingLocked(app,
4494 activity != null ? activity.shortComponentName : null,
4495 annotation != null ? "ANR " + annotation : "ANR",
4496 info.toString(), null);
4497 Message msg = Message.obtain();
4498 HashMap map = new HashMap();
4499 msg.what = SHOW_NOT_RESPONDING_MSG;
4500 msg.obj = map;
4501 map.put("app", app);
4502 if (activity != null) {
4503 map.put("activity", activity);
4504 }
4505
4506 mHandler.sendMessage(msg);
4507 return;
4508 }
4509
4510 /**
4511 * If a stack trace file has been configured, prepare the filesystem
4512 * by creating the directory if it doesn't exist and optionally
4513 * removing the old trace file.
4514 *
4515 * @param removeExisting If set, the existing trace file will be removed.
4516 * @return Returns true if the trace file preparations succeeded
4517 */
4518 public static boolean prepareTraceFile(boolean removeExisting) {
4519 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4520 boolean fileReady = false;
4521 if (!TextUtils.isEmpty(tracesPath)) {
4522 File f = new File(tracesPath);
4523 if (!f.exists()) {
4524 // Ensure the enclosing directory exists
4525 File dir = f.getParentFile();
4526 if (!dir.exists()) {
4527 fileReady = dir.mkdirs();
4528 FileUtils.setPermissions(dir.getAbsolutePath(),
4529 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4530 } else if (dir.isDirectory()) {
4531 fileReady = true;
4532 }
4533 } else if (removeExisting) {
4534 // Remove the previous traces file, so we don't fill the disk.
4535 // The VM will recreate it
4536 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4537 fileReady = f.delete();
4538 }
4539 }
4540
4541 return fileReady;
4542 }
4543
4544
4545 private final void decPersistentCountLocked(ProcessRecord app)
4546 {
4547 app.persistentActivities--;
4548 if (app.persistentActivities > 0) {
4549 // Still more of 'em...
4550 return;
4551 }
4552 if (app.persistent) {
4553 // Ah, but the application itself is persistent. Whatever!
4554 return;
4555 }
4556
4557 // App is no longer persistent... make sure it and the ones
4558 // following it in the LRU list have the correc oom_adj.
4559 updateOomAdjLocked();
4560 }
4561
4562 public void setPersistent(IBinder token, boolean isPersistent) {
4563 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4564 != PackageManager.PERMISSION_GRANTED) {
4565 String msg = "Permission Denial: setPersistent() from pid="
4566 + Binder.getCallingPid()
4567 + ", uid=" + Binder.getCallingUid()
4568 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4569 Log.w(TAG, msg);
4570 throw new SecurityException(msg);
4571 }
4572
4573 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004574 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004575 if (index < 0) {
4576 return;
4577 }
4578 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4579 ProcessRecord app = r.app;
4580
4581 if (localLOGV) Log.v(
4582 TAG, "Setting persistence " + isPersistent + ": " + r);
4583
4584 if (isPersistent) {
4585 if (r.persistent) {
4586 // Okay okay, I heard you already!
4587 if (localLOGV) Log.v(TAG, "Already persistent!");
4588 return;
4589 }
4590 r.persistent = true;
4591 app.persistentActivities++;
4592 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4593 if (app.persistentActivities > 1) {
4594 // We aren't the first...
4595 if (localLOGV) Log.v(TAG, "Not the first!");
4596 return;
4597 }
4598 if (app.persistent) {
4599 // This would be redundant.
4600 if (localLOGV) Log.v(TAG, "App is persistent!");
4601 return;
4602 }
4603
4604 // App is now persistent... make sure it and the ones
4605 // following it now have the correct oom_adj.
4606 final long origId = Binder.clearCallingIdentity();
4607 updateOomAdjLocked();
4608 Binder.restoreCallingIdentity(origId);
4609
4610 } else {
4611 if (!r.persistent) {
4612 // Okay okay, I heard you already!
4613 return;
4614 }
4615 r.persistent = false;
4616 final long origId = Binder.clearCallingIdentity();
4617 decPersistentCountLocked(app);
4618 Binder.restoreCallingIdentity(origId);
4619
4620 }
4621 }
4622 }
4623
4624 public boolean clearApplicationUserData(final String packageName,
4625 final IPackageDataObserver observer) {
4626 int uid = Binder.getCallingUid();
4627 int pid = Binder.getCallingPid();
4628 long callingId = Binder.clearCallingIdentity();
4629 try {
4630 IPackageManager pm = ActivityThread.getPackageManager();
4631 int pkgUid = -1;
4632 synchronized(this) {
4633 try {
4634 pkgUid = pm.getPackageUid(packageName);
4635 } catch (RemoteException e) {
4636 }
4637 if (pkgUid == -1) {
4638 Log.w(TAG, "Invalid packageName:" + packageName);
4639 return false;
4640 }
4641 if (uid == pkgUid || checkComponentPermission(
4642 android.Manifest.permission.CLEAR_APP_USER_DATA,
4643 pid, uid, -1)
4644 == PackageManager.PERMISSION_GRANTED) {
4645 restartPackageLocked(packageName, pkgUid);
4646 } else {
4647 throw new SecurityException(pid+" does not have permission:"+
4648 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4649 "for process:"+packageName);
4650 }
4651 }
4652
4653 try {
4654 //clear application user data
4655 pm.clearApplicationUserData(packageName, observer);
4656 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4657 Uri.fromParts("package", packageName, null));
4658 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4659 broadcastIntentLocked(null, null, intent,
4660 null, null, 0, null, null, null,
4661 false, false, MY_PID, Process.SYSTEM_UID);
4662 } catch (RemoteException e) {
4663 }
4664 } finally {
4665 Binder.restoreCallingIdentity(callingId);
4666 }
4667 return true;
4668 }
4669
4670 public void restartPackage(final String packageName) {
4671 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4672 != PackageManager.PERMISSION_GRANTED) {
4673 String msg = "Permission Denial: restartPackage() from pid="
4674 + Binder.getCallingPid()
4675 + ", uid=" + Binder.getCallingUid()
4676 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4677 Log.w(TAG, msg);
4678 throw new SecurityException(msg);
4679 }
4680
4681 long callingId = Binder.clearCallingIdentity();
4682 try {
4683 IPackageManager pm = ActivityThread.getPackageManager();
4684 int pkgUid = -1;
4685 synchronized(this) {
4686 try {
4687 pkgUid = pm.getPackageUid(packageName);
4688 } catch (RemoteException e) {
4689 }
4690 if (pkgUid == -1) {
4691 Log.w(TAG, "Invalid packageName: " + packageName);
4692 return;
4693 }
4694 restartPackageLocked(packageName, pkgUid);
4695 }
4696 } finally {
4697 Binder.restoreCallingIdentity(callingId);
4698 }
4699 }
4700
4701 private void restartPackageLocked(final String packageName, int uid) {
4702 uninstallPackageLocked(packageName, uid, false);
4703 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4704 Uri.fromParts("package", packageName, null));
4705 intent.putExtra(Intent.EXTRA_UID, uid);
4706 broadcastIntentLocked(null, null, intent,
4707 null, null, 0, null, null, null,
4708 false, false, MY_PID, Process.SYSTEM_UID);
4709 }
4710
4711 private final void uninstallPackageLocked(String name, int uid,
4712 boolean callerWillRestart) {
4713 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4714
4715 int i, N;
4716
4717 final String procNamePrefix = name + ":";
4718 if (uid < 0) {
4719 try {
4720 uid = ActivityThread.getPackageManager().getPackageUid(name);
4721 } catch (RemoteException e) {
4722 }
4723 }
4724
4725 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4726 while (badApps.hasNext()) {
4727 SparseArray<Long> ba = badApps.next();
4728 if (ba.get(uid) != null) {
4729 badApps.remove();
4730 }
4731 }
4732
4733 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4734
4735 // Remove all processes this package may have touched: all with the
4736 // same UID (except for the system or root user), and all whose name
4737 // matches the package name.
4738 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4739 final int NA = apps.size();
4740 for (int ia=0; ia<NA; ia++) {
4741 ProcessRecord app = apps.valueAt(ia);
4742 if (app.removed) {
4743 procs.add(app);
4744 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4745 || app.processName.equals(name)
4746 || app.processName.startsWith(procNamePrefix)) {
4747 app.removed = true;
4748 procs.add(app);
4749 }
4750 }
4751 }
4752
4753 N = procs.size();
4754 for (i=0; i<N; i++) {
4755 removeProcessLocked(procs.get(i), callerWillRestart);
4756 }
4757
4758 for (i=mHistory.size()-1; i>=0; i--) {
4759 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4760 if (r.packageName.equals(name)) {
4761 if (Config.LOGD) Log.d(
4762 TAG, " Force finishing activity "
4763 + r.intent.getComponent().flattenToShortString());
4764 if (r.app != null) {
4765 r.app.removed = true;
4766 }
4767 r.app = null;
4768 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4769 }
4770 }
4771
4772 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4773 for (ServiceRecord service : mServices.values()) {
4774 if (service.packageName.equals(name)) {
4775 if (service.app != null) {
4776 service.app.removed = true;
4777 }
4778 service.app = null;
4779 services.add(service);
4780 }
4781 }
4782
4783 N = services.size();
4784 for (i=0; i<N; i++) {
4785 bringDownServiceLocked(services.get(i), true);
4786 }
4787
4788 resumeTopActivityLocked(null);
4789 }
4790
4791 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4792 final String name = app.processName;
4793 final int uid = app.info.uid;
4794 if (Config.LOGD) Log.d(
4795 TAG, "Force removing process " + app + " (" + name
4796 + "/" + uid + ")");
4797
4798 mProcessNames.remove(name, uid);
4799 boolean needRestart = false;
4800 if (app.pid > 0 && app.pid != MY_PID) {
4801 int pid = app.pid;
4802 synchronized (mPidsSelfLocked) {
4803 mPidsSelfLocked.remove(pid);
4804 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4805 }
4806 handleAppDiedLocked(app, true);
4807 mLRUProcesses.remove(app);
4808 Process.killProcess(pid);
4809
4810 if (app.persistent) {
4811 if (!callerWillRestart) {
4812 addAppLocked(app.info);
4813 } else {
4814 needRestart = true;
4815 }
4816 }
4817 } else {
4818 mRemovedProcesses.add(app);
4819 }
4820
4821 return needRestart;
4822 }
4823
4824 private final void processStartTimedOutLocked(ProcessRecord app) {
4825 final int pid = app.pid;
4826 boolean gone = false;
4827 synchronized (mPidsSelfLocked) {
4828 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4829 if (knownApp != null && knownApp.thread == null) {
4830 mPidsSelfLocked.remove(pid);
4831 gone = true;
4832 }
4833 }
4834
4835 if (gone) {
4836 Log.w(TAG, "Process " + app + " failed to attach");
4837 mProcessNames.remove(app.processName, app.info.uid);
4838 Process.killProcess(pid);
4839 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4840 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4841 mPendingBroadcast = null;
4842 scheduleBroadcastsLocked();
4843 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004844 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4845 Log.w(TAG, "Unattached app died before backup, skipping");
4846 try {
4847 IBackupManager bm = IBackupManager.Stub.asInterface(
4848 ServiceManager.getService(Context.BACKUP_SERVICE));
4849 bm.agentDisconnected(app.info.packageName);
4850 } catch (RemoteException e) {
4851 // Can't happen; the backup manager is local
4852 }
4853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004854 } else {
4855 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4856 }
4857 }
4858
4859 private final boolean attachApplicationLocked(IApplicationThread thread,
4860 int pid) {
4861
4862 // Find the application record that is being attached... either via
4863 // the pid if we are running in multiple processes, or just pull the
4864 // next app record if we are emulating process with anonymous threads.
4865 ProcessRecord app;
4866 if (pid != MY_PID && pid >= 0) {
4867 synchronized (mPidsSelfLocked) {
4868 app = mPidsSelfLocked.get(pid);
4869 }
4870 } else if (mStartingProcesses.size() > 0) {
4871 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004872 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004873 } else {
4874 app = null;
4875 }
4876
4877 if (app == null) {
4878 Log.w(TAG, "No pending application record for pid " + pid
4879 + " (IApplicationThread " + thread + "); dropping process");
4880 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4881 if (pid > 0 && pid != MY_PID) {
4882 Process.killProcess(pid);
4883 } else {
4884 try {
4885 thread.scheduleExit();
4886 } catch (Exception e) {
4887 // Ignore exceptions.
4888 }
4889 }
4890 return false;
4891 }
4892
4893 // If this application record is still attached to a previous
4894 // process, clean it up now.
4895 if (app.thread != null) {
4896 handleAppDiedLocked(app, true);
4897 }
4898
4899 // Tell the process all about itself.
4900
4901 if (localLOGV) Log.v(
4902 TAG, "Binding process pid " + pid + " to record " + app);
4903
4904 String processName = app.processName;
4905 try {
4906 thread.asBinder().linkToDeath(new AppDeathRecipient(
4907 app, pid, thread), 0);
4908 } catch (RemoteException e) {
4909 app.resetPackageList();
4910 startProcessLocked(app, "link fail", processName);
4911 return false;
4912 }
4913
4914 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4915
4916 app.thread = thread;
4917 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004918 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004919 app.forcingToForeground = null;
4920 app.foregroundServices = false;
4921 app.debugging = false;
4922
4923 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4924
4925 List providers = generateApplicationProvidersLocked(app);
4926
4927 if (localLOGV) Log.v(
4928 TAG, "New app record " + app
4929 + " thread=" + thread.asBinder() + " pid=" + pid);
4930 try {
4931 int testMode = IApplicationThread.DEBUG_OFF;
4932 if (mDebugApp != null && mDebugApp.equals(processName)) {
4933 testMode = mWaitForDebugger
4934 ? IApplicationThread.DEBUG_WAIT
4935 : IApplicationThread.DEBUG_ON;
4936 app.debugging = true;
4937 if (mDebugTransient) {
4938 mDebugApp = mOrigDebugApp;
4939 mWaitForDebugger = mOrigWaitForDebugger;
4940 }
4941 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004942 // If the app is being launched for restore or full backup, set it up specially
4943 boolean isRestrictedBackupMode = false;
4944 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4945 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4946 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4947 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004948 ensurePackageDexOpt(app.instrumentationInfo != null
4949 ? app.instrumentationInfo.packageName
4950 : app.info.packageName);
4951 if (app.instrumentationClass != null) {
4952 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004953 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004954 thread.bindApplication(processName, app.instrumentationInfo != null
4955 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004956 app.instrumentationClass, app.instrumentationProfileFile,
4957 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004958 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004959 updateLRUListLocked(app, false);
4960 app.lastRequestedGc = SystemClock.uptimeMillis();
4961 } catch (Exception e) {
4962 // todo: Yikes! What should we do? For now we will try to
4963 // start another process, but that could easily get us in
4964 // an infinite loop of restarting processes...
4965 Log.w(TAG, "Exception thrown during bind!", e);
4966
4967 app.resetPackageList();
4968 startProcessLocked(app, "bind fail", processName);
4969 return false;
4970 }
4971
4972 // Remove this record from the list of starting applications.
4973 mPersistentStartingProcesses.remove(app);
4974 mProcessesOnHold.remove(app);
4975
4976 boolean badApp = false;
4977 boolean didSomething = false;
4978
4979 // See if the top visible activity is waiting to run in this process...
4980 HistoryRecord hr = topRunningActivityLocked(null);
4981 if (hr != null) {
4982 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4983 && processName.equals(hr.processName)) {
4984 try {
4985 if (realStartActivityLocked(hr, app, true, true)) {
4986 didSomething = true;
4987 }
4988 } catch (Exception e) {
4989 Log.w(TAG, "Exception in new application when starting activity "
4990 + hr.intent.getComponent().flattenToShortString(), e);
4991 badApp = true;
4992 }
4993 } else {
4994 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4995 }
4996 }
4997
4998 // Find any services that should be running in this process...
4999 if (!badApp && mPendingServices.size() > 0) {
5000 ServiceRecord sr = null;
5001 try {
5002 for (int i=0; i<mPendingServices.size(); i++) {
5003 sr = mPendingServices.get(i);
5004 if (app.info.uid != sr.appInfo.uid
5005 || !processName.equals(sr.processName)) {
5006 continue;
5007 }
5008
5009 mPendingServices.remove(i);
5010 i--;
5011 realStartServiceLocked(sr, app);
5012 didSomething = true;
5013 }
5014 } catch (Exception e) {
5015 Log.w(TAG, "Exception in new application when starting service "
5016 + sr.shortName, e);
5017 badApp = true;
5018 }
5019 }
5020
5021 // Check if the next broadcast receiver is in this process...
5022 BroadcastRecord br = mPendingBroadcast;
5023 if (!badApp && br != null && br.curApp == app) {
5024 try {
5025 mPendingBroadcast = null;
5026 processCurBroadcastLocked(br, app);
5027 didSomething = true;
5028 } catch (Exception e) {
5029 Log.w(TAG, "Exception in new application when starting receiver "
5030 + br.curComponent.flattenToShortString(), e);
5031 badApp = true;
5032 logBroadcastReceiverDiscard(br);
5033 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5034 br.resultExtras, br.resultAbort, true);
5035 scheduleBroadcastsLocked();
5036 }
5037 }
5038
Christopher Tate181fafa2009-05-14 11:12:14 -07005039 // Check whether the next backup agent is in this process...
5040 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5041 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005042 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005043 try {
5044 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5045 } catch (Exception e) {
5046 Log.w(TAG, "Exception scheduling backup agent creation: ");
5047 e.printStackTrace();
5048 }
5049 }
5050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005051 if (badApp) {
5052 // todo: Also need to kill application to deal with all
5053 // kinds of exceptions.
5054 handleAppDiedLocked(app, false);
5055 return false;
5056 }
5057
5058 if (!didSomething) {
5059 updateOomAdjLocked();
5060 }
5061
5062 return true;
5063 }
5064
5065 public final void attachApplication(IApplicationThread thread) {
5066 synchronized (this) {
5067 int callingPid = Binder.getCallingPid();
5068 final long origId = Binder.clearCallingIdentity();
5069 attachApplicationLocked(thread, callingPid);
5070 Binder.restoreCallingIdentity(origId);
5071 }
5072 }
5073
5074 public final void activityIdle(IBinder token) {
5075 final long origId = Binder.clearCallingIdentity();
5076 activityIdleInternal(token, false);
5077 Binder.restoreCallingIdentity(origId);
5078 }
5079
5080 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5081 boolean remove) {
5082 int N = mStoppingActivities.size();
5083 if (N <= 0) return null;
5084
5085 ArrayList<HistoryRecord> stops = null;
5086
5087 final boolean nowVisible = mResumedActivity != null
5088 && mResumedActivity.nowVisible
5089 && !mResumedActivity.waitingVisible;
5090 for (int i=0; i<N; i++) {
5091 HistoryRecord s = mStoppingActivities.get(i);
5092 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5093 + nowVisible + " waitingVisible=" + s.waitingVisible
5094 + " finishing=" + s.finishing);
5095 if (s.waitingVisible && nowVisible) {
5096 mWaitingVisibleActivities.remove(s);
5097 s.waitingVisible = false;
5098 if (s.finishing) {
5099 // If this activity is finishing, it is sitting on top of
5100 // everyone else but we now know it is no longer needed...
5101 // so get rid of it. Otherwise, we need to go through the
5102 // normal flow and hide it once we determine that it is
5103 // hidden by the activities in front of it.
5104 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5105 mWindowManager.setAppVisibility(s, false);
5106 }
5107 }
5108 if (!s.waitingVisible && remove) {
5109 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5110 if (stops == null) {
5111 stops = new ArrayList<HistoryRecord>();
5112 }
5113 stops.add(s);
5114 mStoppingActivities.remove(i);
5115 N--;
5116 i--;
5117 }
5118 }
5119
5120 return stops;
5121 }
5122
5123 void enableScreenAfterBoot() {
5124 mWindowManager.enableScreenAfterBoot();
5125 }
5126
5127 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5128 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5129
5130 ArrayList<HistoryRecord> stops = null;
5131 ArrayList<HistoryRecord> finishes = null;
5132 ArrayList<HistoryRecord> thumbnails = null;
5133 int NS = 0;
5134 int NF = 0;
5135 int NT = 0;
5136 IApplicationThread sendThumbnail = null;
5137 boolean booting = false;
5138 boolean enableScreen = false;
5139
5140 synchronized (this) {
5141 if (token != null) {
5142 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5143 }
5144
5145 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005146 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005147 if (index >= 0) {
5148 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5149
5150 // No longer need to keep the device awake.
5151 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5152 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5153 mLaunchingActivity.release();
5154 }
5155
5156 // We are now idle. If someone is waiting for a thumbnail from
5157 // us, we can now deliver.
5158 r.idle = true;
5159 scheduleAppGcsLocked();
5160 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5161 sendThumbnail = r.app.thread;
5162 r.thumbnailNeeded = false;
5163 }
5164
5165 // If this activity is fullscreen, set up to hide those under it.
5166
5167 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5168 ensureActivitiesVisibleLocked(null, 0);
5169
5170 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5171 if (!mBooted && !fromTimeout) {
5172 mBooted = true;
5173 enableScreen = true;
5174 }
5175 }
5176
5177 // Atomically retrieve all of the other things to do.
5178 stops = processStoppingActivitiesLocked(true);
5179 NS = stops != null ? stops.size() : 0;
5180 if ((NF=mFinishingActivities.size()) > 0) {
5181 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5182 mFinishingActivities.clear();
5183 }
5184 if ((NT=mCancelledThumbnails.size()) > 0) {
5185 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5186 mCancelledThumbnails.clear();
5187 }
5188
5189 booting = mBooting;
5190 mBooting = false;
5191 }
5192
5193 int i;
5194
5195 // Send thumbnail if requested.
5196 if (sendThumbnail != null) {
5197 try {
5198 sendThumbnail.requestThumbnail(token);
5199 } catch (Exception e) {
5200 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5201 sendPendingThumbnail(null, token, null, null, true);
5202 }
5203 }
5204
5205 // Stop any activities that are scheduled to do so but have been
5206 // waiting for the next one to start.
5207 for (i=0; i<NS; i++) {
5208 HistoryRecord r = (HistoryRecord)stops.get(i);
5209 synchronized (this) {
5210 if (r.finishing) {
5211 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5212 } else {
5213 stopActivityLocked(r);
5214 }
5215 }
5216 }
5217
5218 // Finish any activities that are scheduled to do so but have been
5219 // waiting for the next one to start.
5220 for (i=0; i<NF; i++) {
5221 HistoryRecord r = (HistoryRecord)finishes.get(i);
5222 synchronized (this) {
5223 destroyActivityLocked(r, true);
5224 }
5225 }
5226
5227 // Report back to any thumbnail receivers.
5228 for (i=0; i<NT; i++) {
5229 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5230 sendPendingThumbnail(r, null, null, null, true);
5231 }
5232
5233 if (booting) {
5234 // Ensure that any processes we had put on hold are now started
5235 // up.
5236 final int NP = mProcessesOnHold.size();
5237 if (NP > 0) {
5238 ArrayList<ProcessRecord> procs =
5239 new ArrayList<ProcessRecord>(mProcessesOnHold);
5240 for (int ip=0; ip<NP; ip++) {
5241 this.startProcessLocked(procs.get(ip), "on-hold", null);
5242 }
5243 }
5244 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5245 // Tell anyone interested that we are done booting!
5246 synchronized (this) {
5247 broadcastIntentLocked(null, null,
5248 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5249 null, null, 0, null, null,
5250 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5251 false, false, MY_PID, Process.SYSTEM_UID);
5252 }
5253 }
5254 }
5255
5256 trimApplications();
5257 //dump();
5258 //mWindowManager.dump();
5259
5260 if (enableScreen) {
5261 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5262 SystemClock.uptimeMillis());
5263 enableScreenAfterBoot();
5264 }
5265 }
5266
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005267 final void ensureScreenEnabled() {
5268 boolean enableScreen;
5269 synchronized (this) {
5270 enableScreen = !mBooted;
5271 mBooted = true;
5272 }
5273
5274 if (enableScreen) {
5275 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5276 SystemClock.uptimeMillis());
5277 enableScreenAfterBoot();
5278 }
5279 }
5280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005281 public final void activityPaused(IBinder token, Bundle icicle) {
5282 // Refuse possible leaked file descriptors
5283 if (icicle != null && icicle.hasFileDescriptors()) {
5284 throw new IllegalArgumentException("File descriptors passed in Bundle");
5285 }
5286
5287 final long origId = Binder.clearCallingIdentity();
5288 activityPaused(token, icicle, false);
5289 Binder.restoreCallingIdentity(origId);
5290 }
5291
5292 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5293 if (DEBUG_PAUSE) Log.v(
5294 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5295 + ", timeout=" + timeout);
5296
5297 HistoryRecord r = null;
5298
5299 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005300 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005301 if (index >= 0) {
5302 r = (HistoryRecord)mHistory.get(index);
5303 if (!timeout) {
5304 r.icicle = icicle;
5305 r.haveState = true;
5306 }
5307 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5308 if (mPausingActivity == r) {
5309 r.state = ActivityState.PAUSED;
5310 completePauseLocked();
5311 } else {
5312 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5313 System.identityHashCode(r), r.shortComponentName,
5314 mPausingActivity != null
5315 ? mPausingActivity.shortComponentName : "(none)");
5316 }
5317 }
5318 }
5319 }
5320
5321 public final void activityStopped(IBinder token, Bitmap thumbnail,
5322 CharSequence description) {
5323 if (localLOGV) Log.v(
5324 TAG, "Activity stopped: token=" + token);
5325
5326 HistoryRecord r = null;
5327
5328 final long origId = Binder.clearCallingIdentity();
5329
5330 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005331 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005332 if (index >= 0) {
5333 r = (HistoryRecord)mHistory.get(index);
5334 r.thumbnail = thumbnail;
5335 r.description = description;
5336 r.stopped = true;
5337 r.state = ActivityState.STOPPED;
5338 if (!r.finishing) {
5339 if (r.configDestroy) {
5340 destroyActivityLocked(r, true);
5341 resumeTopActivityLocked(null);
5342 }
5343 }
5344 }
5345 }
5346
5347 if (r != null) {
5348 sendPendingThumbnail(r, null, null, null, false);
5349 }
5350
5351 trimApplications();
5352
5353 Binder.restoreCallingIdentity(origId);
5354 }
5355
5356 public final void activityDestroyed(IBinder token) {
5357 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5358 synchronized (this) {
5359 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5360
Dianne Hackborn75b03852009-06-12 15:43:26 -07005361 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005362 if (index >= 0) {
5363 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5364 if (r.state == ActivityState.DESTROYING) {
5365 final long origId = Binder.clearCallingIdentity();
5366 removeActivityFromHistoryLocked(r);
5367 Binder.restoreCallingIdentity(origId);
5368 }
5369 }
5370 }
5371 }
5372
5373 public String getCallingPackage(IBinder token) {
5374 synchronized (this) {
5375 HistoryRecord r = getCallingRecordLocked(token);
5376 return r != null && r.app != null ? r.app.processName : null;
5377 }
5378 }
5379
5380 public ComponentName getCallingActivity(IBinder token) {
5381 synchronized (this) {
5382 HistoryRecord r = getCallingRecordLocked(token);
5383 return r != null ? r.intent.getComponent() : null;
5384 }
5385 }
5386
5387 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005388 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005389 if (index >= 0) {
5390 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5391 if (r != null) {
5392 return r.resultTo;
5393 }
5394 }
5395 return null;
5396 }
5397
5398 public ComponentName getActivityClassForToken(IBinder token) {
5399 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005400 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005401 if (index >= 0) {
5402 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5403 return r.intent.getComponent();
5404 }
5405 return null;
5406 }
5407 }
5408
5409 public String getPackageForToken(IBinder token) {
5410 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005411 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005412 if (index >= 0) {
5413 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5414 return r.packageName;
5415 }
5416 return null;
5417 }
5418 }
5419
5420 public IIntentSender getIntentSender(int type,
5421 String packageName, IBinder token, String resultWho,
5422 int requestCode, Intent intent, String resolvedType, int flags) {
5423 // Refuse possible leaked file descriptors
5424 if (intent != null && intent.hasFileDescriptors() == true) {
5425 throw new IllegalArgumentException("File descriptors passed in Intent");
5426 }
5427
5428 synchronized(this) {
5429 int callingUid = Binder.getCallingUid();
5430 try {
5431 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5432 Process.supportsProcesses()) {
5433 int uid = ActivityThread.getPackageManager()
5434 .getPackageUid(packageName);
5435 if (uid != Binder.getCallingUid()) {
5436 String msg = "Permission Denial: getIntentSender() from pid="
5437 + Binder.getCallingPid()
5438 + ", uid=" + Binder.getCallingUid()
5439 + ", (need uid=" + uid + ")"
5440 + " is not allowed to send as package " + packageName;
5441 Log.w(TAG, msg);
5442 throw new SecurityException(msg);
5443 }
5444 }
5445 } catch (RemoteException e) {
5446 throw new SecurityException(e);
5447 }
5448 HistoryRecord activity = null;
5449 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005450 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005451 if (index < 0) {
5452 return null;
5453 }
5454 activity = (HistoryRecord)mHistory.get(index);
5455 if (activity.finishing) {
5456 return null;
5457 }
5458 }
5459
5460 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5461 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5462 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5463 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5464 |PendingIntent.FLAG_UPDATE_CURRENT);
5465
5466 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5467 type, packageName, activity, resultWho,
5468 requestCode, intent, resolvedType, flags);
5469 WeakReference<PendingIntentRecord> ref;
5470 ref = mIntentSenderRecords.get(key);
5471 PendingIntentRecord rec = ref != null ? ref.get() : null;
5472 if (rec != null) {
5473 if (!cancelCurrent) {
5474 if (updateCurrent) {
5475 rec.key.requestIntent.replaceExtras(intent);
5476 }
5477 return rec;
5478 }
5479 rec.canceled = true;
5480 mIntentSenderRecords.remove(key);
5481 }
5482 if (noCreate) {
5483 return rec;
5484 }
5485 rec = new PendingIntentRecord(this, key, callingUid);
5486 mIntentSenderRecords.put(key, rec.ref);
5487 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5488 if (activity.pendingResults == null) {
5489 activity.pendingResults
5490 = new HashSet<WeakReference<PendingIntentRecord>>();
5491 }
5492 activity.pendingResults.add(rec.ref);
5493 }
5494 return rec;
5495 }
5496 }
5497
5498 public void cancelIntentSender(IIntentSender sender) {
5499 if (!(sender instanceof PendingIntentRecord)) {
5500 return;
5501 }
5502 synchronized(this) {
5503 PendingIntentRecord rec = (PendingIntentRecord)sender;
5504 try {
5505 int uid = ActivityThread.getPackageManager()
5506 .getPackageUid(rec.key.packageName);
5507 if (uid != Binder.getCallingUid()) {
5508 String msg = "Permission Denial: cancelIntentSender() from pid="
5509 + Binder.getCallingPid()
5510 + ", uid=" + Binder.getCallingUid()
5511 + " is not allowed to cancel packges "
5512 + rec.key.packageName;
5513 Log.w(TAG, msg);
5514 throw new SecurityException(msg);
5515 }
5516 } catch (RemoteException e) {
5517 throw new SecurityException(e);
5518 }
5519 cancelIntentSenderLocked(rec, true);
5520 }
5521 }
5522
5523 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5524 rec.canceled = true;
5525 mIntentSenderRecords.remove(rec.key);
5526 if (cleanActivity && rec.key.activity != null) {
5527 rec.key.activity.pendingResults.remove(rec.ref);
5528 }
5529 }
5530
5531 public String getPackageForIntentSender(IIntentSender pendingResult) {
5532 if (!(pendingResult instanceof PendingIntentRecord)) {
5533 return null;
5534 }
5535 synchronized(this) {
5536 try {
5537 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5538 return res.key.packageName;
5539 } catch (ClassCastException e) {
5540 }
5541 }
5542 return null;
5543 }
5544
5545 public void setProcessLimit(int max) {
5546 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5547 "setProcessLimit()");
5548 mProcessLimit = max;
5549 }
5550
5551 public int getProcessLimit() {
5552 return mProcessLimit;
5553 }
5554
5555 void foregroundTokenDied(ForegroundToken token) {
5556 synchronized (ActivityManagerService.this) {
5557 synchronized (mPidsSelfLocked) {
5558 ForegroundToken cur
5559 = mForegroundProcesses.get(token.pid);
5560 if (cur != token) {
5561 return;
5562 }
5563 mForegroundProcesses.remove(token.pid);
5564 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5565 if (pr == null) {
5566 return;
5567 }
5568 pr.forcingToForeground = null;
5569 pr.foregroundServices = false;
5570 }
5571 updateOomAdjLocked();
5572 }
5573 }
5574
5575 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5576 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5577 "setProcessForeground()");
5578 synchronized(this) {
5579 boolean changed = false;
5580
5581 synchronized (mPidsSelfLocked) {
5582 ProcessRecord pr = mPidsSelfLocked.get(pid);
5583 if (pr == null) {
5584 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5585 return;
5586 }
5587 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5588 if (oldToken != null) {
5589 oldToken.token.unlinkToDeath(oldToken, 0);
5590 mForegroundProcesses.remove(pid);
5591 pr.forcingToForeground = null;
5592 changed = true;
5593 }
5594 if (isForeground && token != null) {
5595 ForegroundToken newToken = new ForegroundToken() {
5596 public void binderDied() {
5597 foregroundTokenDied(this);
5598 }
5599 };
5600 newToken.pid = pid;
5601 newToken.token = token;
5602 try {
5603 token.linkToDeath(newToken, 0);
5604 mForegroundProcesses.put(pid, newToken);
5605 pr.forcingToForeground = token;
5606 changed = true;
5607 } catch (RemoteException e) {
5608 // If the process died while doing this, we will later
5609 // do the cleanup with the process death link.
5610 }
5611 }
5612 }
5613
5614 if (changed) {
5615 updateOomAdjLocked();
5616 }
5617 }
5618 }
5619
5620 // =========================================================
5621 // PERMISSIONS
5622 // =========================================================
5623
5624 static class PermissionController extends IPermissionController.Stub {
5625 ActivityManagerService mActivityManagerService;
5626 PermissionController(ActivityManagerService activityManagerService) {
5627 mActivityManagerService = activityManagerService;
5628 }
5629
5630 public boolean checkPermission(String permission, int pid, int uid) {
5631 return mActivityManagerService.checkPermission(permission, pid,
5632 uid) == PackageManager.PERMISSION_GRANTED;
5633 }
5634 }
5635
5636 /**
5637 * This can be called with or without the global lock held.
5638 */
5639 int checkComponentPermission(String permission, int pid, int uid,
5640 int reqUid) {
5641 // We might be performing an operation on behalf of an indirect binder
5642 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5643 // client identity accordingly before proceeding.
5644 Identity tlsIdentity = sCallerIdentity.get();
5645 if (tlsIdentity != null) {
5646 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5647 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5648 uid = tlsIdentity.uid;
5649 pid = tlsIdentity.pid;
5650 }
5651
5652 // Root, system server and our own process get to do everything.
5653 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5654 !Process.supportsProcesses()) {
5655 return PackageManager.PERMISSION_GRANTED;
5656 }
5657 // If the target requires a specific UID, always fail for others.
5658 if (reqUid >= 0 && uid != reqUid) {
5659 return PackageManager.PERMISSION_DENIED;
5660 }
5661 if (permission == null) {
5662 return PackageManager.PERMISSION_GRANTED;
5663 }
5664 try {
5665 return ActivityThread.getPackageManager()
5666 .checkUidPermission(permission, uid);
5667 } catch (RemoteException e) {
5668 // Should never happen, but if it does... deny!
5669 Log.e(TAG, "PackageManager is dead?!?", e);
5670 }
5671 return PackageManager.PERMISSION_DENIED;
5672 }
5673
5674 /**
5675 * As the only public entry point for permissions checking, this method
5676 * can enforce the semantic that requesting a check on a null global
5677 * permission is automatically denied. (Internally a null permission
5678 * string is used when calling {@link #checkComponentPermission} in cases
5679 * when only uid-based security is needed.)
5680 *
5681 * This can be called with or without the global lock held.
5682 */
5683 public int checkPermission(String permission, int pid, int uid) {
5684 if (permission == null) {
5685 return PackageManager.PERMISSION_DENIED;
5686 }
5687 return checkComponentPermission(permission, pid, uid, -1);
5688 }
5689
5690 /**
5691 * Binder IPC calls go through the public entry point.
5692 * This can be called with or without the global lock held.
5693 */
5694 int checkCallingPermission(String permission) {
5695 return checkPermission(permission,
5696 Binder.getCallingPid(),
5697 Binder.getCallingUid());
5698 }
5699
5700 /**
5701 * This can be called with or without the global lock held.
5702 */
5703 void enforceCallingPermission(String permission, String func) {
5704 if (checkCallingPermission(permission)
5705 == PackageManager.PERMISSION_GRANTED) {
5706 return;
5707 }
5708
5709 String msg = "Permission Denial: " + func + " from pid="
5710 + Binder.getCallingPid()
5711 + ", uid=" + Binder.getCallingUid()
5712 + " requires " + permission;
5713 Log.w(TAG, msg);
5714 throw new SecurityException(msg);
5715 }
5716
5717 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5718 ProviderInfo pi, int uid, int modeFlags) {
5719 try {
5720 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5721 if ((pi.readPermission != null) &&
5722 (pm.checkUidPermission(pi.readPermission, uid)
5723 != PackageManager.PERMISSION_GRANTED)) {
5724 return false;
5725 }
5726 }
5727 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5728 if ((pi.writePermission != null) &&
5729 (pm.checkUidPermission(pi.writePermission, uid)
5730 != PackageManager.PERMISSION_GRANTED)) {
5731 return false;
5732 }
5733 }
5734 return true;
5735 } catch (RemoteException e) {
5736 return false;
5737 }
5738 }
5739
5740 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5741 int modeFlags) {
5742 // Root gets to do everything.
5743 if (uid == 0 || !Process.supportsProcesses()) {
5744 return true;
5745 }
5746 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5747 if (perms == null) return false;
5748 UriPermission perm = perms.get(uri);
5749 if (perm == null) return false;
5750 return (modeFlags&perm.modeFlags) == modeFlags;
5751 }
5752
5753 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5754 // Another redirected-binder-call permissions check as in
5755 // {@link checkComponentPermission}.
5756 Identity tlsIdentity = sCallerIdentity.get();
5757 if (tlsIdentity != null) {
5758 uid = tlsIdentity.uid;
5759 pid = tlsIdentity.pid;
5760 }
5761
5762 // Our own process gets to do everything.
5763 if (pid == MY_PID) {
5764 return PackageManager.PERMISSION_GRANTED;
5765 }
5766 synchronized(this) {
5767 return checkUriPermissionLocked(uri, uid, modeFlags)
5768 ? PackageManager.PERMISSION_GRANTED
5769 : PackageManager.PERMISSION_DENIED;
5770 }
5771 }
5772
5773 private void grantUriPermissionLocked(int callingUid,
5774 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5775 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5776 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5777 if (modeFlags == 0) {
5778 return;
5779 }
5780
5781 final IPackageManager pm = ActivityThread.getPackageManager();
5782
5783 // If this is not a content: uri, we can't do anything with it.
5784 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5785 return;
5786 }
5787
5788 String name = uri.getAuthority();
5789 ProviderInfo pi = null;
5790 ContentProviderRecord cpr
5791 = (ContentProviderRecord)mProvidersByName.get(name);
5792 if (cpr != null) {
5793 pi = cpr.info;
5794 } else {
5795 try {
5796 pi = pm.resolveContentProvider(name,
5797 PackageManager.GET_URI_PERMISSION_PATTERNS);
5798 } catch (RemoteException ex) {
5799 }
5800 }
5801 if (pi == null) {
5802 Log.w(TAG, "No content provider found for: " + name);
5803 return;
5804 }
5805
5806 int targetUid;
5807 try {
5808 targetUid = pm.getPackageUid(targetPkg);
5809 if (targetUid < 0) {
5810 return;
5811 }
5812 } catch (RemoteException ex) {
5813 return;
5814 }
5815
5816 // First... does the target actually need this permission?
5817 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5818 // No need to grant the target this permission.
5819 return;
5820 }
5821
5822 // Second... maybe someone else has already granted the
5823 // permission?
5824 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5825 // No need to grant the target this permission.
5826 return;
5827 }
5828
5829 // Third... is the provider allowing granting of URI permissions?
5830 if (!pi.grantUriPermissions) {
5831 throw new SecurityException("Provider " + pi.packageName
5832 + "/" + pi.name
5833 + " does not allow granting of Uri permissions (uri "
5834 + uri + ")");
5835 }
5836 if (pi.uriPermissionPatterns != null) {
5837 final int N = pi.uriPermissionPatterns.length;
5838 boolean allowed = false;
5839 for (int i=0; i<N; i++) {
5840 if (pi.uriPermissionPatterns[i] != null
5841 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5842 allowed = true;
5843 break;
5844 }
5845 }
5846 if (!allowed) {
5847 throw new SecurityException("Provider " + pi.packageName
5848 + "/" + pi.name
5849 + " does not allow granting of permission to path of Uri "
5850 + uri);
5851 }
5852 }
5853
5854 // Fourth... does the caller itself have permission to access
5855 // this uri?
5856 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5857 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5858 throw new SecurityException("Uid " + callingUid
5859 + " does not have permission to uri " + uri);
5860 }
5861 }
5862
5863 // Okay! So here we are: the caller has the assumed permission
5864 // to the uri, and the target doesn't. Let's now give this to
5865 // the target.
5866
5867 HashMap<Uri, UriPermission> targetUris
5868 = mGrantedUriPermissions.get(targetUid);
5869 if (targetUris == null) {
5870 targetUris = new HashMap<Uri, UriPermission>();
5871 mGrantedUriPermissions.put(targetUid, targetUris);
5872 }
5873
5874 UriPermission perm = targetUris.get(uri);
5875 if (perm == null) {
5876 perm = new UriPermission(targetUid, uri);
5877 targetUris.put(uri, perm);
5878
5879 }
5880 perm.modeFlags |= modeFlags;
5881 if (activity == null) {
5882 perm.globalModeFlags |= modeFlags;
5883 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5884 perm.readActivities.add(activity);
5885 if (activity.readUriPermissions == null) {
5886 activity.readUriPermissions = new HashSet<UriPermission>();
5887 }
5888 activity.readUriPermissions.add(perm);
5889 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5890 perm.writeActivities.add(activity);
5891 if (activity.writeUriPermissions == null) {
5892 activity.writeUriPermissions = new HashSet<UriPermission>();
5893 }
5894 activity.writeUriPermissions.add(perm);
5895 }
5896 }
5897
5898 private void grantUriPermissionFromIntentLocked(int callingUid,
5899 String targetPkg, Intent intent, HistoryRecord activity) {
5900 if (intent == null) {
5901 return;
5902 }
5903 Uri data = intent.getData();
5904 if (data == null) {
5905 return;
5906 }
5907 grantUriPermissionLocked(callingUid, targetPkg, data,
5908 intent.getFlags(), activity);
5909 }
5910
5911 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5912 Uri uri, int modeFlags) {
5913 synchronized(this) {
5914 final ProcessRecord r = getRecordForAppLocked(caller);
5915 if (r == null) {
5916 throw new SecurityException("Unable to find app for caller "
5917 + caller
5918 + " when granting permission to uri " + uri);
5919 }
5920 if (targetPkg == null) {
5921 Log.w(TAG, "grantUriPermission: null target");
5922 return;
5923 }
5924 if (uri == null) {
5925 Log.w(TAG, "grantUriPermission: null uri");
5926 return;
5927 }
5928
5929 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5930 null);
5931 }
5932 }
5933
5934 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5935 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5936 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5937 HashMap<Uri, UriPermission> perms
5938 = mGrantedUriPermissions.get(perm.uid);
5939 if (perms != null) {
5940 perms.remove(perm.uri);
5941 if (perms.size() == 0) {
5942 mGrantedUriPermissions.remove(perm.uid);
5943 }
5944 }
5945 }
5946 }
5947
5948 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5949 if (activity.readUriPermissions != null) {
5950 for (UriPermission perm : activity.readUriPermissions) {
5951 perm.readActivities.remove(activity);
5952 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5953 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5954 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5955 removeUriPermissionIfNeededLocked(perm);
5956 }
5957 }
5958 }
5959 if (activity.writeUriPermissions != null) {
5960 for (UriPermission perm : activity.writeUriPermissions) {
5961 perm.writeActivities.remove(activity);
5962 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5963 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5964 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5965 removeUriPermissionIfNeededLocked(perm);
5966 }
5967 }
5968 }
5969 }
5970
5971 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5972 int modeFlags) {
5973 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5974 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5975 if (modeFlags == 0) {
5976 return;
5977 }
5978
5979 final IPackageManager pm = ActivityThread.getPackageManager();
5980
5981 final String authority = uri.getAuthority();
5982 ProviderInfo pi = null;
5983 ContentProviderRecord cpr
5984 = (ContentProviderRecord)mProvidersByName.get(authority);
5985 if (cpr != null) {
5986 pi = cpr.info;
5987 } else {
5988 try {
5989 pi = pm.resolveContentProvider(authority,
5990 PackageManager.GET_URI_PERMISSION_PATTERNS);
5991 } catch (RemoteException ex) {
5992 }
5993 }
5994 if (pi == null) {
5995 Log.w(TAG, "No content provider found for: " + authority);
5996 return;
5997 }
5998
5999 // Does the caller have this permission on the URI?
6000 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6001 // Right now, if you are not the original owner of the permission,
6002 // you are not allowed to revoke it.
6003 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6004 throw new SecurityException("Uid " + callingUid
6005 + " does not have permission to uri " + uri);
6006 //}
6007 }
6008
6009 // Go through all of the permissions and remove any that match.
6010 final List<String> SEGMENTS = uri.getPathSegments();
6011 if (SEGMENTS != null) {
6012 final int NS = SEGMENTS.size();
6013 int N = mGrantedUriPermissions.size();
6014 for (int i=0; i<N; i++) {
6015 HashMap<Uri, UriPermission> perms
6016 = mGrantedUriPermissions.valueAt(i);
6017 Iterator<UriPermission> it = perms.values().iterator();
6018 toploop:
6019 while (it.hasNext()) {
6020 UriPermission perm = it.next();
6021 Uri targetUri = perm.uri;
6022 if (!authority.equals(targetUri.getAuthority())) {
6023 continue;
6024 }
6025 List<String> targetSegments = targetUri.getPathSegments();
6026 if (targetSegments == null) {
6027 continue;
6028 }
6029 if (targetSegments.size() < NS) {
6030 continue;
6031 }
6032 for (int j=0; j<NS; j++) {
6033 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6034 continue toploop;
6035 }
6036 }
6037 perm.clearModes(modeFlags);
6038 if (perm.modeFlags == 0) {
6039 it.remove();
6040 }
6041 }
6042 if (perms.size() == 0) {
6043 mGrantedUriPermissions.remove(
6044 mGrantedUriPermissions.keyAt(i));
6045 N--;
6046 i--;
6047 }
6048 }
6049 }
6050 }
6051
6052 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6053 int modeFlags) {
6054 synchronized(this) {
6055 final ProcessRecord r = getRecordForAppLocked(caller);
6056 if (r == null) {
6057 throw new SecurityException("Unable to find app for caller "
6058 + caller
6059 + " when revoking permission to uri " + uri);
6060 }
6061 if (uri == null) {
6062 Log.w(TAG, "revokeUriPermission: null uri");
6063 return;
6064 }
6065
6066 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6067 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6068 if (modeFlags == 0) {
6069 return;
6070 }
6071
6072 final IPackageManager pm = ActivityThread.getPackageManager();
6073
6074 final String authority = uri.getAuthority();
6075 ProviderInfo pi = null;
6076 ContentProviderRecord cpr
6077 = (ContentProviderRecord)mProvidersByName.get(authority);
6078 if (cpr != null) {
6079 pi = cpr.info;
6080 } else {
6081 try {
6082 pi = pm.resolveContentProvider(authority,
6083 PackageManager.GET_URI_PERMISSION_PATTERNS);
6084 } catch (RemoteException ex) {
6085 }
6086 }
6087 if (pi == null) {
6088 Log.w(TAG, "No content provider found for: " + authority);
6089 return;
6090 }
6091
6092 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6093 }
6094 }
6095
6096 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6097 synchronized (this) {
6098 ProcessRecord app =
6099 who != null ? getRecordForAppLocked(who) : null;
6100 if (app == null) return;
6101
6102 Message msg = Message.obtain();
6103 msg.what = WAIT_FOR_DEBUGGER_MSG;
6104 msg.obj = app;
6105 msg.arg1 = waiting ? 1 : 0;
6106 mHandler.sendMessage(msg);
6107 }
6108 }
6109
6110 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6111 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006112 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006113 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006114 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006115 }
6116
6117 // =========================================================
6118 // TASK MANAGEMENT
6119 // =========================================================
6120
6121 public List getTasks(int maxNum, int flags,
6122 IThumbnailReceiver receiver) {
6123 ArrayList list = new ArrayList();
6124
6125 PendingThumbnailsRecord pending = null;
6126 IApplicationThread topThumbnail = null;
6127 HistoryRecord topRecord = null;
6128
6129 synchronized(this) {
6130 if (localLOGV) Log.v(
6131 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6132 + ", receiver=" + receiver);
6133
6134 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6135 != PackageManager.PERMISSION_GRANTED) {
6136 if (receiver != null) {
6137 // If the caller wants to wait for pending thumbnails,
6138 // it ain't gonna get them.
6139 try {
6140 receiver.finished();
6141 } catch (RemoteException ex) {
6142 }
6143 }
6144 String msg = "Permission Denial: getTasks() from pid="
6145 + Binder.getCallingPid()
6146 + ", uid=" + Binder.getCallingUid()
6147 + " requires " + android.Manifest.permission.GET_TASKS;
6148 Log.w(TAG, msg);
6149 throw new SecurityException(msg);
6150 }
6151
6152 int pos = mHistory.size()-1;
6153 HistoryRecord next =
6154 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6155 HistoryRecord top = null;
6156 CharSequence topDescription = null;
6157 TaskRecord curTask = null;
6158 int numActivities = 0;
6159 int numRunning = 0;
6160 while (pos >= 0 && maxNum > 0) {
6161 final HistoryRecord r = next;
6162 pos--;
6163 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6164
6165 // Initialize state for next task if needed.
6166 if (top == null ||
6167 (top.state == ActivityState.INITIALIZING
6168 && top.task == r.task)) {
6169 top = r;
6170 topDescription = r.description;
6171 curTask = r.task;
6172 numActivities = numRunning = 0;
6173 }
6174
6175 // Add 'r' into the current task.
6176 numActivities++;
6177 if (r.app != null && r.app.thread != null) {
6178 numRunning++;
6179 }
6180 if (topDescription == null) {
6181 topDescription = r.description;
6182 }
6183
6184 if (localLOGV) Log.v(
6185 TAG, r.intent.getComponent().flattenToShortString()
6186 + ": task=" + r.task);
6187
6188 // If the next one is a different task, generate a new
6189 // TaskInfo entry for what we have.
6190 if (next == null || next.task != curTask) {
6191 ActivityManager.RunningTaskInfo ci
6192 = new ActivityManager.RunningTaskInfo();
6193 ci.id = curTask.taskId;
6194 ci.baseActivity = r.intent.getComponent();
6195 ci.topActivity = top.intent.getComponent();
6196 ci.thumbnail = top.thumbnail;
6197 ci.description = topDescription;
6198 ci.numActivities = numActivities;
6199 ci.numRunning = numRunning;
6200 //System.out.println(
6201 // "#" + maxNum + ": " + " descr=" + ci.description);
6202 if (ci.thumbnail == null && receiver != null) {
6203 if (localLOGV) Log.v(
6204 TAG, "State=" + top.state + "Idle=" + top.idle
6205 + " app=" + top.app
6206 + " thr=" + (top.app != null ? top.app.thread : null));
6207 if (top.state == ActivityState.RESUMED
6208 || top.state == ActivityState.PAUSING) {
6209 if (top.idle && top.app != null
6210 && top.app.thread != null) {
6211 topRecord = top;
6212 topThumbnail = top.app.thread;
6213 } else {
6214 top.thumbnailNeeded = true;
6215 }
6216 }
6217 if (pending == null) {
6218 pending = new PendingThumbnailsRecord(receiver);
6219 }
6220 pending.pendingRecords.add(top);
6221 }
6222 list.add(ci);
6223 maxNum--;
6224 top = null;
6225 }
6226 }
6227
6228 if (pending != null) {
6229 mPendingThumbnails.add(pending);
6230 }
6231 }
6232
6233 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6234
6235 if (topThumbnail != null) {
6236 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6237 try {
6238 topThumbnail.requestThumbnail(topRecord);
6239 } catch (Exception e) {
6240 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6241 sendPendingThumbnail(null, topRecord, null, null, true);
6242 }
6243 }
6244
6245 if (pending == null && receiver != null) {
6246 // In this case all thumbnails were available and the client
6247 // is being asked to be told when the remaining ones come in...
6248 // which is unusually, since the top-most currently running
6249 // activity should never have a canned thumbnail! Oh well.
6250 try {
6251 receiver.finished();
6252 } catch (RemoteException ex) {
6253 }
6254 }
6255
6256 return list;
6257 }
6258
6259 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6260 int flags) {
6261 synchronized (this) {
6262 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6263 "getRecentTasks()");
6264
6265 final int N = mRecentTasks.size();
6266 ArrayList<ActivityManager.RecentTaskInfo> res
6267 = new ArrayList<ActivityManager.RecentTaskInfo>(
6268 maxNum < N ? maxNum : N);
6269 for (int i=0; i<N && maxNum > 0; i++) {
6270 TaskRecord tr = mRecentTasks.get(i);
6271 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6272 || (tr.intent == null)
6273 || ((tr.intent.getFlags()
6274 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6275 ActivityManager.RecentTaskInfo rti
6276 = new ActivityManager.RecentTaskInfo();
6277 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6278 rti.baseIntent = new Intent(
6279 tr.intent != null ? tr.intent : tr.affinityIntent);
6280 rti.origActivity = tr.origActivity;
6281 res.add(rti);
6282 maxNum--;
6283 }
6284 }
6285 return res;
6286 }
6287 }
6288
6289 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6290 int j;
6291 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6292 TaskRecord jt = startTask;
6293
6294 // First look backwards
6295 for (j=startIndex-1; j>=0; j--) {
6296 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6297 if (r.task != jt) {
6298 jt = r.task;
6299 if (affinity.equals(jt.affinity)) {
6300 return j;
6301 }
6302 }
6303 }
6304
6305 // Now look forwards
6306 final int N = mHistory.size();
6307 jt = startTask;
6308 for (j=startIndex+1; j<N; j++) {
6309 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6310 if (r.task != jt) {
6311 if (affinity.equals(jt.affinity)) {
6312 return j;
6313 }
6314 jt = r.task;
6315 }
6316 }
6317
6318 // Might it be at the top?
6319 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6320 return N-1;
6321 }
6322
6323 return -1;
6324 }
6325
6326 /**
6327 * Perform a reset of the given task, if needed as part of launching it.
6328 * Returns the new HistoryRecord at the top of the task.
6329 */
6330 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6331 HistoryRecord newActivity) {
6332 boolean forceReset = (newActivity.info.flags
6333 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6334 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6335 if ((newActivity.info.flags
6336 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6337 forceReset = true;
6338 }
6339 }
6340
6341 final TaskRecord task = taskTop.task;
6342
6343 // We are going to move through the history list so that we can look
6344 // at each activity 'target' with 'below' either the interesting
6345 // activity immediately below it in the stack or null.
6346 HistoryRecord target = null;
6347 int targetI = 0;
6348 int taskTopI = -1;
6349 int replyChainEnd = -1;
6350 int lastReparentPos = -1;
6351 for (int i=mHistory.size()-1; i>=-1; i--) {
6352 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6353
6354 if (below != null && below.finishing) {
6355 continue;
6356 }
6357 if (target == null) {
6358 target = below;
6359 targetI = i;
6360 // If we were in the middle of a reply chain before this
6361 // task, it doesn't appear like the root of the chain wants
6362 // anything interesting, so drop it.
6363 replyChainEnd = -1;
6364 continue;
6365 }
6366
6367 final int flags = target.info.flags;
6368
6369 final boolean finishOnTaskLaunch =
6370 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6371 final boolean allowTaskReparenting =
6372 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6373
6374 if (target.task == task) {
6375 // We are inside of the task being reset... we'll either
6376 // finish this activity, push it out for another task,
6377 // or leave it as-is. We only do this
6378 // for activities that are not the root of the task (since
6379 // if we finish the root, we may no longer have the task!).
6380 if (taskTopI < 0) {
6381 taskTopI = targetI;
6382 }
6383 if (below != null && below.task == task) {
6384 final boolean clearWhenTaskReset =
6385 (target.intent.getFlags()
6386 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006387 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006388 // If this activity is sending a reply to a previous
6389 // activity, we can't do anything with it now until
6390 // we reach the start of the reply chain.
6391 // XXX note that we are assuming the result is always
6392 // to the previous activity, which is almost always
6393 // the case but we really shouldn't count on.
6394 if (replyChainEnd < 0) {
6395 replyChainEnd = targetI;
6396 }
Ed Heyl73798232009-03-24 21:32:21 -07006397 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006398 && target.taskAffinity != null
6399 && !target.taskAffinity.equals(task.affinity)) {
6400 // If this activity has an affinity for another
6401 // task, then we need to move it out of here. We will
6402 // move it as far out of the way as possible, to the
6403 // bottom of the activity stack. This also keeps it
6404 // correctly ordered with any activities we previously
6405 // moved.
6406 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6407 if (target.taskAffinity != null
6408 && target.taskAffinity.equals(p.task.affinity)) {
6409 // If the activity currently at the bottom has the
6410 // same task affinity as the one we are moving,
6411 // then merge it into the same task.
6412 target.task = p.task;
6413 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6414 + " out to bottom task " + p.task);
6415 } else {
6416 mCurTask++;
6417 if (mCurTask <= 0) {
6418 mCurTask = 1;
6419 }
6420 target.task = new TaskRecord(mCurTask, target.info, null,
6421 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6422 target.task.affinityIntent = target.intent;
6423 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6424 + " out to new task " + target.task);
6425 }
6426 mWindowManager.setAppGroupId(target, task.taskId);
6427 if (replyChainEnd < 0) {
6428 replyChainEnd = targetI;
6429 }
6430 int dstPos = 0;
6431 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6432 p = (HistoryRecord)mHistory.get(srcPos);
6433 if (p.finishing) {
6434 continue;
6435 }
6436 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6437 + " out to target's task " + target.task);
6438 task.numActivities--;
6439 p.task = target.task;
6440 target.task.numActivities++;
6441 mHistory.remove(srcPos);
6442 mHistory.add(dstPos, p);
6443 mWindowManager.moveAppToken(dstPos, p);
6444 mWindowManager.setAppGroupId(p, p.task.taskId);
6445 dstPos++;
6446 if (VALIDATE_TOKENS) {
6447 mWindowManager.validateAppTokens(mHistory);
6448 }
6449 i++;
6450 }
6451 if (taskTop == p) {
6452 taskTop = below;
6453 }
6454 if (taskTopI == replyChainEnd) {
6455 taskTopI = -1;
6456 }
6457 replyChainEnd = -1;
6458 addRecentTask(target.task);
6459 } else if (forceReset || finishOnTaskLaunch
6460 || clearWhenTaskReset) {
6461 // If the activity should just be removed -- either
6462 // because it asks for it, or the task should be
6463 // cleared -- then finish it and anything that is
6464 // part of its reply chain.
6465 if (clearWhenTaskReset) {
6466 // In this case, we want to finish this activity
6467 // and everything above it, so be sneaky and pretend
6468 // like these are all in the reply chain.
6469 replyChainEnd = targetI+1;
6470 while (replyChainEnd < mHistory.size() &&
6471 ((HistoryRecord)mHistory.get(
6472 replyChainEnd)).task == task) {
6473 replyChainEnd++;
6474 }
6475 replyChainEnd--;
6476 } else if (replyChainEnd < 0) {
6477 replyChainEnd = targetI;
6478 }
6479 HistoryRecord p = null;
6480 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6481 p = (HistoryRecord)mHistory.get(srcPos);
6482 if (p.finishing) {
6483 continue;
6484 }
6485 if (finishActivityLocked(p, srcPos,
6486 Activity.RESULT_CANCELED, null, "reset")) {
6487 replyChainEnd--;
6488 srcPos--;
6489 }
6490 }
6491 if (taskTop == p) {
6492 taskTop = below;
6493 }
6494 if (taskTopI == replyChainEnd) {
6495 taskTopI = -1;
6496 }
6497 replyChainEnd = -1;
6498 } else {
6499 // If we were in the middle of a chain, well the
6500 // activity that started it all doesn't want anything
6501 // special, so leave it all as-is.
6502 replyChainEnd = -1;
6503 }
6504 } else {
6505 // Reached the bottom of the task -- any reply chain
6506 // should be left as-is.
6507 replyChainEnd = -1;
6508 }
6509
6510 } else if (target.resultTo != null) {
6511 // If this activity is sending a reply to a previous
6512 // activity, we can't do anything with it now until
6513 // we reach the start of the reply chain.
6514 // XXX note that we are assuming the result is always
6515 // to the previous activity, which is almost always
6516 // the case but we really shouldn't count on.
6517 if (replyChainEnd < 0) {
6518 replyChainEnd = targetI;
6519 }
6520
6521 } else if (taskTopI >= 0 && allowTaskReparenting
6522 && task.affinity != null
6523 && task.affinity.equals(target.taskAffinity)) {
6524 // We are inside of another task... if this activity has
6525 // an affinity for our task, then either remove it if we are
6526 // clearing or move it over to our task. Note that
6527 // we currently punt on the case where we are resetting a
6528 // task that is not at the top but who has activities above
6529 // with an affinity to it... this is really not a normal
6530 // case, and we will need to later pull that task to the front
6531 // and usually at that point we will do the reset and pick
6532 // up those remaining activities. (This only happens if
6533 // someone starts an activity in a new task from an activity
6534 // in a task that is not currently on top.)
6535 if (forceReset || finishOnTaskLaunch) {
6536 if (replyChainEnd < 0) {
6537 replyChainEnd = targetI;
6538 }
6539 HistoryRecord p = null;
6540 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6541 p = (HistoryRecord)mHistory.get(srcPos);
6542 if (p.finishing) {
6543 continue;
6544 }
6545 if (finishActivityLocked(p, srcPos,
6546 Activity.RESULT_CANCELED, null, "reset")) {
6547 taskTopI--;
6548 lastReparentPos--;
6549 replyChainEnd--;
6550 srcPos--;
6551 }
6552 }
6553 replyChainEnd = -1;
6554 } else {
6555 if (replyChainEnd < 0) {
6556 replyChainEnd = targetI;
6557 }
6558 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6559 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6560 if (p.finishing) {
6561 continue;
6562 }
6563 if (lastReparentPos < 0) {
6564 lastReparentPos = taskTopI;
6565 taskTop = p;
6566 } else {
6567 lastReparentPos--;
6568 }
6569 mHistory.remove(srcPos);
6570 p.task.numActivities--;
6571 p.task = task;
6572 mHistory.add(lastReparentPos, p);
6573 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6574 + " in to resetting task " + task);
6575 task.numActivities++;
6576 mWindowManager.moveAppToken(lastReparentPos, p);
6577 mWindowManager.setAppGroupId(p, p.task.taskId);
6578 if (VALIDATE_TOKENS) {
6579 mWindowManager.validateAppTokens(mHistory);
6580 }
6581 }
6582 replyChainEnd = -1;
6583
6584 // Now we've moved it in to place... but what if this is
6585 // a singleTop activity and we have put it on top of another
6586 // instance of the same activity? Then we drop the instance
6587 // below so it remains singleTop.
6588 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6589 for (int j=lastReparentPos-1; j>=0; j--) {
6590 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6591 if (p.finishing) {
6592 continue;
6593 }
6594 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6595 if (finishActivityLocked(p, j,
6596 Activity.RESULT_CANCELED, null, "replace")) {
6597 taskTopI--;
6598 lastReparentPos--;
6599 }
6600 }
6601 }
6602 }
6603 }
6604 }
6605
6606 target = below;
6607 targetI = i;
6608 }
6609
6610 return taskTop;
6611 }
6612
6613 /**
6614 * TODO: Add mWatcher hook
6615 */
6616 public void moveTaskToFront(int task) {
6617 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6618 "moveTaskToFront()");
6619
6620 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006621 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6622 Binder.getCallingUid(), "Task to front")) {
6623 return;
6624 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006625 final long origId = Binder.clearCallingIdentity();
6626 try {
6627 int N = mRecentTasks.size();
6628 for (int i=0; i<N; i++) {
6629 TaskRecord tr = mRecentTasks.get(i);
6630 if (tr.taskId == task) {
6631 moveTaskToFrontLocked(tr);
6632 return;
6633 }
6634 }
6635 for (int i=mHistory.size()-1; i>=0; i--) {
6636 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6637 if (hr.task.taskId == task) {
6638 moveTaskToFrontLocked(hr.task);
6639 return;
6640 }
6641 }
6642 } finally {
6643 Binder.restoreCallingIdentity(origId);
6644 }
6645 }
6646 }
6647
6648 private final void moveTaskToFrontLocked(TaskRecord tr) {
6649 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6650
6651 final int task = tr.taskId;
6652 int top = mHistory.size()-1;
6653
6654 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6655 // nothing to do!
6656 return;
6657 }
6658
6659 if (DEBUG_TRANSITION) Log.v(TAG,
6660 "Prepare to front transition: task=" + tr);
6661 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6662
6663 ArrayList moved = new ArrayList();
6664
6665 // Applying the affinities may have removed entries from the history,
6666 // so get the size again.
6667 top = mHistory.size()-1;
6668 int pos = top;
6669
6670 // Shift all activities with this task up to the top
6671 // of the stack, keeping them in the same internal order.
6672 while (pos >= 0) {
6673 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6674 if (localLOGV) Log.v(
6675 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6676 boolean first = true;
6677 if (r.task.taskId == task) {
6678 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6679 mHistory.remove(pos);
6680 mHistory.add(top, r);
6681 moved.add(0, r);
6682 top--;
6683 if (first) {
6684 addRecentTask(r.task);
6685 first = false;
6686 }
6687 }
6688 pos--;
6689 }
6690
6691 mWindowManager.moveAppTokensToTop(moved);
6692 if (VALIDATE_TOKENS) {
6693 mWindowManager.validateAppTokens(mHistory);
6694 }
6695
6696 finishTaskMove(task);
6697 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6698 }
6699
6700 private final void finishTaskMove(int task) {
6701 resumeTopActivityLocked(null);
6702 }
6703
6704 public void moveTaskToBack(int task) {
6705 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6706 "moveTaskToBack()");
6707
6708 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006709 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6710 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6711 Binder.getCallingUid(), "Task to back")) {
6712 return;
6713 }
6714 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006715 final long origId = Binder.clearCallingIdentity();
6716 moveTaskToBackLocked(task);
6717 Binder.restoreCallingIdentity(origId);
6718 }
6719 }
6720
6721 /**
6722 * Moves an activity, and all of the other activities within the same task, to the bottom
6723 * of the history stack. The activity's order within the task is unchanged.
6724 *
6725 * @param token A reference to the activity we wish to move
6726 * @param nonRoot If false then this only works if the activity is the root
6727 * of a task; if true it will work for any activity in a task.
6728 * @return Returns true if the move completed, false if not.
6729 */
6730 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6731 synchronized(this) {
6732 final long origId = Binder.clearCallingIdentity();
6733 int taskId = getTaskForActivityLocked(token, !nonRoot);
6734 if (taskId >= 0) {
6735 return moveTaskToBackLocked(taskId);
6736 }
6737 Binder.restoreCallingIdentity(origId);
6738 }
6739 return false;
6740 }
6741
6742 /**
6743 * Worker method for rearranging history stack. Implements the function of moving all
6744 * activities for a specific task (gathering them if disjoint) into a single group at the
6745 * bottom of the stack.
6746 *
6747 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6748 * to premeptively cancel the move.
6749 *
6750 * @param task The taskId to collect and move to the bottom.
6751 * @return Returns true if the move completed, false if not.
6752 */
6753 private final boolean moveTaskToBackLocked(int task) {
6754 Log.i(TAG, "moveTaskToBack: " + task);
6755
6756 // If we have a watcher, preflight the move before committing to it. First check
6757 // for *other* available tasks, but if none are available, then try again allowing the
6758 // current task to be selected.
6759 if (mWatcher != null) {
6760 HistoryRecord next = topRunningActivityLocked(null, task);
6761 if (next == null) {
6762 next = topRunningActivityLocked(null, 0);
6763 }
6764 if (next != null) {
6765 // ask watcher if this is allowed
6766 boolean moveOK = true;
6767 try {
6768 moveOK = mWatcher.activityResuming(next.packageName);
6769 } catch (RemoteException e) {
6770 mWatcher = null;
6771 }
6772 if (!moveOK) {
6773 return false;
6774 }
6775 }
6776 }
6777
6778 ArrayList moved = new ArrayList();
6779
6780 if (DEBUG_TRANSITION) Log.v(TAG,
6781 "Prepare to back transition: task=" + task);
6782 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6783
6784 final int N = mHistory.size();
6785 int bottom = 0;
6786 int pos = 0;
6787
6788 // Shift all activities with this task down to the bottom
6789 // of the stack, keeping them in the same internal order.
6790 while (pos < N) {
6791 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6792 if (localLOGV) Log.v(
6793 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6794 if (r.task.taskId == task) {
6795 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6796 mHistory.remove(pos);
6797 mHistory.add(bottom, r);
6798 moved.add(r);
6799 bottom++;
6800 }
6801 pos++;
6802 }
6803
6804 mWindowManager.moveAppTokensToBottom(moved);
6805 if (VALIDATE_TOKENS) {
6806 mWindowManager.validateAppTokens(mHistory);
6807 }
6808
6809 finishTaskMove(task);
6810 return true;
6811 }
6812
6813 public void moveTaskBackwards(int task) {
6814 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6815 "moveTaskBackwards()");
6816
6817 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006818 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6819 Binder.getCallingUid(), "Task backwards")) {
6820 return;
6821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006822 final long origId = Binder.clearCallingIdentity();
6823 moveTaskBackwardsLocked(task);
6824 Binder.restoreCallingIdentity(origId);
6825 }
6826 }
6827
6828 private final void moveTaskBackwardsLocked(int task) {
6829 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6830 }
6831
6832 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6833 synchronized(this) {
6834 return getTaskForActivityLocked(token, onlyRoot);
6835 }
6836 }
6837
6838 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6839 final int N = mHistory.size();
6840 TaskRecord lastTask = null;
6841 for (int i=0; i<N; i++) {
6842 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6843 if (r == token) {
6844 if (!onlyRoot || lastTask != r.task) {
6845 return r.task.taskId;
6846 }
6847 return -1;
6848 }
6849 lastTask = r.task;
6850 }
6851
6852 return -1;
6853 }
6854
6855 /**
6856 * Returns the top activity in any existing task matching the given
6857 * Intent. Returns null if no such task is found.
6858 */
6859 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6860 ComponentName cls = intent.getComponent();
6861 if (info.targetActivity != null) {
6862 cls = new ComponentName(info.packageName, info.targetActivity);
6863 }
6864
6865 TaskRecord cp = null;
6866
6867 final int N = mHistory.size();
6868 for (int i=(N-1); i>=0; i--) {
6869 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6870 if (!r.finishing && r.task != cp
6871 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6872 cp = r.task;
6873 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6874 // + "/aff=" + r.task.affinity + " to new cls="
6875 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6876 if (r.task.affinity != null) {
6877 if (r.task.affinity.equals(info.taskAffinity)) {
6878 //Log.i(TAG, "Found matching affinity!");
6879 return r;
6880 }
6881 } else if (r.task.intent != null
6882 && r.task.intent.getComponent().equals(cls)) {
6883 //Log.i(TAG, "Found matching class!");
6884 //dump();
6885 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6886 return r;
6887 } else if (r.task.affinityIntent != null
6888 && r.task.affinityIntent.getComponent().equals(cls)) {
6889 //Log.i(TAG, "Found matching class!");
6890 //dump();
6891 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6892 return r;
6893 }
6894 }
6895 }
6896
6897 return null;
6898 }
6899
6900 /**
6901 * Returns the first activity (starting from the top of the stack) that
6902 * is the same as the given activity. Returns null if no such activity
6903 * is found.
6904 */
6905 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6906 ComponentName cls = intent.getComponent();
6907 if (info.targetActivity != null) {
6908 cls = new ComponentName(info.packageName, info.targetActivity);
6909 }
6910
6911 final int N = mHistory.size();
6912 for (int i=(N-1); i>=0; i--) {
6913 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6914 if (!r.finishing) {
6915 if (r.intent.getComponent().equals(cls)) {
6916 //Log.i(TAG, "Found matching class!");
6917 //dump();
6918 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6919 return r;
6920 }
6921 }
6922 }
6923
6924 return null;
6925 }
6926
6927 public void finishOtherInstances(IBinder token, ComponentName className) {
6928 synchronized(this) {
6929 final long origId = Binder.clearCallingIdentity();
6930
6931 int N = mHistory.size();
6932 TaskRecord lastTask = null;
6933 for (int i=0; i<N; i++) {
6934 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6935 if (r.realActivity.equals(className)
6936 && r != token && lastTask != r.task) {
6937 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6938 null, "others")) {
6939 i--;
6940 N--;
6941 }
6942 }
6943 lastTask = r.task;
6944 }
6945
6946 Binder.restoreCallingIdentity(origId);
6947 }
6948 }
6949
6950 // =========================================================
6951 // THUMBNAILS
6952 // =========================================================
6953
6954 public void reportThumbnail(IBinder token,
6955 Bitmap thumbnail, CharSequence description) {
6956 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6957 final long origId = Binder.clearCallingIdentity();
6958 sendPendingThumbnail(null, token, thumbnail, description, true);
6959 Binder.restoreCallingIdentity(origId);
6960 }
6961
6962 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6963 Bitmap thumbnail, CharSequence description, boolean always) {
6964 TaskRecord task = null;
6965 ArrayList receivers = null;
6966
6967 //System.out.println("Send pending thumbnail: " + r);
6968
6969 synchronized(this) {
6970 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006971 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006972 if (index < 0) {
6973 return;
6974 }
6975 r = (HistoryRecord)mHistory.get(index);
6976 }
6977 if (thumbnail == null) {
6978 thumbnail = r.thumbnail;
6979 description = r.description;
6980 }
6981 if (thumbnail == null && !always) {
6982 // If there is no thumbnail, and this entry is not actually
6983 // going away, then abort for now and pick up the next
6984 // thumbnail we get.
6985 return;
6986 }
6987 task = r.task;
6988
6989 int N = mPendingThumbnails.size();
6990 int i=0;
6991 while (i<N) {
6992 PendingThumbnailsRecord pr =
6993 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6994 //System.out.println("Looking in " + pr.pendingRecords);
6995 if (pr.pendingRecords.remove(r)) {
6996 if (receivers == null) {
6997 receivers = new ArrayList();
6998 }
6999 receivers.add(pr);
7000 if (pr.pendingRecords.size() == 0) {
7001 pr.finished = true;
7002 mPendingThumbnails.remove(i);
7003 N--;
7004 continue;
7005 }
7006 }
7007 i++;
7008 }
7009 }
7010
7011 if (receivers != null) {
7012 final int N = receivers.size();
7013 for (int i=0; i<N; i++) {
7014 try {
7015 PendingThumbnailsRecord pr =
7016 (PendingThumbnailsRecord)receivers.get(i);
7017 pr.receiver.newThumbnail(
7018 task != null ? task.taskId : -1, thumbnail, description);
7019 if (pr.finished) {
7020 pr.receiver.finished();
7021 }
7022 } catch (Exception e) {
7023 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7024 }
7025 }
7026 }
7027 }
7028
7029 // =========================================================
7030 // CONTENT PROVIDERS
7031 // =========================================================
7032
7033 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7034 List providers = null;
7035 try {
7036 providers = ActivityThread.getPackageManager().
7037 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007038 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007039 } catch (RemoteException ex) {
7040 }
7041 if (providers != null) {
7042 final int N = providers.size();
7043 for (int i=0; i<N; i++) {
7044 ProviderInfo cpi =
7045 (ProviderInfo)providers.get(i);
7046 ContentProviderRecord cpr =
7047 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7048 if (cpr == null) {
7049 cpr = new ContentProviderRecord(cpi, app.info);
7050 mProvidersByClass.put(cpi.name, cpr);
7051 }
7052 app.pubProviders.put(cpi.name, cpr);
7053 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007054 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007055 }
7056 }
7057 return providers;
7058 }
7059
7060 private final String checkContentProviderPermissionLocked(
7061 ProviderInfo cpi, ProcessRecord r, int mode) {
7062 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7063 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7064 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7065 cpi.exported ? -1 : cpi.applicationInfo.uid)
7066 == PackageManager.PERMISSION_GRANTED
7067 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7068 return null;
7069 }
7070 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7071 cpi.exported ? -1 : cpi.applicationInfo.uid)
7072 == PackageManager.PERMISSION_GRANTED) {
7073 return null;
7074 }
7075 String msg = "Permission Denial: opening provider " + cpi.name
7076 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7077 + ", uid=" + callingUid + ") requires "
7078 + cpi.readPermission + " or " + cpi.writePermission;
7079 Log.w(TAG, msg);
7080 return msg;
7081 }
7082
7083 private final ContentProviderHolder getContentProviderImpl(
7084 IApplicationThread caller, String name) {
7085 ContentProviderRecord cpr;
7086 ProviderInfo cpi = null;
7087
7088 synchronized(this) {
7089 ProcessRecord r = null;
7090 if (caller != null) {
7091 r = getRecordForAppLocked(caller);
7092 if (r == null) {
7093 throw new SecurityException(
7094 "Unable to find app for caller " + caller
7095 + " (pid=" + Binder.getCallingPid()
7096 + ") when getting content provider " + name);
7097 }
7098 }
7099
7100 // First check if this content provider has been published...
7101 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7102 if (cpr != null) {
7103 cpi = cpr.info;
7104 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7105 return new ContentProviderHolder(cpi,
7106 cpi.readPermission != null
7107 ? cpi.readPermission : cpi.writePermission);
7108 }
7109
7110 if (r != null && cpr.canRunHere(r)) {
7111 // This provider has been published or is in the process
7112 // of being published... but it is also allowed to run
7113 // in the caller's process, so don't make a connection
7114 // and just let the caller instantiate its own instance.
7115 if (cpr.provider != null) {
7116 // don't give caller the provider object, it needs
7117 // to make its own.
7118 cpr = new ContentProviderRecord(cpr);
7119 }
7120 return cpr;
7121 }
7122
7123 final long origId = Binder.clearCallingIdentity();
7124
7125 // In this case the provider is a single instance, so we can
7126 // return it right away.
7127 if (r != null) {
7128 r.conProviders.add(cpr);
7129 cpr.clients.add(r);
7130 } else {
7131 cpr.externals++;
7132 }
7133
7134 if (cpr.app != null) {
7135 updateOomAdjLocked(cpr.app);
7136 }
7137
7138 Binder.restoreCallingIdentity(origId);
7139
7140 } else {
7141 try {
7142 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007143 resolveContentProvider(name,
7144 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007145 } catch (RemoteException ex) {
7146 }
7147 if (cpi == null) {
7148 return null;
7149 }
7150
7151 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7152 return new ContentProviderHolder(cpi,
7153 cpi.readPermission != null
7154 ? cpi.readPermission : cpi.writePermission);
7155 }
7156
7157 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7158 final boolean firstClass = cpr == null;
7159 if (firstClass) {
7160 try {
7161 ApplicationInfo ai =
7162 ActivityThread.getPackageManager().
7163 getApplicationInfo(
7164 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007165 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007166 if (ai == null) {
7167 Log.w(TAG, "No package info for content provider "
7168 + cpi.name);
7169 return null;
7170 }
7171 cpr = new ContentProviderRecord(cpi, ai);
7172 } catch (RemoteException ex) {
7173 // pm is in same process, this will never happen.
7174 }
7175 }
7176
7177 if (r != null && cpr.canRunHere(r)) {
7178 // If this is a multiprocess provider, then just return its
7179 // info and allow the caller to instantiate it. Only do
7180 // this if the provider is the same user as the caller's
7181 // process, or can run as root (so can be in any process).
7182 return cpr;
7183 }
7184
7185 if (false) {
7186 RuntimeException e = new RuntimeException("foo");
7187 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7188 // + " pruid " + ai.uid + "): " + cpi.className, e);
7189 }
7190
7191 // This is single process, and our app is now connecting to it.
7192 // See if we are already in the process of launching this
7193 // provider.
7194 final int N = mLaunchingProviders.size();
7195 int i;
7196 for (i=0; i<N; i++) {
7197 if (mLaunchingProviders.get(i) == cpr) {
7198 break;
7199 }
7200 if (false) {
7201 final ContentProviderRecord rec =
7202 (ContentProviderRecord)mLaunchingProviders.get(i);
7203 if (rec.info.name.equals(cpr.info.name)) {
7204 cpr = rec;
7205 break;
7206 }
7207 }
7208 }
7209
7210 // If the provider is not already being launched, then get it
7211 // started.
7212 if (i >= N) {
7213 final long origId = Binder.clearCallingIdentity();
7214 ProcessRecord proc = startProcessLocked(cpi.processName,
7215 cpr.appInfo, false, 0, "content provider",
7216 new ComponentName(cpi.applicationInfo.packageName,
7217 cpi.name));
7218 if (proc == null) {
7219 Log.w(TAG, "Unable to launch app "
7220 + cpi.applicationInfo.packageName + "/"
7221 + cpi.applicationInfo.uid + " for provider "
7222 + name + ": process is bad");
7223 return null;
7224 }
7225 cpr.launchingApp = proc;
7226 mLaunchingProviders.add(cpr);
7227 Binder.restoreCallingIdentity(origId);
7228 }
7229
7230 // Make sure the provider is published (the same provider class
7231 // may be published under multiple names).
7232 if (firstClass) {
7233 mProvidersByClass.put(cpi.name, cpr);
7234 }
7235 mProvidersByName.put(name, cpr);
7236
7237 if (r != null) {
7238 r.conProviders.add(cpr);
7239 cpr.clients.add(r);
7240 } else {
7241 cpr.externals++;
7242 }
7243 }
7244 }
7245
7246 // Wait for the provider to be published...
7247 synchronized (cpr) {
7248 while (cpr.provider == null) {
7249 if (cpr.launchingApp == null) {
7250 Log.w(TAG, "Unable to launch app "
7251 + cpi.applicationInfo.packageName + "/"
7252 + cpi.applicationInfo.uid + " for provider "
7253 + name + ": launching app became null");
7254 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7255 cpi.applicationInfo.packageName,
7256 cpi.applicationInfo.uid, name);
7257 return null;
7258 }
7259 try {
7260 cpr.wait();
7261 } catch (InterruptedException ex) {
7262 }
7263 }
7264 }
7265 return cpr;
7266 }
7267
7268 public final ContentProviderHolder getContentProvider(
7269 IApplicationThread caller, String name) {
7270 if (caller == null) {
7271 String msg = "null IApplicationThread when getting content provider "
7272 + name;
7273 Log.w(TAG, msg);
7274 throw new SecurityException(msg);
7275 }
7276
7277 return getContentProviderImpl(caller, name);
7278 }
7279
7280 private ContentProviderHolder getContentProviderExternal(String name) {
7281 return getContentProviderImpl(null, name);
7282 }
7283
7284 /**
7285 * Drop a content provider from a ProcessRecord's bookkeeping
7286 * @param cpr
7287 */
7288 public void removeContentProvider(IApplicationThread caller, String name) {
7289 synchronized (this) {
7290 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7291 if(cpr == null) {
7292 //remove from mProvidersByClass
7293 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7294 return;
7295 }
7296 final ProcessRecord r = getRecordForAppLocked(caller);
7297 if (r == null) {
7298 throw new SecurityException(
7299 "Unable to find app for caller " + caller +
7300 " when removing content provider " + name);
7301 }
7302 //update content provider record entry info
7303 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7304 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7305 r.info.processName+" from process "+localCpr.appInfo.processName);
7306 if(localCpr.appInfo.processName == r.info.processName) {
7307 //should not happen. taken care of as a local provider
7308 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7309 return;
7310 } else {
7311 localCpr.clients.remove(r);
7312 r.conProviders.remove(localCpr);
7313 }
7314 updateOomAdjLocked();
7315 }
7316 }
7317
7318 private void removeContentProviderExternal(String name) {
7319 synchronized (this) {
7320 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7321 if(cpr == null) {
7322 //remove from mProvidersByClass
7323 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7324 return;
7325 }
7326
7327 //update content provider record entry info
7328 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7329 localCpr.externals--;
7330 if (localCpr.externals < 0) {
7331 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7332 }
7333 updateOomAdjLocked();
7334 }
7335 }
7336
7337 public final void publishContentProviders(IApplicationThread caller,
7338 List<ContentProviderHolder> providers) {
7339 if (providers == null) {
7340 return;
7341 }
7342
7343 synchronized(this) {
7344 final ProcessRecord r = getRecordForAppLocked(caller);
7345 if (r == null) {
7346 throw new SecurityException(
7347 "Unable to find app for caller " + caller
7348 + " (pid=" + Binder.getCallingPid()
7349 + ") when publishing content providers");
7350 }
7351
7352 final long origId = Binder.clearCallingIdentity();
7353
7354 final int N = providers.size();
7355 for (int i=0; i<N; i++) {
7356 ContentProviderHolder src = providers.get(i);
7357 if (src == null || src.info == null || src.provider == null) {
7358 continue;
7359 }
7360 ContentProviderRecord dst =
7361 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7362 if (dst != null) {
7363 mProvidersByClass.put(dst.info.name, dst);
7364 String names[] = dst.info.authority.split(";");
7365 for (int j = 0; j < names.length; j++) {
7366 mProvidersByName.put(names[j], dst);
7367 }
7368
7369 int NL = mLaunchingProviders.size();
7370 int j;
7371 for (j=0; j<NL; j++) {
7372 if (mLaunchingProviders.get(j) == dst) {
7373 mLaunchingProviders.remove(j);
7374 j--;
7375 NL--;
7376 }
7377 }
7378 synchronized (dst) {
7379 dst.provider = src.provider;
7380 dst.app = r;
7381 dst.notifyAll();
7382 }
7383 updateOomAdjLocked(r);
7384 }
7385 }
7386
7387 Binder.restoreCallingIdentity(origId);
7388 }
7389 }
7390
7391 public static final void installSystemProviders() {
7392 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7393 List providers = mSelf.generateApplicationProvidersLocked(app);
7394 mSystemThread.installSystemProviders(providers);
7395 }
7396
7397 // =========================================================
7398 // GLOBAL MANAGEMENT
7399 // =========================================================
7400
7401 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7402 ApplicationInfo info, String customProcess) {
7403 String proc = customProcess != null ? customProcess : info.processName;
7404 BatteryStatsImpl.Uid.Proc ps = null;
7405 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7406 synchronized (stats) {
7407 ps = stats.getProcessStatsLocked(info.uid, proc);
7408 }
7409 return new ProcessRecord(ps, thread, info, proc);
7410 }
7411
7412 final ProcessRecord addAppLocked(ApplicationInfo info) {
7413 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7414
7415 if (app == null) {
7416 app = newProcessRecordLocked(null, info, null);
7417 mProcessNames.put(info.processName, info.uid, app);
7418 updateLRUListLocked(app, true);
7419 }
7420
7421 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7422 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7423 app.persistent = true;
7424 app.maxAdj = CORE_SERVER_ADJ;
7425 }
7426 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7427 mPersistentStartingProcesses.add(app);
7428 startProcessLocked(app, "added application", app.processName);
7429 }
7430
7431 return app;
7432 }
7433
7434 public void unhandledBack() {
7435 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7436 "unhandledBack()");
7437
7438 synchronized(this) {
7439 int count = mHistory.size();
7440 if (Config.LOGD) Log.d(
7441 TAG, "Performing unhandledBack(): stack size = " + count);
7442 if (count > 1) {
7443 final long origId = Binder.clearCallingIdentity();
7444 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7445 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7446 Binder.restoreCallingIdentity(origId);
7447 }
7448 }
7449 }
7450
7451 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7452 String name = uri.getAuthority();
7453 ContentProviderHolder cph = getContentProviderExternal(name);
7454 ParcelFileDescriptor pfd = null;
7455 if (cph != null) {
7456 // We record the binder invoker's uid in thread-local storage before
7457 // going to the content provider to open the file. Later, in the code
7458 // that handles all permissions checks, we look for this uid and use
7459 // that rather than the Activity Manager's own uid. The effect is that
7460 // we do the check against the caller's permissions even though it looks
7461 // to the content provider like the Activity Manager itself is making
7462 // the request.
7463 sCallerIdentity.set(new Identity(
7464 Binder.getCallingPid(), Binder.getCallingUid()));
7465 try {
7466 pfd = cph.provider.openFile(uri, "r");
7467 } catch (FileNotFoundException e) {
7468 // do nothing; pfd will be returned null
7469 } finally {
7470 // Ensure that whatever happens, we clean up the identity state
7471 sCallerIdentity.remove();
7472 }
7473
7474 // We've got the fd now, so we're done with the provider.
7475 removeContentProviderExternal(name);
7476 } else {
7477 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7478 }
7479 return pfd;
7480 }
7481
7482 public void goingToSleep() {
7483 synchronized(this) {
7484 mSleeping = true;
7485 mWindowManager.setEventDispatching(false);
7486
7487 if (mResumedActivity != null) {
7488 pauseIfSleepingLocked();
7489 } else {
7490 Log.w(TAG, "goingToSleep with no resumed activity!");
7491 }
7492 }
7493 }
7494
Dianne Hackborn55280a92009-05-07 15:53:46 -07007495 public boolean shutdown(int timeout) {
7496 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7497 != PackageManager.PERMISSION_GRANTED) {
7498 throw new SecurityException("Requires permission "
7499 + android.Manifest.permission.SHUTDOWN);
7500 }
7501
7502 boolean timedout = false;
7503
7504 synchronized(this) {
7505 mShuttingDown = true;
7506 mWindowManager.setEventDispatching(false);
7507
7508 if (mResumedActivity != null) {
7509 pauseIfSleepingLocked();
7510 final long endTime = System.currentTimeMillis() + timeout;
7511 while (mResumedActivity != null || mPausingActivity != null) {
7512 long delay = endTime - System.currentTimeMillis();
7513 if (delay <= 0) {
7514 Log.w(TAG, "Activity manager shutdown timed out");
7515 timedout = true;
7516 break;
7517 }
7518 try {
7519 this.wait();
7520 } catch (InterruptedException e) {
7521 }
7522 }
7523 }
7524 }
7525
7526 mUsageStatsService.shutdown();
7527 mBatteryStatsService.shutdown();
7528
7529 return timedout;
7530 }
7531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007532 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007533 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007534 if (!mGoingToSleep.isHeld()) {
7535 mGoingToSleep.acquire();
7536 if (mLaunchingActivity.isHeld()) {
7537 mLaunchingActivity.release();
7538 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7539 }
7540 }
7541
7542 // If we are not currently pausing an activity, get the current
7543 // one to pause. If we are pausing one, we will just let that stuff
7544 // run and release the wake lock when all done.
7545 if (mPausingActivity == null) {
7546 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7547 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7548 startPausingLocked(false, true);
7549 }
7550 }
7551 }
7552
7553 public void wakingUp() {
7554 synchronized(this) {
7555 if (mGoingToSleep.isHeld()) {
7556 mGoingToSleep.release();
7557 }
7558 mWindowManager.setEventDispatching(true);
7559 mSleeping = false;
7560 resumeTopActivityLocked(null);
7561 }
7562 }
7563
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007564 public void stopAppSwitches() {
7565 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7566 != PackageManager.PERMISSION_GRANTED) {
7567 throw new SecurityException("Requires permission "
7568 + android.Manifest.permission.STOP_APP_SWITCHES);
7569 }
7570
7571 synchronized(this) {
7572 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7573 + APP_SWITCH_DELAY_TIME;
7574 mDidAppSwitch = false;
7575 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7576 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7577 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7578 }
7579 }
7580
7581 public void resumeAppSwitches() {
7582 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7583 != PackageManager.PERMISSION_GRANTED) {
7584 throw new SecurityException("Requires permission "
7585 + android.Manifest.permission.STOP_APP_SWITCHES);
7586 }
7587
7588 synchronized(this) {
7589 // Note that we don't execute any pending app switches... we will
7590 // let those wait until either the timeout, or the next start
7591 // activity request.
7592 mAppSwitchesAllowedTime = 0;
7593 }
7594 }
7595
7596 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7597 String name) {
7598 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7599 return true;
7600 }
7601
7602 final int perm = checkComponentPermission(
7603 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7604 callingUid, -1);
7605 if (perm == PackageManager.PERMISSION_GRANTED) {
7606 return true;
7607 }
7608
7609 Log.w(TAG, name + " request from " + callingUid + " stopped");
7610 return false;
7611 }
7612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007613 public void setDebugApp(String packageName, boolean waitForDebugger,
7614 boolean persistent) {
7615 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7616 "setDebugApp()");
7617
7618 // Note that this is not really thread safe if there are multiple
7619 // callers into it at the same time, but that's not a situation we
7620 // care about.
7621 if (persistent) {
7622 final ContentResolver resolver = mContext.getContentResolver();
7623 Settings.System.putString(
7624 resolver, Settings.System.DEBUG_APP,
7625 packageName);
7626 Settings.System.putInt(
7627 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7628 waitForDebugger ? 1 : 0);
7629 }
7630
7631 synchronized (this) {
7632 if (!persistent) {
7633 mOrigDebugApp = mDebugApp;
7634 mOrigWaitForDebugger = mWaitForDebugger;
7635 }
7636 mDebugApp = packageName;
7637 mWaitForDebugger = waitForDebugger;
7638 mDebugTransient = !persistent;
7639 if (packageName != null) {
7640 final long origId = Binder.clearCallingIdentity();
7641 uninstallPackageLocked(packageName, -1, false);
7642 Binder.restoreCallingIdentity(origId);
7643 }
7644 }
7645 }
7646
7647 public void setAlwaysFinish(boolean enabled) {
7648 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7649 "setAlwaysFinish()");
7650
7651 Settings.System.putInt(
7652 mContext.getContentResolver(),
7653 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7654
7655 synchronized (this) {
7656 mAlwaysFinishActivities = enabled;
7657 }
7658 }
7659
7660 public void setActivityWatcher(IActivityWatcher watcher) {
7661 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7662 "setActivityWatcher()");
7663 synchronized (this) {
7664 mWatcher = watcher;
7665 }
7666 }
7667
7668 public final void enterSafeMode() {
7669 synchronized(this) {
7670 // It only makes sense to do this before the system is ready
7671 // and started launching other packages.
7672 if (!mSystemReady) {
7673 try {
7674 ActivityThread.getPackageManager().enterSafeMode();
7675 } catch (RemoteException e) {
7676 }
7677
7678 View v = LayoutInflater.from(mContext).inflate(
7679 com.android.internal.R.layout.safe_mode, null);
7680 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7681 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7682 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7683 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7684 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7685 lp.format = v.getBackground().getOpacity();
7686 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7687 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7688 ((WindowManager)mContext.getSystemService(
7689 Context.WINDOW_SERVICE)).addView(v, lp);
7690 }
7691 }
7692 }
7693
7694 public void noteWakeupAlarm(IIntentSender sender) {
7695 if (!(sender instanceof PendingIntentRecord)) {
7696 return;
7697 }
7698 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7699 synchronized (stats) {
7700 if (mBatteryStatsService.isOnBattery()) {
7701 mBatteryStatsService.enforceCallingPermission();
7702 PendingIntentRecord rec = (PendingIntentRecord)sender;
7703 int MY_UID = Binder.getCallingUid();
7704 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7705 BatteryStatsImpl.Uid.Pkg pkg =
7706 stats.getPackageStatsLocked(uid, rec.key.packageName);
7707 pkg.incWakeupsLocked();
7708 }
7709 }
7710 }
7711
7712 public boolean killPidsForMemory(int[] pids) {
7713 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7714 throw new SecurityException("killPidsForMemory only available to the system");
7715 }
7716
7717 // XXX Note: don't acquire main activity lock here, because the window
7718 // manager calls in with its locks held.
7719
7720 boolean killed = false;
7721 synchronized (mPidsSelfLocked) {
7722 int[] types = new int[pids.length];
7723 int worstType = 0;
7724 for (int i=0; i<pids.length; i++) {
7725 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7726 if (proc != null) {
7727 int type = proc.setAdj;
7728 types[i] = type;
7729 if (type > worstType) {
7730 worstType = type;
7731 }
7732 }
7733 }
7734
7735 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7736 // then constrain it so we will kill all hidden procs.
7737 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7738 worstType = HIDDEN_APP_MIN_ADJ;
7739 }
7740 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7741 for (int i=0; i<pids.length; i++) {
7742 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7743 if (proc == null) {
7744 continue;
7745 }
7746 int adj = proc.setAdj;
7747 if (adj >= worstType) {
7748 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7749 + adj + ")");
7750 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7751 proc.processName, adj);
7752 killed = true;
7753 Process.killProcess(pids[i]);
7754 }
7755 }
7756 }
7757 return killed;
7758 }
7759
7760 public void reportPss(IApplicationThread caller, int pss) {
7761 Watchdog.PssRequestor req;
7762 String name;
7763 ProcessRecord callerApp;
7764 synchronized (this) {
7765 if (caller == null) {
7766 return;
7767 }
7768 callerApp = getRecordForAppLocked(caller);
7769 if (callerApp == null) {
7770 return;
7771 }
7772 callerApp.lastPss = pss;
7773 req = callerApp;
7774 name = callerApp.processName;
7775 }
7776 Watchdog.getInstance().reportPss(req, name, pss);
7777 if (!callerApp.persistent) {
7778 removeRequestedPss(callerApp);
7779 }
7780 }
7781
7782 public void requestPss(Runnable completeCallback) {
7783 ArrayList<ProcessRecord> procs;
7784 synchronized (this) {
7785 mRequestPssCallback = completeCallback;
7786 mRequestPssList.clear();
7787 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7788 ProcessRecord proc = mLRUProcesses.get(i);
7789 if (!proc.persistent) {
7790 mRequestPssList.add(proc);
7791 }
7792 }
7793 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7794 }
7795
7796 int oldPri = Process.getThreadPriority(Process.myTid());
7797 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7798 for (int i=procs.size()-1; i>=0; i--) {
7799 ProcessRecord proc = procs.get(i);
7800 proc.lastPss = 0;
7801 proc.requestPss();
7802 }
7803 Process.setThreadPriority(oldPri);
7804 }
7805
7806 void removeRequestedPss(ProcessRecord proc) {
7807 Runnable callback = null;
7808 synchronized (this) {
7809 if (mRequestPssList.remove(proc)) {
7810 if (mRequestPssList.size() == 0) {
7811 callback = mRequestPssCallback;
7812 mRequestPssCallback = null;
7813 }
7814 }
7815 }
7816
7817 if (callback != null) {
7818 callback.run();
7819 }
7820 }
7821
7822 public void collectPss(Watchdog.PssStats stats) {
7823 stats.mEmptyPss = 0;
7824 stats.mEmptyCount = 0;
7825 stats.mBackgroundPss = 0;
7826 stats.mBackgroundCount = 0;
7827 stats.mServicePss = 0;
7828 stats.mServiceCount = 0;
7829 stats.mVisiblePss = 0;
7830 stats.mVisibleCount = 0;
7831 stats.mForegroundPss = 0;
7832 stats.mForegroundCount = 0;
7833 stats.mNoPssCount = 0;
7834 synchronized (this) {
7835 int i;
7836 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7837 ? mProcDeaths.length : stats.mProcDeaths.length;
7838 int aggr = 0;
7839 for (i=0; i<NPD; i++) {
7840 aggr += mProcDeaths[i];
7841 stats.mProcDeaths[i] = aggr;
7842 }
7843 while (i<stats.mProcDeaths.length) {
7844 stats.mProcDeaths[i] = 0;
7845 i++;
7846 }
7847
7848 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7849 ProcessRecord proc = mLRUProcesses.get(i);
7850 if (proc.persistent) {
7851 continue;
7852 }
7853 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7854 if (proc.lastPss == 0) {
7855 stats.mNoPssCount++;
7856 continue;
7857 }
7858 if (proc.setAdj == EMPTY_APP_ADJ) {
7859 stats.mEmptyPss += proc.lastPss;
7860 stats.mEmptyCount++;
7861 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7862 stats.mEmptyPss += proc.lastPss;
7863 stats.mEmptyCount++;
7864 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7865 stats.mBackgroundPss += proc.lastPss;
7866 stats.mBackgroundCount++;
7867 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7868 stats.mVisiblePss += proc.lastPss;
7869 stats.mVisibleCount++;
7870 } else {
7871 stats.mForegroundPss += proc.lastPss;
7872 stats.mForegroundCount++;
7873 }
7874 }
7875 }
7876 }
7877
7878 public final void startRunning(String pkg, String cls, String action,
7879 String data) {
7880 synchronized(this) {
7881 if (mStartRunning) {
7882 return;
7883 }
7884 mStartRunning = true;
7885 mTopComponent = pkg != null && cls != null
7886 ? new ComponentName(pkg, cls) : null;
7887 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7888 mTopData = data;
7889 if (!mSystemReady) {
7890 return;
7891 }
7892 }
7893
7894 systemReady();
7895 }
7896
7897 private void retrieveSettings() {
7898 final ContentResolver resolver = mContext.getContentResolver();
7899 String debugApp = Settings.System.getString(
7900 resolver, Settings.System.DEBUG_APP);
7901 boolean waitForDebugger = Settings.System.getInt(
7902 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7903 boolean alwaysFinishActivities = Settings.System.getInt(
7904 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7905
7906 Configuration configuration = new Configuration();
7907 Settings.System.getConfiguration(resolver, configuration);
7908
7909 synchronized (this) {
7910 mDebugApp = mOrigDebugApp = debugApp;
7911 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7912 mAlwaysFinishActivities = alwaysFinishActivities;
7913 // This happens before any activities are started, so we can
7914 // change mConfiguration in-place.
7915 mConfiguration.updateFrom(configuration);
7916 }
7917 }
7918
7919 public boolean testIsSystemReady() {
7920 // no need to synchronize(this) just to read & return the value
7921 return mSystemReady;
7922 }
7923
7924 public void systemReady() {
7925 // In the simulator, startRunning will never have been called, which
7926 // normally sets a few crucial variables. Do it here instead.
7927 if (!Process.supportsProcesses()) {
7928 mStartRunning = true;
7929 mTopAction = Intent.ACTION_MAIN;
7930 }
7931
7932 synchronized(this) {
7933 if (mSystemReady) {
7934 return;
7935 }
7936 mSystemReady = true;
7937 if (!mStartRunning) {
7938 return;
7939 }
7940 }
7941
7942 if (Config.LOGD) Log.d(TAG, "Start running!");
7943 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7944 SystemClock.uptimeMillis());
7945
7946 synchronized(this) {
7947 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7948 ResolveInfo ri = mContext.getPackageManager()
7949 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007950 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007951 CharSequence errorMsg = null;
7952 if (ri != null) {
7953 ActivityInfo ai = ri.activityInfo;
7954 ApplicationInfo app = ai.applicationInfo;
7955 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7956 mTopAction = Intent.ACTION_FACTORY_TEST;
7957 mTopData = null;
7958 mTopComponent = new ComponentName(app.packageName,
7959 ai.name);
7960 } else {
7961 errorMsg = mContext.getResources().getText(
7962 com.android.internal.R.string.factorytest_not_system);
7963 }
7964 } else {
7965 errorMsg = mContext.getResources().getText(
7966 com.android.internal.R.string.factorytest_no_action);
7967 }
7968 if (errorMsg != null) {
7969 mTopAction = null;
7970 mTopData = null;
7971 mTopComponent = null;
7972 Message msg = Message.obtain();
7973 msg.what = SHOW_FACTORY_ERROR_MSG;
7974 msg.getData().putCharSequence("msg", errorMsg);
7975 mHandler.sendMessage(msg);
7976 }
7977 }
7978 }
7979
7980 retrieveSettings();
7981
7982 synchronized (this) {
7983 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7984 try {
7985 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007986 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007987 if (apps != null) {
7988 int N = apps.size();
7989 int i;
7990 for (i=0; i<N; i++) {
7991 ApplicationInfo info
7992 = (ApplicationInfo)apps.get(i);
7993 if (info != null &&
7994 !info.packageName.equals("android")) {
7995 addAppLocked(info);
7996 }
7997 }
7998 }
7999 } catch (RemoteException ex) {
8000 // pm is in same process, this will never happen.
8001 }
8002 }
8003
8004 try {
8005 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8006 Message msg = Message.obtain();
8007 msg.what = SHOW_UID_ERROR_MSG;
8008 mHandler.sendMessage(msg);
8009 }
8010 } catch (RemoteException e) {
8011 }
8012
8013 // Start up initial activity.
8014 mBooting = true;
8015 resumeTopActivityLocked(null);
8016 }
8017 }
8018
8019 boolean makeAppCrashingLocked(ProcessRecord app,
8020 String tag, String shortMsg, String longMsg, byte[] crashData) {
8021 app.crashing = true;
8022 app.crashingReport = generateProcessError(app,
8023 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8024 startAppProblemLocked(app);
8025 app.stopFreezingAllLocked();
8026 return handleAppCrashLocked(app);
8027 }
8028
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008029 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8030 IPackageManager pm = ActivityThread.getPackageManager();
8031 try {
8032 // was an installer package name specified when this app was
8033 // installed?
8034 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8035 if (installerPackageName == null) {
8036 return null;
8037 }
8038
8039 // is there an Activity in this package that handles ACTION_APP_ERROR?
8040 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008041 intent.setPackage(installerPackageName);
8042 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008043 if (info == null || info.activityInfo == null) {
8044 return null;
8045 }
8046
8047 return new ComponentName(installerPackageName, info.activityInfo.name);
8048 } catch (RemoteException e) {
8049 // will return null and no error report will be delivered
8050 }
8051 return null;
8052 }
8053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008054 void makeAppNotRespondingLocked(ProcessRecord app,
8055 String tag, String shortMsg, String longMsg, byte[] crashData) {
8056 app.notResponding = true;
8057 app.notRespondingReport = generateProcessError(app,
8058 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8059 crashData);
8060 startAppProblemLocked(app);
8061 app.stopFreezingAllLocked();
8062 }
8063
8064 /**
8065 * Generate a process error record, suitable for attachment to a ProcessRecord.
8066 *
8067 * @param app The ProcessRecord in which the error occurred.
8068 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8069 * ActivityManager.AppErrorStateInfo
8070 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8071 * @param shortMsg Short message describing the crash.
8072 * @param longMsg Long message describing the crash.
8073 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8074 *
8075 * @return Returns a fully-formed AppErrorStateInfo record.
8076 */
8077 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8078 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8079 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8080
8081 report.condition = condition;
8082 report.processName = app.processName;
8083 report.pid = app.pid;
8084 report.uid = app.info.uid;
8085 report.tag = tag;
8086 report.shortMsg = shortMsg;
8087 report.longMsg = longMsg;
8088 report.crashData = crashData;
8089
8090 return report;
8091 }
8092
8093 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8094 boolean crashed) {
8095 synchronized (this) {
8096 app.crashing = false;
8097 app.crashingReport = null;
8098 app.notResponding = false;
8099 app.notRespondingReport = null;
8100 if (app.anrDialog == fromDialog) {
8101 app.anrDialog = null;
8102 }
8103 if (app.waitDialog == fromDialog) {
8104 app.waitDialog = null;
8105 }
8106 if (app.pid > 0 && app.pid != MY_PID) {
8107 if (crashed) {
8108 handleAppCrashLocked(app);
8109 }
8110 Log.i(ActivityManagerService.TAG, "Killing process "
8111 + app.processName
8112 + " (pid=" + app.pid + ") at user's request");
8113 Process.killProcess(app.pid);
8114 }
8115
8116 }
8117 }
8118
8119 boolean handleAppCrashLocked(ProcessRecord app) {
8120 long now = SystemClock.uptimeMillis();
8121
8122 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8123 app.info.uid);
8124 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8125 // This process loses!
8126 Log.w(TAG, "Process " + app.info.processName
8127 + " has crashed too many times: killing!");
8128 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8129 app.info.processName, app.info.uid);
8130 killServicesLocked(app, false);
8131 for (int i=mHistory.size()-1; i>=0; i--) {
8132 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8133 if (r.app == app) {
8134 if (Config.LOGD) Log.d(
8135 TAG, " Force finishing activity "
8136 + r.intent.getComponent().flattenToShortString());
8137 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8138 }
8139 }
8140 if (!app.persistent) {
8141 // We don't want to start this process again until the user
8142 // explicitly does so... but for persistent process, we really
8143 // need to keep it running. If a persistent process is actually
8144 // repeatedly crashing, then badness for everyone.
8145 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8146 app.info.processName);
8147 mBadProcesses.put(app.info.processName, app.info.uid, now);
8148 app.bad = true;
8149 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8150 app.removed = true;
8151 removeProcessLocked(app, false);
8152 return false;
8153 }
8154 }
8155
8156 // Bump up the crash count of any services currently running in the proc.
8157 if (app.services.size() != 0) {
8158 // Any services running in the application need to be placed
8159 // back in the pending list.
8160 Iterator it = app.services.iterator();
8161 while (it.hasNext()) {
8162 ServiceRecord sr = (ServiceRecord)it.next();
8163 sr.crashCount++;
8164 }
8165 }
8166
8167 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8168 return true;
8169 }
8170
8171 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008172 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008173 skipCurrentReceiverLocked(app);
8174 }
8175
8176 void skipCurrentReceiverLocked(ProcessRecord app) {
8177 boolean reschedule = false;
8178 BroadcastRecord r = app.curReceiver;
8179 if (r != null) {
8180 // The current broadcast is waiting for this app's receiver
8181 // to be finished. Looks like that's not going to happen, so
8182 // let the broadcast continue.
8183 logBroadcastReceiverDiscard(r);
8184 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8185 r.resultExtras, r.resultAbort, true);
8186 reschedule = true;
8187 }
8188 r = mPendingBroadcast;
8189 if (r != null && r.curApp == app) {
8190 if (DEBUG_BROADCAST) Log.v(TAG,
8191 "skip & discard pending app " + r);
8192 logBroadcastReceiverDiscard(r);
8193 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8194 r.resultExtras, r.resultAbort, true);
8195 reschedule = true;
8196 }
8197 if (reschedule) {
8198 scheduleBroadcastsLocked();
8199 }
8200 }
8201
8202 public int handleApplicationError(IBinder app, int flags,
8203 String tag, String shortMsg, String longMsg, byte[] crashData) {
8204 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008205 ProcessRecord r = null;
8206 synchronized (this) {
8207 if (app != null) {
8208 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8209 final int NA = apps.size();
8210 for (int ia=0; ia<NA; ia++) {
8211 ProcessRecord p = apps.valueAt(ia);
8212 if (p.thread != null && p.thread.asBinder() == app) {
8213 r = p;
8214 break;
8215 }
8216 }
8217 }
8218 }
8219
8220 if (r != null) {
8221 // The application has crashed. Send the SIGQUIT to the process so
8222 // that it can dump its state.
8223 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8224 //Log.i(TAG, "Current system threads:");
8225 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8226 }
8227
8228 if (mWatcher != null) {
8229 try {
8230 String name = r != null ? r.processName : null;
8231 int pid = r != null ? r.pid : Binder.getCallingPid();
8232 if (!mWatcher.appCrashed(name, pid,
8233 shortMsg, longMsg, crashData)) {
8234 Log.w(TAG, "Force-killing crashed app " + name
8235 + " at watcher's request");
8236 Process.killProcess(pid);
8237 return 0;
8238 }
8239 } catch (RemoteException e) {
8240 mWatcher = null;
8241 }
8242 }
8243
8244 final long origId = Binder.clearCallingIdentity();
8245
8246 // If this process is running instrumentation, finish it.
8247 if (r != null && r.instrumentationClass != null) {
8248 Log.w(TAG, "Error in app " + r.processName
8249 + " running instrumentation " + r.instrumentationClass + ":");
8250 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8251 if (longMsg != null) Log.w(TAG, " " + longMsg);
8252 Bundle info = new Bundle();
8253 info.putString("shortMsg", shortMsg);
8254 info.putString("longMsg", longMsg);
8255 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8256 Binder.restoreCallingIdentity(origId);
8257 return 0;
8258 }
8259
8260 if (r != null) {
8261 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8262 return 0;
8263 }
8264 } else {
8265 Log.w(TAG, "Some application object " + app + " tag " + tag
8266 + " has crashed, but I don't know who it is.");
8267 Log.w(TAG, "ShortMsg:" + shortMsg);
8268 Log.w(TAG, "LongMsg:" + longMsg);
8269 Binder.restoreCallingIdentity(origId);
8270 return 0;
8271 }
8272
8273 Message msg = Message.obtain();
8274 msg.what = SHOW_ERROR_MSG;
8275 HashMap data = new HashMap();
8276 data.put("result", result);
8277 data.put("app", r);
8278 data.put("flags", flags);
8279 data.put("shortMsg", shortMsg);
8280 data.put("longMsg", longMsg);
8281 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8282 // For system processes, submit crash data to the server.
8283 data.put("crashData", crashData);
8284 }
8285 msg.obj = data;
8286 mHandler.sendMessage(msg);
8287
8288 Binder.restoreCallingIdentity(origId);
8289 }
8290
8291 int res = result.get();
8292
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008293 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008294 synchronized (this) {
8295 if (r != null) {
8296 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8297 SystemClock.uptimeMillis());
8298 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008299 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8300 appErrorIntent = createAppErrorIntentLocked(r);
8301 res = AppErrorDialog.FORCE_QUIT;
8302 }
8303 }
8304
8305 if (appErrorIntent != null) {
8306 try {
8307 mContext.startActivity(appErrorIntent);
8308 } catch (ActivityNotFoundException e) {
8309 Log.w(TAG, "bug report receiver dissappeared", e);
8310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008311 }
8312
8313 return res;
8314 }
8315
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008316 Intent createAppErrorIntentLocked(ProcessRecord r) {
8317 ApplicationErrorReport report = createAppErrorReportLocked(r);
8318 if (report == null) {
8319 return null;
8320 }
8321 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8322 result.setComponent(r.errorReportReceiver);
8323 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8324 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8325 return result;
8326 }
8327
8328 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8329 if (r.errorReportReceiver == null) {
8330 return null;
8331 }
8332
8333 if (!r.crashing && !r.notResponding) {
8334 return null;
8335 }
8336
8337 try {
8338 ApplicationErrorReport report = new ApplicationErrorReport();
8339 report.packageName = r.info.packageName;
8340 report.installerPackageName = r.errorReportReceiver.getPackageName();
8341 report.processName = r.processName;
8342
8343 if (r.crashing) {
8344 report.type = ApplicationErrorReport.TYPE_CRASH;
8345 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8346
8347 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8348 r.crashingReport.crashData);
8349 DataInputStream dataStream = new DataInputStream(byteStream);
8350 CrashData crashData = new CrashData(dataStream);
8351 ThrowableData throwData = crashData.getThrowableData();
8352
8353 report.time = crashData.getTime();
8354 report.crashInfo.stackTrace = throwData.toString();
8355
Jacek Surazskif829a782009-06-11 22:47:02 +02008356 // Extract the source of the exception, useful for report
8357 // clustering. Also extract the "deepest" non-null exception
8358 // message.
8359 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008360 while (throwData.getCause() != null) {
8361 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008362 String msg = throwData.getMessage();
8363 if (msg != null && msg.length() > 0) {
8364 exceptionMessage = msg;
8365 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008366 }
8367 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008368 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008369 report.crashInfo.exceptionClassName = throwData.getType();
8370 report.crashInfo.throwFileName = trace.getFileName();
8371 report.crashInfo.throwClassName = trace.getClassName();
8372 report.crashInfo.throwMethodName = trace.getMethodName();
8373 } else if (r.notResponding) {
8374 report.type = ApplicationErrorReport.TYPE_ANR;
8375 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8376
8377 report.anrInfo.activity = r.notRespondingReport.tag;
8378 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8379 report.anrInfo.info = r.notRespondingReport.longMsg;
8380 }
8381
8382 return report;
8383 } catch (IOException e) {
8384 // we don't send it
8385 }
8386
8387 return null;
8388 }
8389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008390 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8391 // assume our apps are happy - lazy create the list
8392 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8393
8394 synchronized (this) {
8395
8396 // iterate across all processes
8397 final int N = mLRUProcesses.size();
8398 for (int i = 0; i < N; i++) {
8399 ProcessRecord app = mLRUProcesses.get(i);
8400 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8401 // This one's in trouble, so we'll generate a report for it
8402 // crashes are higher priority (in case there's a crash *and* an anr)
8403 ActivityManager.ProcessErrorStateInfo report = null;
8404 if (app.crashing) {
8405 report = app.crashingReport;
8406 } else if (app.notResponding) {
8407 report = app.notRespondingReport;
8408 }
8409
8410 if (report != null) {
8411 if (errList == null) {
8412 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8413 }
8414 errList.add(report);
8415 } else {
8416 Log.w(TAG, "Missing app error report, app = " + app.processName +
8417 " crashing = " + app.crashing +
8418 " notResponding = " + app.notResponding);
8419 }
8420 }
8421 }
8422 }
8423
8424 return errList;
8425 }
8426
8427 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8428 // Lazy instantiation of list
8429 List<ActivityManager.RunningAppProcessInfo> runList = null;
8430 synchronized (this) {
8431 // Iterate across all processes
8432 final int N = mLRUProcesses.size();
8433 for (int i = 0; i < N; i++) {
8434 ProcessRecord app = mLRUProcesses.get(i);
8435 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8436 // Generate process state info for running application
8437 ActivityManager.RunningAppProcessInfo currApp =
8438 new ActivityManager.RunningAppProcessInfo(app.processName,
8439 app.pid, app.getPackageList());
8440 int adj = app.curAdj;
8441 if (adj >= CONTENT_PROVIDER_ADJ) {
8442 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8443 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8444 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008445 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8446 } else if (adj >= HOME_APP_ADJ) {
8447 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8448 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008449 } else if (adj >= SECONDARY_SERVER_ADJ) {
8450 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8451 } else if (adj >= VISIBLE_APP_ADJ) {
8452 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8453 } else {
8454 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8455 }
8456 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8457 // + " lru=" + currApp.lru);
8458 if (runList == null) {
8459 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8460 }
8461 runList.add(currApp);
8462 }
8463 }
8464 }
8465 return runList;
8466 }
8467
8468 @Override
8469 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8470 synchronized (this) {
8471 if (checkCallingPermission(android.Manifest.permission.DUMP)
8472 != PackageManager.PERMISSION_GRANTED) {
8473 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8474 + Binder.getCallingPid()
8475 + ", uid=" + Binder.getCallingUid()
8476 + " without permission "
8477 + android.Manifest.permission.DUMP);
8478 return;
8479 }
8480 if (args.length != 0 && "service".equals(args[0])) {
8481 dumpService(fd, pw, args);
8482 return;
8483 }
8484 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008485 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008486 pw.println(" ");
8487 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008488 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008489 if (mWaitingVisibleActivities.size() > 0) {
8490 pw.println(" ");
8491 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008492 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008493 }
8494 if (mStoppingActivities.size() > 0) {
8495 pw.println(" ");
8496 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008497 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008498 }
8499 if (mFinishingActivities.size() > 0) {
8500 pw.println(" ");
8501 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008502 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008503 }
8504
8505 pw.println(" ");
8506 pw.println(" mPausingActivity: " + mPausingActivity);
8507 pw.println(" mResumedActivity: " + mResumedActivity);
8508 pw.println(" mFocusedActivity: " + mFocusedActivity);
8509 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8510
8511 if (mRecentTasks.size() > 0) {
8512 pw.println(" ");
8513 pw.println("Recent tasks in Current Activity Manager State:");
8514
8515 final int N = mRecentTasks.size();
8516 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008517 TaskRecord tr = mRecentTasks.get(i);
8518 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8519 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008520 mRecentTasks.get(i).dump(pw, " ");
8521 }
8522 }
8523
8524 pw.println(" ");
8525 pw.println(" mCurTask: " + mCurTask);
8526
8527 pw.println(" ");
8528 pw.println("Processes in Current Activity Manager State:");
8529
8530 boolean needSep = false;
8531 int numPers = 0;
8532
8533 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8534 final int NA = procs.size();
8535 for (int ia=0; ia<NA; ia++) {
8536 if (!needSep) {
8537 pw.println(" All known processes:");
8538 needSep = true;
8539 }
8540 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008541 pw.print(r.persistent ? " *PERS*" : " *APP*");
8542 pw.print(" UID "); pw.print(procs.keyAt(ia));
8543 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008544 r.dump(pw, " ");
8545 if (r.persistent) {
8546 numPers++;
8547 }
8548 }
8549 }
8550
8551 if (mLRUProcesses.size() > 0) {
8552 if (needSep) pw.println(" ");
8553 needSep = true;
8554 pw.println(" Running processes (most recent first):");
8555 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008556 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008557 needSep = true;
8558 }
8559
8560 synchronized (mPidsSelfLocked) {
8561 if (mPidsSelfLocked.size() > 0) {
8562 if (needSep) pw.println(" ");
8563 needSep = true;
8564 pw.println(" PID mappings:");
8565 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008566 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8567 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008568 }
8569 }
8570 }
8571
8572 if (mForegroundProcesses.size() > 0) {
8573 if (needSep) pw.println(" ");
8574 needSep = true;
8575 pw.println(" Foreground Processes:");
8576 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008577 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8578 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008579 }
8580 }
8581
8582 if (mPersistentStartingProcesses.size() > 0) {
8583 if (needSep) pw.println(" ");
8584 needSep = true;
8585 pw.println(" Persisent processes that are starting:");
8586 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008587 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008588 }
8589
8590 if (mStartingProcesses.size() > 0) {
8591 if (needSep) pw.println(" ");
8592 needSep = true;
8593 pw.println(" Processes that are starting:");
8594 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008595 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008596 }
8597
8598 if (mRemovedProcesses.size() > 0) {
8599 if (needSep) pw.println(" ");
8600 needSep = true;
8601 pw.println(" Processes that are being removed:");
8602 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008603 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008604 }
8605
8606 if (mProcessesOnHold.size() > 0) {
8607 if (needSep) pw.println(" ");
8608 needSep = true;
8609 pw.println(" Processes that are on old until the system is ready:");
8610 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008611 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008612 }
8613
8614 if (mProcessCrashTimes.getMap().size() > 0) {
8615 if (needSep) pw.println(" ");
8616 needSep = true;
8617 pw.println(" Time since processes crashed:");
8618 long now = SystemClock.uptimeMillis();
8619 for (Map.Entry<String, SparseArray<Long>> procs
8620 : mProcessCrashTimes.getMap().entrySet()) {
8621 SparseArray<Long> uids = procs.getValue();
8622 final int N = uids.size();
8623 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008624 pw.print(" Process "); pw.print(procs.getKey());
8625 pw.print(" uid "); pw.print(uids.keyAt(i));
8626 pw.print(": last crashed ");
8627 pw.print((now-uids.valueAt(i)));
8628 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008629 }
8630 }
8631 }
8632
8633 if (mBadProcesses.getMap().size() > 0) {
8634 if (needSep) pw.println(" ");
8635 needSep = true;
8636 pw.println(" Bad processes:");
8637 for (Map.Entry<String, SparseArray<Long>> procs
8638 : mBadProcesses.getMap().entrySet()) {
8639 SparseArray<Long> uids = procs.getValue();
8640 final int N = uids.size();
8641 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008642 pw.print(" Bad process "); pw.print(procs.getKey());
8643 pw.print(" uid "); pw.print(uids.keyAt(i));
8644 pw.print(": crashed at time ");
8645 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008646 }
8647 }
8648 }
8649
8650 pw.println(" ");
8651 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008652 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008653 pw.println(" mConfiguration: " + mConfiguration);
8654 pw.println(" mStartRunning=" + mStartRunning
8655 + " mSystemReady=" + mSystemReady
8656 + " mBooting=" + mBooting
8657 + " mBooted=" + mBooted
8658 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008659 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008660 pw.println(" mGoingToSleep=" + mGoingToSleep);
8661 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8662 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8663 + " mDebugTransient=" + mDebugTransient
8664 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8665 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8666 + " mWatcher=" + mWatcher);
8667 }
8668 }
8669
8670 /**
8671 * There are three ways to call this:
8672 * - no service specified: dump all the services
8673 * - a flattened component name that matched an existing service was specified as the
8674 * first arg: dump that one service
8675 * - the first arg isn't the flattened component name of an existing service:
8676 * dump all services whose component contains the first arg as a substring
8677 */
8678 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8679 String[] newArgs;
8680 String componentNameString;
8681 ServiceRecord r;
8682 if (args.length == 1) {
8683 componentNameString = null;
8684 newArgs = EMPTY_STRING_ARRAY;
8685 r = null;
8686 } else {
8687 componentNameString = args[1];
8688 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8689 r = componentName != null ? mServices.get(componentName) : null;
8690 newArgs = new String[args.length - 2];
8691 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8692 }
8693
8694 if (r != null) {
8695 dumpService(fd, pw, r, newArgs);
8696 } else {
8697 for (ServiceRecord r1 : mServices.values()) {
8698 if (componentNameString == null
8699 || r1.name.flattenToString().contains(componentNameString)) {
8700 dumpService(fd, pw, r1, newArgs);
8701 }
8702 }
8703 }
8704 }
8705
8706 /**
8707 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8708 * there is a thread associated with the service.
8709 */
8710 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8711 pw.println(" Service " + r.name.flattenToString());
8712 if (r.app != null && r.app.thread != null) {
8713 try {
8714 // flush anything that is already in the PrintWriter since the thread is going
8715 // to write to the file descriptor directly
8716 pw.flush();
8717 r.app.thread.dumpService(fd, r, args);
8718 pw.print("\n");
8719 } catch (RemoteException e) {
8720 pw.println("got a RemoteException while dumping the service");
8721 }
8722 }
8723 }
8724
8725 void dumpBroadcasts(PrintWriter pw) {
8726 synchronized (this) {
8727 if (checkCallingPermission(android.Manifest.permission.DUMP)
8728 != PackageManager.PERMISSION_GRANTED) {
8729 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8730 + Binder.getCallingPid()
8731 + ", uid=" + Binder.getCallingUid()
8732 + " without permission "
8733 + android.Manifest.permission.DUMP);
8734 return;
8735 }
8736 pw.println("Broadcasts in Current Activity Manager State:");
8737
8738 if (mRegisteredReceivers.size() > 0) {
8739 pw.println(" ");
8740 pw.println(" Registered Receivers:");
8741 Iterator it = mRegisteredReceivers.values().iterator();
8742 while (it.hasNext()) {
8743 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008744 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008745 r.dump(pw, " ");
8746 }
8747 }
8748
8749 pw.println(" ");
8750 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008751 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008752
8753 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8754 || mPendingBroadcast != null) {
8755 if (mParallelBroadcasts.size() > 0) {
8756 pw.println(" ");
8757 pw.println(" Active broadcasts:");
8758 }
8759 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8760 pw.println(" Broadcast #" + i + ":");
8761 mParallelBroadcasts.get(i).dump(pw, " ");
8762 }
8763 if (mOrderedBroadcasts.size() > 0) {
8764 pw.println(" ");
8765 pw.println(" Active serialized broadcasts:");
8766 }
8767 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8768 pw.println(" Serialized Broadcast #" + i + ":");
8769 mOrderedBroadcasts.get(i).dump(pw, " ");
8770 }
8771 pw.println(" ");
8772 pw.println(" Pending broadcast:");
8773 if (mPendingBroadcast != null) {
8774 mPendingBroadcast.dump(pw, " ");
8775 } else {
8776 pw.println(" (null)");
8777 }
8778 }
8779
8780 pw.println(" ");
8781 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8782 if (mStickyBroadcasts != null) {
8783 pw.println(" ");
8784 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008785 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008786 for (Map.Entry<String, ArrayList<Intent>> ent
8787 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008788 pw.print(" * Sticky action "); pw.print(ent.getKey());
8789 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008790 ArrayList<Intent> intents = ent.getValue();
8791 final int N = intents.size();
8792 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008793 sb.setLength(0);
8794 sb.append(" Intent: ");
8795 intents.get(i).toShortString(sb, true, false);
8796 pw.println(sb.toString());
8797 Bundle bundle = intents.get(i).getExtras();
8798 if (bundle != null) {
8799 pw.print(" ");
8800 pw.println(bundle.toString());
8801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008802 }
8803 }
8804 }
8805
8806 pw.println(" ");
8807 pw.println(" mHandler:");
8808 mHandler.dump(new PrintWriterPrinter(pw), " ");
8809 }
8810 }
8811
8812 void dumpServices(PrintWriter pw) {
8813 synchronized (this) {
8814 if (checkCallingPermission(android.Manifest.permission.DUMP)
8815 != PackageManager.PERMISSION_GRANTED) {
8816 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8817 + Binder.getCallingPid()
8818 + ", uid=" + Binder.getCallingUid()
8819 + " without permission "
8820 + android.Manifest.permission.DUMP);
8821 return;
8822 }
8823 pw.println("Services in Current Activity Manager State:");
8824
8825 boolean needSep = false;
8826
8827 if (mServices.size() > 0) {
8828 pw.println(" Active services:");
8829 Iterator<ServiceRecord> it = mServices.values().iterator();
8830 while (it.hasNext()) {
8831 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008832 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008833 r.dump(pw, " ");
8834 }
8835 needSep = true;
8836 }
8837
8838 if (mPendingServices.size() > 0) {
8839 if (needSep) pw.println(" ");
8840 pw.println(" Pending services:");
8841 for (int i=0; i<mPendingServices.size(); i++) {
8842 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008843 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008844 r.dump(pw, " ");
8845 }
8846 needSep = true;
8847 }
8848
8849 if (mRestartingServices.size() > 0) {
8850 if (needSep) pw.println(" ");
8851 pw.println(" Restarting services:");
8852 for (int i=0; i<mRestartingServices.size(); i++) {
8853 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008854 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008855 r.dump(pw, " ");
8856 }
8857 needSep = true;
8858 }
8859
8860 if (mStoppingServices.size() > 0) {
8861 if (needSep) pw.println(" ");
8862 pw.println(" Stopping services:");
8863 for (int i=0; i<mStoppingServices.size(); i++) {
8864 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008865 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008866 r.dump(pw, " ");
8867 }
8868 needSep = true;
8869 }
8870
8871 if (mServiceConnections.size() > 0) {
8872 if (needSep) pw.println(" ");
8873 pw.println(" Connection bindings to services:");
8874 Iterator<ConnectionRecord> it
8875 = mServiceConnections.values().iterator();
8876 while (it.hasNext()) {
8877 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008878 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008879 r.dump(pw, " ");
8880 }
8881 }
8882 }
8883 }
8884
8885 void dumpProviders(PrintWriter pw) {
8886 synchronized (this) {
8887 if (checkCallingPermission(android.Manifest.permission.DUMP)
8888 != PackageManager.PERMISSION_GRANTED) {
8889 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8890 + Binder.getCallingPid()
8891 + ", uid=" + Binder.getCallingUid()
8892 + " without permission "
8893 + android.Manifest.permission.DUMP);
8894 return;
8895 }
8896
8897 pw.println("Content Providers in Current Activity Manager State:");
8898
8899 boolean needSep = false;
8900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008901 if (mProvidersByClass.size() > 0) {
8902 if (needSep) pw.println(" ");
8903 pw.println(" Published content providers (by class):");
8904 Iterator it = mProvidersByClass.entrySet().iterator();
8905 while (it.hasNext()) {
8906 Map.Entry e = (Map.Entry)it.next();
8907 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008908 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008909 r.dump(pw, " ");
8910 }
8911 needSep = true;
8912 }
8913
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008914 if (mProvidersByName.size() > 0) {
8915 pw.println(" ");
8916 pw.println(" Authority to provider mappings:");
8917 Iterator it = mProvidersByName.entrySet().iterator();
8918 while (it.hasNext()) {
8919 Map.Entry e = (Map.Entry)it.next();
8920 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8921 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8922 pw.println(r);
8923 }
8924 needSep = true;
8925 }
8926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008927 if (mLaunchingProviders.size() > 0) {
8928 if (needSep) pw.println(" ");
8929 pw.println(" Launching content providers:");
8930 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008931 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8932 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008933 }
8934 needSep = true;
8935 }
8936
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008937 if (mGrantedUriPermissions.size() > 0) {
8938 pw.println();
8939 pw.println("Granted Uri Permissions:");
8940 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8941 int uid = mGrantedUriPermissions.keyAt(i);
8942 HashMap<Uri, UriPermission> perms
8943 = mGrantedUriPermissions.valueAt(i);
8944 pw.print(" * UID "); pw.print(uid);
8945 pw.println(" holds:");
8946 for (UriPermission perm : perms.values()) {
8947 pw.print(" "); pw.println(perm);
8948 perm.dump(pw, " ");
8949 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008950 }
8951 }
8952 }
8953 }
8954
8955 void dumpSenders(PrintWriter pw) {
8956 synchronized (this) {
8957 if (checkCallingPermission(android.Manifest.permission.DUMP)
8958 != PackageManager.PERMISSION_GRANTED) {
8959 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8960 + Binder.getCallingPid()
8961 + ", uid=" + Binder.getCallingUid()
8962 + " without permission "
8963 + android.Manifest.permission.DUMP);
8964 return;
8965 }
8966
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008967 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008968
8969 if (this.mIntentSenderRecords.size() > 0) {
8970 Iterator<WeakReference<PendingIntentRecord>> it
8971 = mIntentSenderRecords.values().iterator();
8972 while (it.hasNext()) {
8973 WeakReference<PendingIntentRecord> ref = it.next();
8974 PendingIntentRecord rec = ref != null ? ref.get(): null;
8975 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008976 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008977 rec.dump(pw, " ");
8978 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008979 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008980 }
8981 }
8982 }
8983 }
8984 }
8985
8986 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008987 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 TaskRecord lastTask = null;
8989 for (int i=list.size()-1; i>=0; i--) {
8990 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008991 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008992 if (lastTask != r.task) {
8993 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008994 pw.print(prefix);
8995 pw.print(full ? "* " : " ");
8996 pw.println(lastTask);
8997 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008998 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009000 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009001 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9002 pw.print(" #"); pw.print(i); pw.print(": ");
9003 pw.println(r);
9004 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009005 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009007 }
9008 }
9009
9010 private static final int dumpProcessList(PrintWriter pw, List list,
9011 String prefix, String normalLabel, String persistentLabel,
9012 boolean inclOomAdj) {
9013 int numPers = 0;
9014 for (int i=list.size()-1; i>=0; i--) {
9015 ProcessRecord r = (ProcessRecord)list.get(i);
9016 if (false) {
9017 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9018 + " #" + i + ":");
9019 r.dump(pw, prefix + " ");
9020 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009021 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009022 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009023 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009024 } else {
9025 pw.println(String.format("%s%s #%2d: %s",
9026 prefix, (r.persistent ? persistentLabel : normalLabel),
9027 i, r.toString()));
9028 }
9029 if (r.persistent) {
9030 numPers++;
9031 }
9032 }
9033 return numPers;
9034 }
9035
9036 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9037 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009038 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009039 long uptime = SystemClock.uptimeMillis();
9040 long realtime = SystemClock.elapsedRealtime();
9041
9042 if (isCheckinRequest) {
9043 // short checkin version
9044 pw.println(uptime + "," + realtime);
9045 pw.flush();
9046 } else {
9047 pw.println("Applications Memory Usage (kB):");
9048 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9049 }
9050 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9051 ProcessRecord r = (ProcessRecord)list.get(i);
9052 if (r.thread != null) {
9053 if (!isCheckinRequest) {
9054 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9055 pw.flush();
9056 }
9057 try {
9058 r.thread.asBinder().dump(fd, args);
9059 } catch (RemoteException e) {
9060 if (!isCheckinRequest) {
9061 pw.println("Got RemoteException!");
9062 pw.flush();
9063 }
9064 }
9065 }
9066 }
9067 }
9068
9069 /**
9070 * Searches array of arguments for the specified string
9071 * @param args array of argument strings
9072 * @param value value to search for
9073 * @return true if the value is contained in the array
9074 */
9075 private static boolean scanArgs(String[] args, String value) {
9076 if (args != null) {
9077 for (String arg : args) {
9078 if (value.equals(arg)) {
9079 return true;
9080 }
9081 }
9082 }
9083 return false;
9084 }
9085
Dianne Hackborn75b03852009-06-12 15:43:26 -07009086 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009087 int count = mHistory.size();
9088
9089 // convert the token to an entry in the history.
9090 HistoryRecord r = null;
9091 int index = -1;
9092 for (int i=count-1; i>=0; i--) {
9093 Object o = mHistory.get(i);
9094 if (o == token) {
9095 r = (HistoryRecord)o;
9096 index = i;
9097 break;
9098 }
9099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009100
9101 return index;
9102 }
9103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009104 private final void killServicesLocked(ProcessRecord app,
9105 boolean allowRestart) {
9106 // Report disconnected services.
9107 if (false) {
9108 // XXX we are letting the client link to the service for
9109 // death notifications.
9110 if (app.services.size() > 0) {
9111 Iterator it = app.services.iterator();
9112 while (it.hasNext()) {
9113 ServiceRecord r = (ServiceRecord)it.next();
9114 if (r.connections.size() > 0) {
9115 Iterator<ConnectionRecord> jt
9116 = r.connections.values().iterator();
9117 while (jt.hasNext()) {
9118 ConnectionRecord c = jt.next();
9119 if (c.binding.client != app) {
9120 try {
9121 //c.conn.connected(r.className, null);
9122 } catch (Exception e) {
9123 // todo: this should be asynchronous!
9124 Log.w(TAG, "Exception thrown disconnected servce "
9125 + r.shortName
9126 + " from app " + app.processName, e);
9127 }
9128 }
9129 }
9130 }
9131 }
9132 }
9133 }
9134
9135 // Clean up any connections this application has to other services.
9136 if (app.connections.size() > 0) {
9137 Iterator<ConnectionRecord> it = app.connections.iterator();
9138 while (it.hasNext()) {
9139 ConnectionRecord r = it.next();
9140 removeConnectionLocked(r, app, null);
9141 }
9142 }
9143 app.connections.clear();
9144
9145 if (app.services.size() != 0) {
9146 // Any services running in the application need to be placed
9147 // back in the pending list.
9148 Iterator it = app.services.iterator();
9149 while (it.hasNext()) {
9150 ServiceRecord sr = (ServiceRecord)it.next();
9151 synchronized (sr.stats.getBatteryStats()) {
9152 sr.stats.stopLaunchedLocked();
9153 }
9154 sr.app = null;
9155 sr.executeNesting = 0;
9156 mStoppingServices.remove(sr);
9157 if (sr.bindings.size() > 0) {
9158 Iterator<IntentBindRecord> bindings
9159 = sr.bindings.values().iterator();
9160 while (bindings.hasNext()) {
9161 IntentBindRecord b = bindings.next();
9162 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9163 + ": shouldUnbind=" + b.hasBound);
9164 b.binder = null;
9165 b.requested = b.received = b.hasBound = false;
9166 }
9167 }
9168
9169 if (sr.crashCount >= 2) {
9170 Log.w(TAG, "Service crashed " + sr.crashCount
9171 + " times, stopping: " + sr);
9172 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9173 sr.crashCount, sr.shortName, app.pid);
9174 bringDownServiceLocked(sr, true);
9175 } else if (!allowRestart) {
9176 bringDownServiceLocked(sr, true);
9177 } else {
9178 scheduleServiceRestartLocked(sr);
9179 }
9180 }
9181
9182 if (!allowRestart) {
9183 app.services.clear();
9184 }
9185 }
9186
9187 app.executingServices.clear();
9188 }
9189
9190 private final void removeDyingProviderLocked(ProcessRecord proc,
9191 ContentProviderRecord cpr) {
9192 synchronized (cpr) {
9193 cpr.launchingApp = null;
9194 cpr.notifyAll();
9195 }
9196
9197 mProvidersByClass.remove(cpr.info.name);
9198 String names[] = cpr.info.authority.split(";");
9199 for (int j = 0; j < names.length; j++) {
9200 mProvidersByName.remove(names[j]);
9201 }
9202
9203 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9204 while (cit.hasNext()) {
9205 ProcessRecord capp = cit.next();
9206 if (!capp.persistent && capp.thread != null
9207 && capp.pid != 0
9208 && capp.pid != MY_PID) {
9209 Log.i(TAG, "Killing app " + capp.processName
9210 + " (pid " + capp.pid
9211 + ") because provider " + cpr.info.name
9212 + " is in dying process " + proc.processName);
9213 Process.killProcess(capp.pid);
9214 }
9215 }
9216
9217 mLaunchingProviders.remove(cpr);
9218 }
9219
9220 /**
9221 * Main code for cleaning up a process when it has gone away. This is
9222 * called both as a result of the process dying, or directly when stopping
9223 * a process when running in single process mode.
9224 */
9225 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9226 boolean restarting, int index) {
9227 if (index >= 0) {
9228 mLRUProcesses.remove(index);
9229 }
9230
9231 // Dismiss any open dialogs.
9232 if (app.crashDialog != null) {
9233 app.crashDialog.dismiss();
9234 app.crashDialog = null;
9235 }
9236 if (app.anrDialog != null) {
9237 app.anrDialog.dismiss();
9238 app.anrDialog = null;
9239 }
9240 if (app.waitDialog != null) {
9241 app.waitDialog.dismiss();
9242 app.waitDialog = null;
9243 }
9244
9245 app.crashing = false;
9246 app.notResponding = false;
9247
9248 app.resetPackageList();
9249 app.thread = null;
9250 app.forcingToForeground = null;
9251 app.foregroundServices = false;
9252
9253 killServicesLocked(app, true);
9254
9255 boolean restart = false;
9256
9257 int NL = mLaunchingProviders.size();
9258
9259 // Remove published content providers.
9260 if (!app.pubProviders.isEmpty()) {
9261 Iterator it = app.pubProviders.values().iterator();
9262 while (it.hasNext()) {
9263 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9264 cpr.provider = null;
9265 cpr.app = null;
9266
9267 // See if someone is waiting for this provider... in which
9268 // case we don't remove it, but just let it restart.
9269 int i = 0;
9270 if (!app.bad) {
9271 for (; i<NL; i++) {
9272 if (mLaunchingProviders.get(i) == cpr) {
9273 restart = true;
9274 break;
9275 }
9276 }
9277 } else {
9278 i = NL;
9279 }
9280
9281 if (i >= NL) {
9282 removeDyingProviderLocked(app, cpr);
9283 NL = mLaunchingProviders.size();
9284 }
9285 }
9286 app.pubProviders.clear();
9287 }
9288
9289 // Look through the content providers we are waiting to have launched,
9290 // and if any run in this process then either schedule a restart of
9291 // the process or kill the client waiting for it if this process has
9292 // gone bad.
9293 for (int i=0; i<NL; i++) {
9294 ContentProviderRecord cpr = (ContentProviderRecord)
9295 mLaunchingProviders.get(i);
9296 if (cpr.launchingApp == app) {
9297 if (!app.bad) {
9298 restart = true;
9299 } else {
9300 removeDyingProviderLocked(app, cpr);
9301 NL = mLaunchingProviders.size();
9302 }
9303 }
9304 }
9305
9306 // Unregister from connected content providers.
9307 if (!app.conProviders.isEmpty()) {
9308 Iterator it = app.conProviders.iterator();
9309 while (it.hasNext()) {
9310 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9311 cpr.clients.remove(app);
9312 }
9313 app.conProviders.clear();
9314 }
9315
9316 skipCurrentReceiverLocked(app);
9317
9318 // Unregister any receivers.
9319 if (app.receivers.size() > 0) {
9320 Iterator<ReceiverList> it = app.receivers.iterator();
9321 while (it.hasNext()) {
9322 removeReceiverLocked(it.next());
9323 }
9324 app.receivers.clear();
9325 }
9326
Christopher Tate181fafa2009-05-14 11:12:14 -07009327 // If the app is undergoing backup, tell the backup manager about it
9328 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9329 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9330 try {
9331 IBackupManager bm = IBackupManager.Stub.asInterface(
9332 ServiceManager.getService(Context.BACKUP_SERVICE));
9333 bm.agentDisconnected(app.info.packageName);
9334 } catch (RemoteException e) {
9335 // can't happen; backup manager is local
9336 }
9337 }
9338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009339 // If the caller is restarting this app, then leave it in its
9340 // current lists and let the caller take care of it.
9341 if (restarting) {
9342 return;
9343 }
9344
9345 if (!app.persistent) {
9346 if (DEBUG_PROCESSES) Log.v(TAG,
9347 "Removing non-persistent process during cleanup: " + app);
9348 mProcessNames.remove(app.processName, app.info.uid);
9349 } else if (!app.removed) {
9350 // This app is persistent, so we need to keep its record around.
9351 // If it is not already on the pending app list, add it there
9352 // and start a new process for it.
9353 app.thread = null;
9354 app.forcingToForeground = null;
9355 app.foregroundServices = false;
9356 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9357 mPersistentStartingProcesses.add(app);
9358 restart = true;
9359 }
9360 }
9361 mProcessesOnHold.remove(app);
9362
The Android Open Source Project4df24232009-03-05 14:34:35 -08009363 if (app == mHomeProcess) {
9364 mHomeProcess = null;
9365 }
9366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009367 if (restart) {
9368 // We have components that still need to be running in the
9369 // process, so re-launch it.
9370 mProcessNames.put(app.processName, app.info.uid, app);
9371 startProcessLocked(app, "restart", app.processName);
9372 } else if (app.pid > 0 && app.pid != MY_PID) {
9373 // Goodbye!
9374 synchronized (mPidsSelfLocked) {
9375 mPidsSelfLocked.remove(app.pid);
9376 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9377 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009378 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009379 }
9380 }
9381
9382 // =========================================================
9383 // SERVICES
9384 // =========================================================
9385
9386 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9387 ActivityManager.RunningServiceInfo info =
9388 new ActivityManager.RunningServiceInfo();
9389 info.service = r.name;
9390 if (r.app != null) {
9391 info.pid = r.app.pid;
9392 }
9393 info.process = r.processName;
9394 info.foreground = r.isForeground;
9395 info.activeSince = r.createTime;
9396 info.started = r.startRequested;
9397 info.clientCount = r.connections.size();
9398 info.crashCount = r.crashCount;
9399 info.lastActivityTime = r.lastActivity;
9400 return info;
9401 }
9402
9403 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9404 int flags) {
9405 synchronized (this) {
9406 ArrayList<ActivityManager.RunningServiceInfo> res
9407 = new ArrayList<ActivityManager.RunningServiceInfo>();
9408
9409 if (mServices.size() > 0) {
9410 Iterator<ServiceRecord> it = mServices.values().iterator();
9411 while (it.hasNext() && res.size() < maxNum) {
9412 res.add(makeRunningServiceInfoLocked(it.next()));
9413 }
9414 }
9415
9416 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9417 ServiceRecord r = mRestartingServices.get(i);
9418 ActivityManager.RunningServiceInfo info =
9419 makeRunningServiceInfoLocked(r);
9420 info.restarting = r.nextRestartTime;
9421 res.add(info);
9422 }
9423
9424 return res;
9425 }
9426 }
9427
9428 private final ServiceRecord findServiceLocked(ComponentName name,
9429 IBinder token) {
9430 ServiceRecord r = mServices.get(name);
9431 return r == token ? r : null;
9432 }
9433
9434 private final class ServiceLookupResult {
9435 final ServiceRecord record;
9436 final String permission;
9437
9438 ServiceLookupResult(ServiceRecord _record, String _permission) {
9439 record = _record;
9440 permission = _permission;
9441 }
9442 };
9443
9444 private ServiceLookupResult findServiceLocked(Intent service,
9445 String resolvedType) {
9446 ServiceRecord r = null;
9447 if (service.getComponent() != null) {
9448 r = mServices.get(service.getComponent());
9449 }
9450 if (r == null) {
9451 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9452 r = mServicesByIntent.get(filter);
9453 }
9454
9455 if (r == null) {
9456 try {
9457 ResolveInfo rInfo =
9458 ActivityThread.getPackageManager().resolveService(
9459 service, resolvedType, 0);
9460 ServiceInfo sInfo =
9461 rInfo != null ? rInfo.serviceInfo : null;
9462 if (sInfo == null) {
9463 return null;
9464 }
9465
9466 ComponentName name = new ComponentName(
9467 sInfo.applicationInfo.packageName, sInfo.name);
9468 r = mServices.get(name);
9469 } catch (RemoteException ex) {
9470 // pm is in same process, this will never happen.
9471 }
9472 }
9473 if (r != null) {
9474 int callingPid = Binder.getCallingPid();
9475 int callingUid = Binder.getCallingUid();
9476 if (checkComponentPermission(r.permission,
9477 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9478 != PackageManager.PERMISSION_GRANTED) {
9479 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9480 + " from pid=" + callingPid
9481 + ", uid=" + callingUid
9482 + " requires " + r.permission);
9483 return new ServiceLookupResult(null, r.permission);
9484 }
9485 return new ServiceLookupResult(r, null);
9486 }
9487 return null;
9488 }
9489
9490 private class ServiceRestarter implements Runnable {
9491 private ServiceRecord mService;
9492
9493 void setService(ServiceRecord service) {
9494 mService = service;
9495 }
9496
9497 public void run() {
9498 synchronized(ActivityManagerService.this) {
9499 performServiceRestartLocked(mService);
9500 }
9501 }
9502 }
9503
9504 private ServiceLookupResult retrieveServiceLocked(Intent service,
9505 String resolvedType, int callingPid, int callingUid) {
9506 ServiceRecord r = null;
9507 if (service.getComponent() != null) {
9508 r = mServices.get(service.getComponent());
9509 }
9510 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9511 r = mServicesByIntent.get(filter);
9512 if (r == null) {
9513 try {
9514 ResolveInfo rInfo =
9515 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009516 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009517 ServiceInfo sInfo =
9518 rInfo != null ? rInfo.serviceInfo : null;
9519 if (sInfo == null) {
9520 Log.w(TAG, "Unable to start service " + service +
9521 ": not found");
9522 return null;
9523 }
9524
9525 ComponentName name = new ComponentName(
9526 sInfo.applicationInfo.packageName, sInfo.name);
9527 r = mServices.get(name);
9528 if (r == null) {
9529 filter = new Intent.FilterComparison(service.cloneFilter());
9530 ServiceRestarter res = new ServiceRestarter();
9531 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9532 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9533 synchronized (stats) {
9534 ss = stats.getServiceStatsLocked(
9535 sInfo.applicationInfo.uid, sInfo.packageName,
9536 sInfo.name);
9537 }
9538 r = new ServiceRecord(ss, name, filter, sInfo, res);
9539 res.setService(r);
9540 mServices.put(name, r);
9541 mServicesByIntent.put(filter, r);
9542
9543 // Make sure this component isn't in the pending list.
9544 int N = mPendingServices.size();
9545 for (int i=0; i<N; i++) {
9546 ServiceRecord pr = mPendingServices.get(i);
9547 if (pr.name.equals(name)) {
9548 mPendingServices.remove(i);
9549 i--;
9550 N--;
9551 }
9552 }
9553 }
9554 } catch (RemoteException ex) {
9555 // pm is in same process, this will never happen.
9556 }
9557 }
9558 if (r != null) {
9559 if (checkComponentPermission(r.permission,
9560 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9561 != PackageManager.PERMISSION_GRANTED) {
9562 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9563 + " from pid=" + Binder.getCallingPid()
9564 + ", uid=" + Binder.getCallingUid()
9565 + " requires " + r.permission);
9566 return new ServiceLookupResult(null, r.permission);
9567 }
9568 return new ServiceLookupResult(r, null);
9569 }
9570 return null;
9571 }
9572
9573 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9574 long now = SystemClock.uptimeMillis();
9575 if (r.executeNesting == 0 && r.app != null) {
9576 if (r.app.executingServices.size() == 0) {
9577 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9578 msg.obj = r.app;
9579 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9580 }
9581 r.app.executingServices.add(r);
9582 }
9583 r.executeNesting++;
9584 r.executingStart = now;
9585 }
9586
9587 private final void sendServiceArgsLocked(ServiceRecord r,
9588 boolean oomAdjusted) {
9589 final int N = r.startArgs.size();
9590 if (N == 0) {
9591 return;
9592 }
9593
9594 final int BASEID = r.lastStartId - N + 1;
9595 int i = 0;
9596 while (i < N) {
9597 try {
9598 Intent args = r.startArgs.get(i);
9599 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9600 + r.name + " " + r.intent + " args=" + args);
9601 bumpServiceExecutingLocked(r);
9602 if (!oomAdjusted) {
9603 oomAdjusted = true;
9604 updateOomAdjLocked(r.app);
9605 }
9606 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9607 i++;
9608 } catch (Exception e) {
9609 break;
9610 }
9611 }
9612 if (i == N) {
9613 r.startArgs.clear();
9614 } else {
9615 while (i > 0) {
9616 r.startArgs.remove(0);
9617 i--;
9618 }
9619 }
9620 }
9621
9622 private final boolean requestServiceBindingLocked(ServiceRecord r,
9623 IntentBindRecord i, boolean rebind) {
9624 if (r.app == null || r.app.thread == null) {
9625 // If service is not currently running, can't yet bind.
9626 return false;
9627 }
9628 if ((!i.requested || rebind) && i.apps.size() > 0) {
9629 try {
9630 bumpServiceExecutingLocked(r);
9631 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9632 + ": shouldUnbind=" + i.hasBound);
9633 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9634 if (!rebind) {
9635 i.requested = true;
9636 }
9637 i.hasBound = true;
9638 i.doRebind = false;
9639 } catch (RemoteException e) {
9640 return false;
9641 }
9642 }
9643 return true;
9644 }
9645
9646 private final void requestServiceBindingsLocked(ServiceRecord r) {
9647 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9648 while (bindings.hasNext()) {
9649 IntentBindRecord i = bindings.next();
9650 if (!requestServiceBindingLocked(r, i, false)) {
9651 break;
9652 }
9653 }
9654 }
9655
9656 private final void realStartServiceLocked(ServiceRecord r,
9657 ProcessRecord app) throws RemoteException {
9658 if (app.thread == null) {
9659 throw new RemoteException();
9660 }
9661
9662 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009663 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009664
9665 app.services.add(r);
9666 bumpServiceExecutingLocked(r);
9667 updateLRUListLocked(app, true);
9668
9669 boolean created = false;
9670 try {
9671 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9672 + r.name + " " + r.intent);
9673 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9674 System.identityHashCode(r), r.shortName,
9675 r.intent.getIntent().toString(), r.app.pid);
9676 synchronized (r.stats.getBatteryStats()) {
9677 r.stats.startLaunchedLocked();
9678 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009679 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009680 app.thread.scheduleCreateService(r, r.serviceInfo);
9681 created = true;
9682 } finally {
9683 if (!created) {
9684 app.services.remove(r);
9685 scheduleServiceRestartLocked(r);
9686 }
9687 }
9688
9689 requestServiceBindingsLocked(r);
9690 sendServiceArgsLocked(r, true);
9691 }
9692
9693 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9694 r.totalRestartCount++;
9695 if (r.restartDelay == 0) {
9696 r.restartCount++;
9697 r.restartDelay = SERVICE_RESTART_DURATION;
9698 } else {
9699 // If it has been a "reasonably long time" since the service
9700 // was started, then reset our restart duration back to
9701 // the beginning, so we don't infinitely increase the duration
9702 // on a service that just occasionally gets killed (which is
9703 // a normal case, due to process being killed to reclaim memory).
9704 long now = SystemClock.uptimeMillis();
9705 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9706 r.restartCount = 1;
9707 r.restartDelay = SERVICE_RESTART_DURATION;
9708 } else {
9709 r.restartDelay *= 2;
9710 }
9711 }
9712 if (!mRestartingServices.contains(r)) {
9713 mRestartingServices.add(r);
9714 }
9715 mHandler.removeCallbacks(r.restarter);
9716 mHandler.postDelayed(r.restarter, r.restartDelay);
9717 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9718 Log.w(TAG, "Scheduling restart of crashed service "
9719 + r.shortName + " in " + r.restartDelay + "ms");
9720 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9721 r.shortName, r.restartDelay);
9722
9723 Message msg = Message.obtain();
9724 msg.what = SERVICE_ERROR_MSG;
9725 msg.obj = r;
9726 mHandler.sendMessage(msg);
9727 }
9728
9729 final void performServiceRestartLocked(ServiceRecord r) {
9730 if (!mRestartingServices.contains(r)) {
9731 return;
9732 }
9733 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9734 }
9735
9736 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9737 if (r.restartDelay == 0) {
9738 return false;
9739 }
9740 r.resetRestartCounter();
9741 mRestartingServices.remove(r);
9742 mHandler.removeCallbacks(r.restarter);
9743 return true;
9744 }
9745
9746 private final boolean bringUpServiceLocked(ServiceRecord r,
9747 int intentFlags, boolean whileRestarting) {
9748 //Log.i(TAG, "Bring up service:");
9749 //r.dump(" ");
9750
9751 if (r.app != null) {
9752 sendServiceArgsLocked(r, false);
9753 return true;
9754 }
9755
9756 if (!whileRestarting && r.restartDelay > 0) {
9757 // If waiting for a restart, then do nothing.
9758 return true;
9759 }
9760
9761 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9762 + " " + r.intent);
9763
9764 final String appName = r.processName;
9765 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9766 if (app != null && app.thread != null) {
9767 try {
9768 realStartServiceLocked(r, app);
9769 return true;
9770 } catch (RemoteException e) {
9771 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9772 }
9773
9774 // If a dead object exception was thrown -- fall through to
9775 // restart the application.
9776 }
9777
9778 if (!mPendingServices.contains(r)) {
9779 // Not running -- get it started, and enqueue this service record
9780 // to be executed when the app comes up.
9781 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9782 "service", r.name) == null) {
9783 Log.w(TAG, "Unable to launch app "
9784 + r.appInfo.packageName + "/"
9785 + r.appInfo.uid + " for service "
9786 + r.intent.getIntent() + ": process is bad");
9787 bringDownServiceLocked(r, true);
9788 return false;
9789 }
9790 mPendingServices.add(r);
9791 }
9792 return true;
9793 }
9794
9795 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9796 //Log.i(TAG, "Bring down service:");
9797 //r.dump(" ");
9798
9799 // Does it still need to run?
9800 if (!force && r.startRequested) {
9801 return;
9802 }
9803 if (r.connections.size() > 0) {
9804 if (!force) {
9805 // XXX should probably keep a count of the number of auto-create
9806 // connections directly in the service.
9807 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9808 while (it.hasNext()) {
9809 ConnectionRecord cr = it.next();
9810 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9811 return;
9812 }
9813 }
9814 }
9815
9816 // Report to all of the connections that the service is no longer
9817 // available.
9818 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9819 while (it.hasNext()) {
9820 ConnectionRecord c = it.next();
9821 try {
9822 // todo: shouldn't be a synchronous call!
9823 c.conn.connected(r.name, null);
9824 } catch (Exception e) {
9825 Log.w(TAG, "Failure disconnecting service " + r.name +
9826 " to connection " + c.conn.asBinder() +
9827 " (in " + c.binding.client.processName + ")", e);
9828 }
9829 }
9830 }
9831
9832 // Tell the service that it has been unbound.
9833 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9834 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9835 while (it.hasNext()) {
9836 IntentBindRecord ibr = it.next();
9837 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9838 + ": hasBound=" + ibr.hasBound);
9839 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9840 try {
9841 bumpServiceExecutingLocked(r);
9842 updateOomAdjLocked(r.app);
9843 ibr.hasBound = false;
9844 r.app.thread.scheduleUnbindService(r,
9845 ibr.intent.getIntent());
9846 } catch (Exception e) {
9847 Log.w(TAG, "Exception when unbinding service "
9848 + r.shortName, e);
9849 serviceDoneExecutingLocked(r, true);
9850 }
9851 }
9852 }
9853 }
9854
9855 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9856 + " " + r.intent);
9857 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9858 System.identityHashCode(r), r.shortName,
9859 (r.app != null) ? r.app.pid : -1);
9860
9861 mServices.remove(r.name);
9862 mServicesByIntent.remove(r.intent);
9863 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9864 r.totalRestartCount = 0;
9865 unscheduleServiceRestartLocked(r);
9866
9867 // Also make sure it is not on the pending list.
9868 int N = mPendingServices.size();
9869 for (int i=0; i<N; i++) {
9870 if (mPendingServices.get(i) == r) {
9871 mPendingServices.remove(i);
9872 if (DEBUG_SERVICE) Log.v(
9873 TAG, "Removed pending service: " + r.shortName);
9874 i--;
9875 N--;
9876 }
9877 }
9878
9879 if (r.app != null) {
9880 synchronized (r.stats.getBatteryStats()) {
9881 r.stats.stopLaunchedLocked();
9882 }
9883 r.app.services.remove(r);
9884 if (r.app.thread != null) {
9885 updateServiceForegroundLocked(r.app, false);
9886 try {
9887 Log.i(TAG, "Stopping service: " + r.shortName);
9888 bumpServiceExecutingLocked(r);
9889 mStoppingServices.add(r);
9890 updateOomAdjLocked(r.app);
9891 r.app.thread.scheduleStopService(r);
9892 } catch (Exception e) {
9893 Log.w(TAG, "Exception when stopping service "
9894 + r.shortName, e);
9895 serviceDoneExecutingLocked(r, true);
9896 }
9897 } else {
9898 if (DEBUG_SERVICE) Log.v(
9899 TAG, "Removed service that has no process: " + r.shortName);
9900 }
9901 } else {
9902 if (DEBUG_SERVICE) Log.v(
9903 TAG, "Removed service that is not running: " + r.shortName);
9904 }
9905 }
9906
9907 ComponentName startServiceLocked(IApplicationThread caller,
9908 Intent service, String resolvedType,
9909 int callingPid, int callingUid) {
9910 synchronized(this) {
9911 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9912 + " type=" + resolvedType + " args=" + service.getExtras());
9913
9914 if (caller != null) {
9915 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9916 if (callerApp == null) {
9917 throw new SecurityException(
9918 "Unable to find app for caller " + caller
9919 + " (pid=" + Binder.getCallingPid()
9920 + ") when starting service " + service);
9921 }
9922 }
9923
9924 ServiceLookupResult res =
9925 retrieveServiceLocked(service, resolvedType,
9926 callingPid, callingUid);
9927 if (res == null) {
9928 return null;
9929 }
9930 if (res.record == null) {
9931 return new ComponentName("!", res.permission != null
9932 ? res.permission : "private to package");
9933 }
9934 ServiceRecord r = res.record;
9935 if (unscheduleServiceRestartLocked(r)) {
9936 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9937 + r.shortName);
9938 }
9939 r.startRequested = true;
9940 r.startArgs.add(service);
9941 r.lastStartId++;
9942 if (r.lastStartId < 1) {
9943 r.lastStartId = 1;
9944 }
9945 r.lastActivity = SystemClock.uptimeMillis();
9946 synchronized (r.stats.getBatteryStats()) {
9947 r.stats.startRunningLocked();
9948 }
9949 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9950 return new ComponentName("!", "Service process is bad");
9951 }
9952 return r.name;
9953 }
9954 }
9955
9956 public ComponentName startService(IApplicationThread caller, Intent service,
9957 String resolvedType) {
9958 // Refuse possible leaked file descriptors
9959 if (service != null && service.hasFileDescriptors() == true) {
9960 throw new IllegalArgumentException("File descriptors passed in Intent");
9961 }
9962
9963 synchronized(this) {
9964 final int callingPid = Binder.getCallingPid();
9965 final int callingUid = Binder.getCallingUid();
9966 final long origId = Binder.clearCallingIdentity();
9967 ComponentName res = startServiceLocked(caller, service,
9968 resolvedType, callingPid, callingUid);
9969 Binder.restoreCallingIdentity(origId);
9970 return res;
9971 }
9972 }
9973
9974 ComponentName startServiceInPackage(int uid,
9975 Intent service, String resolvedType) {
9976 synchronized(this) {
9977 final long origId = Binder.clearCallingIdentity();
9978 ComponentName res = startServiceLocked(null, service,
9979 resolvedType, -1, uid);
9980 Binder.restoreCallingIdentity(origId);
9981 return res;
9982 }
9983 }
9984
9985 public int stopService(IApplicationThread caller, Intent service,
9986 String resolvedType) {
9987 // Refuse possible leaked file descriptors
9988 if (service != null && service.hasFileDescriptors() == true) {
9989 throw new IllegalArgumentException("File descriptors passed in Intent");
9990 }
9991
9992 synchronized(this) {
9993 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9994 + " type=" + resolvedType);
9995
9996 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9997 if (caller != null && callerApp == null) {
9998 throw new SecurityException(
9999 "Unable to find app for caller " + caller
10000 + " (pid=" + Binder.getCallingPid()
10001 + ") when stopping service " + service);
10002 }
10003
10004 // If this service is active, make sure it is stopped.
10005 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10006 if (r != null) {
10007 if (r.record != null) {
10008 synchronized (r.record.stats.getBatteryStats()) {
10009 r.record.stats.stopRunningLocked();
10010 }
10011 r.record.startRequested = false;
10012 final long origId = Binder.clearCallingIdentity();
10013 bringDownServiceLocked(r.record, false);
10014 Binder.restoreCallingIdentity(origId);
10015 return 1;
10016 }
10017 return -1;
10018 }
10019 }
10020
10021 return 0;
10022 }
10023
10024 public IBinder peekService(Intent service, String resolvedType) {
10025 // Refuse possible leaked file descriptors
10026 if (service != null && service.hasFileDescriptors() == true) {
10027 throw new IllegalArgumentException("File descriptors passed in Intent");
10028 }
10029
10030 IBinder ret = null;
10031
10032 synchronized(this) {
10033 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10034
10035 if (r != null) {
10036 // r.record is null if findServiceLocked() failed the caller permission check
10037 if (r.record == null) {
10038 throw new SecurityException(
10039 "Permission Denial: Accessing service " + r.record.name
10040 + " from pid=" + Binder.getCallingPid()
10041 + ", uid=" + Binder.getCallingUid()
10042 + " requires " + r.permission);
10043 }
10044 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10045 if (ib != null) {
10046 ret = ib.binder;
10047 }
10048 }
10049 }
10050
10051 return ret;
10052 }
10053
10054 public boolean stopServiceToken(ComponentName className, IBinder token,
10055 int startId) {
10056 synchronized(this) {
10057 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10058 + " " + token + " startId=" + startId);
10059 ServiceRecord r = findServiceLocked(className, token);
10060 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10061 synchronized (r.stats.getBatteryStats()) {
10062 r.stats.stopRunningLocked();
10063 r.startRequested = false;
10064 }
10065 final long origId = Binder.clearCallingIdentity();
10066 bringDownServiceLocked(r, false);
10067 Binder.restoreCallingIdentity(origId);
10068 return true;
10069 }
10070 }
10071 return false;
10072 }
10073
10074 public void setServiceForeground(ComponentName className, IBinder token,
10075 boolean isForeground) {
10076 synchronized(this) {
10077 ServiceRecord r = findServiceLocked(className, token);
10078 if (r != null) {
10079 if (r.isForeground != isForeground) {
10080 final long origId = Binder.clearCallingIdentity();
10081 r.isForeground = isForeground;
10082 if (r.app != null) {
10083 updateServiceForegroundLocked(r.app, true);
10084 }
10085 Binder.restoreCallingIdentity(origId);
10086 }
10087 }
10088 }
10089 }
10090
10091 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10092 boolean anyForeground = false;
10093 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10094 if (sr.isForeground) {
10095 anyForeground = true;
10096 break;
10097 }
10098 }
10099 if (anyForeground != proc.foregroundServices) {
10100 proc.foregroundServices = anyForeground;
10101 if (oomAdj) {
10102 updateOomAdjLocked();
10103 }
10104 }
10105 }
10106
10107 public int bindService(IApplicationThread caller, IBinder token,
10108 Intent service, String resolvedType,
10109 IServiceConnection connection, int flags) {
10110 // Refuse possible leaked file descriptors
10111 if (service != null && service.hasFileDescriptors() == true) {
10112 throw new IllegalArgumentException("File descriptors passed in Intent");
10113 }
10114
10115 synchronized(this) {
10116 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10117 + " type=" + resolvedType + " conn=" + connection.asBinder()
10118 + " flags=0x" + Integer.toHexString(flags));
10119 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10120 if (callerApp == null) {
10121 throw new SecurityException(
10122 "Unable to find app for caller " + caller
10123 + " (pid=" + Binder.getCallingPid()
10124 + ") when binding service " + service);
10125 }
10126
10127 HistoryRecord activity = null;
10128 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010129 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010130 if (aindex < 0) {
10131 Log.w(TAG, "Binding with unknown activity: " + token);
10132 return 0;
10133 }
10134 activity = (HistoryRecord)mHistory.get(aindex);
10135 }
10136
10137 ServiceLookupResult res =
10138 retrieveServiceLocked(service, resolvedType,
10139 Binder.getCallingPid(), Binder.getCallingUid());
10140 if (res == null) {
10141 return 0;
10142 }
10143 if (res.record == null) {
10144 return -1;
10145 }
10146 ServiceRecord s = res.record;
10147
10148 final long origId = Binder.clearCallingIdentity();
10149
10150 if (unscheduleServiceRestartLocked(s)) {
10151 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10152 + s.shortName);
10153 }
10154
10155 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10156 ConnectionRecord c = new ConnectionRecord(b, activity,
10157 connection, flags);
10158
10159 IBinder binder = connection.asBinder();
10160 s.connections.put(binder, c);
10161 b.connections.add(c);
10162 if (activity != null) {
10163 if (activity.connections == null) {
10164 activity.connections = new HashSet<ConnectionRecord>();
10165 }
10166 activity.connections.add(c);
10167 }
10168 b.client.connections.add(c);
10169 mServiceConnections.put(binder, c);
10170
10171 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10172 s.lastActivity = SystemClock.uptimeMillis();
10173 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10174 return 0;
10175 }
10176 }
10177
10178 if (s.app != null) {
10179 // This could have made the service more important.
10180 updateOomAdjLocked(s.app);
10181 }
10182
10183 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10184 + ": received=" + b.intent.received
10185 + " apps=" + b.intent.apps.size()
10186 + " doRebind=" + b.intent.doRebind);
10187
10188 if (s.app != null && b.intent.received) {
10189 // Service is already running, so we can immediately
10190 // publish the connection.
10191 try {
10192 c.conn.connected(s.name, b.intent.binder);
10193 } catch (Exception e) {
10194 Log.w(TAG, "Failure sending service " + s.shortName
10195 + " to connection " + c.conn.asBinder()
10196 + " (in " + c.binding.client.processName + ")", e);
10197 }
10198
10199 // If this is the first app connected back to this binding,
10200 // and the service had previously asked to be told when
10201 // rebound, then do so.
10202 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10203 requestServiceBindingLocked(s, b.intent, true);
10204 }
10205 } else if (!b.intent.requested) {
10206 requestServiceBindingLocked(s, b.intent, false);
10207 }
10208
10209 Binder.restoreCallingIdentity(origId);
10210 }
10211
10212 return 1;
10213 }
10214
10215 private void removeConnectionLocked(
10216 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10217 IBinder binder = c.conn.asBinder();
10218 AppBindRecord b = c.binding;
10219 ServiceRecord s = b.service;
10220 s.connections.remove(binder);
10221 b.connections.remove(c);
10222 if (c.activity != null && c.activity != skipAct) {
10223 if (c.activity.connections != null) {
10224 c.activity.connections.remove(c);
10225 }
10226 }
10227 if (b.client != skipApp) {
10228 b.client.connections.remove(c);
10229 }
10230 mServiceConnections.remove(binder);
10231
10232 if (b.connections.size() == 0) {
10233 b.intent.apps.remove(b.client);
10234 }
10235
10236 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10237 + ": shouldUnbind=" + b.intent.hasBound);
10238 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10239 && b.intent.hasBound) {
10240 try {
10241 bumpServiceExecutingLocked(s);
10242 updateOomAdjLocked(s.app);
10243 b.intent.hasBound = false;
10244 // Assume the client doesn't want to know about a rebind;
10245 // we will deal with that later if it asks for one.
10246 b.intent.doRebind = false;
10247 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10248 } catch (Exception e) {
10249 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10250 serviceDoneExecutingLocked(s, true);
10251 }
10252 }
10253
10254 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10255 bringDownServiceLocked(s, false);
10256 }
10257 }
10258
10259 public boolean unbindService(IServiceConnection connection) {
10260 synchronized (this) {
10261 IBinder binder = connection.asBinder();
10262 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10263 ConnectionRecord r = mServiceConnections.get(binder);
10264 if (r == null) {
10265 Log.w(TAG, "Unbind failed: could not find connection for "
10266 + connection.asBinder());
10267 return false;
10268 }
10269
10270 final long origId = Binder.clearCallingIdentity();
10271
10272 removeConnectionLocked(r, null, null);
10273
10274 if (r.binding.service.app != null) {
10275 // This could have made the service less important.
10276 updateOomAdjLocked(r.binding.service.app);
10277 }
10278
10279 Binder.restoreCallingIdentity(origId);
10280 }
10281
10282 return true;
10283 }
10284
10285 public void publishService(IBinder token, Intent intent, IBinder service) {
10286 // Refuse possible leaked file descriptors
10287 if (intent != null && intent.hasFileDescriptors() == true) {
10288 throw new IllegalArgumentException("File descriptors passed in Intent");
10289 }
10290
10291 synchronized(this) {
10292 if (!(token instanceof ServiceRecord)) {
10293 throw new IllegalArgumentException("Invalid service token");
10294 }
10295 ServiceRecord r = (ServiceRecord)token;
10296
10297 final long origId = Binder.clearCallingIdentity();
10298
10299 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10300 + " " + intent + ": " + service);
10301 if (r != null) {
10302 Intent.FilterComparison filter
10303 = new Intent.FilterComparison(intent);
10304 IntentBindRecord b = r.bindings.get(filter);
10305 if (b != null && !b.received) {
10306 b.binder = service;
10307 b.requested = true;
10308 b.received = true;
10309 if (r.connections.size() > 0) {
10310 Iterator<ConnectionRecord> it
10311 = r.connections.values().iterator();
10312 while (it.hasNext()) {
10313 ConnectionRecord c = it.next();
10314 if (!filter.equals(c.binding.intent.intent)) {
10315 if (DEBUG_SERVICE) Log.v(
10316 TAG, "Not publishing to: " + c);
10317 if (DEBUG_SERVICE) Log.v(
10318 TAG, "Bound intent: " + c.binding.intent.intent);
10319 if (DEBUG_SERVICE) Log.v(
10320 TAG, "Published intent: " + intent);
10321 continue;
10322 }
10323 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10324 try {
10325 c.conn.connected(r.name, service);
10326 } catch (Exception e) {
10327 Log.w(TAG, "Failure sending service " + r.name +
10328 " to connection " + c.conn.asBinder() +
10329 " (in " + c.binding.client.processName + ")", e);
10330 }
10331 }
10332 }
10333 }
10334
10335 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10336
10337 Binder.restoreCallingIdentity(origId);
10338 }
10339 }
10340 }
10341
10342 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10343 // Refuse possible leaked file descriptors
10344 if (intent != null && intent.hasFileDescriptors() == true) {
10345 throw new IllegalArgumentException("File descriptors passed in Intent");
10346 }
10347
10348 synchronized(this) {
10349 if (!(token instanceof ServiceRecord)) {
10350 throw new IllegalArgumentException("Invalid service token");
10351 }
10352 ServiceRecord r = (ServiceRecord)token;
10353
10354 final long origId = Binder.clearCallingIdentity();
10355
10356 if (r != null) {
10357 Intent.FilterComparison filter
10358 = new Intent.FilterComparison(intent);
10359 IntentBindRecord b = r.bindings.get(filter);
10360 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10361 + " at " + b + ": apps="
10362 + (b != null ? b.apps.size() : 0));
10363 if (b != null) {
10364 if (b.apps.size() > 0) {
10365 // Applications have already bound since the last
10366 // unbind, so just rebind right here.
10367 requestServiceBindingLocked(r, b, true);
10368 } else {
10369 // Note to tell the service the next time there is
10370 // a new client.
10371 b.doRebind = true;
10372 }
10373 }
10374
10375 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10376
10377 Binder.restoreCallingIdentity(origId);
10378 }
10379 }
10380 }
10381
10382 public void serviceDoneExecuting(IBinder token) {
10383 synchronized(this) {
10384 if (!(token instanceof ServiceRecord)) {
10385 throw new IllegalArgumentException("Invalid service token");
10386 }
10387 ServiceRecord r = (ServiceRecord)token;
10388 boolean inStopping = mStoppingServices.contains(token);
10389 if (r != null) {
10390 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10391 + ": nesting=" + r.executeNesting
10392 + ", inStopping=" + inStopping);
10393 if (r != token) {
10394 Log.w(TAG, "Done executing service " + r.name
10395 + " with incorrect token: given " + token
10396 + ", expected " + r);
10397 return;
10398 }
10399
10400 final long origId = Binder.clearCallingIdentity();
10401 serviceDoneExecutingLocked(r, inStopping);
10402 Binder.restoreCallingIdentity(origId);
10403 } else {
10404 Log.w(TAG, "Done executing unknown service " + r.name
10405 + " with token " + token);
10406 }
10407 }
10408 }
10409
10410 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10411 r.executeNesting--;
10412 if (r.executeNesting <= 0 && r.app != null) {
10413 r.app.executingServices.remove(r);
10414 if (r.app.executingServices.size() == 0) {
10415 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10416 }
10417 if (inStopping) {
10418 mStoppingServices.remove(r);
10419 }
10420 updateOomAdjLocked(r.app);
10421 }
10422 }
10423
10424 void serviceTimeout(ProcessRecord proc) {
10425 synchronized(this) {
10426 if (proc.executingServices.size() == 0 || proc.thread == null) {
10427 return;
10428 }
10429 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10430 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10431 ServiceRecord timeout = null;
10432 long nextTime = 0;
10433 while (it.hasNext()) {
10434 ServiceRecord sr = it.next();
10435 if (sr.executingStart < maxTime) {
10436 timeout = sr;
10437 break;
10438 }
10439 if (sr.executingStart > nextTime) {
10440 nextTime = sr.executingStart;
10441 }
10442 }
10443 if (timeout != null && mLRUProcesses.contains(proc)) {
10444 Log.w(TAG, "Timeout executing service: " + timeout);
10445 appNotRespondingLocked(proc, null, "Executing service "
10446 + timeout.name);
10447 } else {
10448 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10449 msg.obj = proc;
10450 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10451 }
10452 }
10453 }
10454
10455 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010456 // BACKUP AND RESTORE
10457 // =========================================================
10458
10459 // Cause the target app to be launched if necessary and its backup agent
10460 // instantiated. The backup agent will invoke backupAgentCreated() on the
10461 // activity manager to announce its creation.
10462 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10463 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10464 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10465
10466 synchronized(this) {
10467 // !!! TODO: currently no check here that we're already bound
10468 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10469 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10470 synchronized (stats) {
10471 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10472 }
10473
10474 BackupRecord r = new BackupRecord(ss, app, backupMode);
10475 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10476 // startProcessLocked() returns existing proc's record if it's already running
10477 ProcessRecord proc = startProcessLocked(app.processName, app,
10478 false, 0, "backup", hostingName);
10479 if (proc == null) {
10480 Log.e(TAG, "Unable to start backup agent process " + r);
10481 return false;
10482 }
10483
10484 r.app = proc;
10485 mBackupTarget = r;
10486 mBackupAppName = app.packageName;
10487
Christopher Tate6fa95972009-06-05 18:43:55 -070010488 // Try not to kill the process during backup
10489 updateOomAdjLocked(proc);
10490
Christopher Tate181fafa2009-05-14 11:12:14 -070010491 // If the process is already attached, schedule the creation of the backup agent now.
10492 // If it is not yet live, this will be done when it attaches to the framework.
10493 if (proc.thread != null) {
10494 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10495 try {
10496 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10497 } catch (RemoteException e) {
10498 // !!! TODO: notify the backup manager that we crashed, or rely on
10499 // death notices, or...?
10500 }
10501 } else {
10502 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10503 }
10504 // Invariants: at this point, the target app process exists and the application
10505 // is either already running or in the process of coming up. mBackupTarget and
10506 // mBackupAppName describe the app, so that when it binds back to the AM we
10507 // know that it's scheduled for a backup-agent operation.
10508 }
10509
10510 return true;
10511 }
10512
10513 // A backup agent has just come up
10514 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10515 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10516 + " = " + agent);
10517
10518 synchronized(this) {
10519 if (!agentPackageName.equals(mBackupAppName)) {
10520 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10521 return;
10522 }
10523
Christopher Tate043dadc2009-06-02 16:11:00 -070010524 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010525 try {
10526 IBackupManager bm = IBackupManager.Stub.asInterface(
10527 ServiceManager.getService(Context.BACKUP_SERVICE));
10528 bm.agentConnected(agentPackageName, agent);
10529 } catch (RemoteException e) {
10530 // can't happen; the backup manager service is local
10531 } catch (Exception e) {
10532 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10533 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010534 } finally {
10535 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010536 }
10537 }
10538 }
10539
10540 // done with this agent
10541 public void unbindBackupAgent(ApplicationInfo appInfo) {
10542 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010543 if (appInfo == null) {
10544 Log.w(TAG, "unbind backup agent for null app");
10545 return;
10546 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010547
10548 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010549 if (mBackupAppName == null) {
10550 Log.w(TAG, "Unbinding backup agent with no active backup");
10551 return;
10552 }
10553
Christopher Tate181fafa2009-05-14 11:12:14 -070010554 if (!mBackupAppName.equals(appInfo.packageName)) {
10555 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10556 return;
10557 }
10558
Christopher Tate6fa95972009-06-05 18:43:55 -070010559 ProcessRecord proc = mBackupTarget.app;
10560 mBackupTarget = null;
10561 mBackupAppName = null;
10562
10563 // Not backing this app up any more; reset its OOM adjustment
10564 updateOomAdjLocked(proc);
10565
Christopher Tatec7b31e32009-06-10 15:49:30 -070010566 // If the app crashed during backup, 'thread' will be null here
10567 if (proc.thread != null) {
10568 try {
10569 proc.thread.scheduleDestroyBackupAgent(appInfo);
10570 } catch (Exception e) {
10571 Log.e(TAG, "Exception when unbinding backup agent:");
10572 e.printStackTrace();
10573 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010574 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010575 }
10576 }
10577 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010578 // BROADCASTS
10579 // =========================================================
10580
10581 private final List getStickies(String action, IntentFilter filter,
10582 List cur) {
10583 final ContentResolver resolver = mContext.getContentResolver();
10584 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10585 if (list == null) {
10586 return cur;
10587 }
10588 int N = list.size();
10589 for (int i=0; i<N; i++) {
10590 Intent intent = list.get(i);
10591 if (filter.match(resolver, intent, true, TAG) >= 0) {
10592 if (cur == null) {
10593 cur = new ArrayList<Intent>();
10594 }
10595 cur.add(intent);
10596 }
10597 }
10598 return cur;
10599 }
10600
10601 private final void scheduleBroadcastsLocked() {
10602 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10603 + mBroadcastsScheduled);
10604
10605 if (mBroadcastsScheduled) {
10606 return;
10607 }
10608 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10609 mBroadcastsScheduled = true;
10610 }
10611
10612 public Intent registerReceiver(IApplicationThread caller,
10613 IIntentReceiver receiver, IntentFilter filter, String permission) {
10614 synchronized(this) {
10615 ProcessRecord callerApp = null;
10616 if (caller != null) {
10617 callerApp = getRecordForAppLocked(caller);
10618 if (callerApp == null) {
10619 throw new SecurityException(
10620 "Unable to find app for caller " + caller
10621 + " (pid=" + Binder.getCallingPid()
10622 + ") when registering receiver " + receiver);
10623 }
10624 }
10625
10626 List allSticky = null;
10627
10628 // Look for any matching sticky broadcasts...
10629 Iterator actions = filter.actionsIterator();
10630 if (actions != null) {
10631 while (actions.hasNext()) {
10632 String action = (String)actions.next();
10633 allSticky = getStickies(action, filter, allSticky);
10634 }
10635 } else {
10636 allSticky = getStickies(null, filter, allSticky);
10637 }
10638
10639 // The first sticky in the list is returned directly back to
10640 // the client.
10641 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10642
10643 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10644 + ": " + sticky);
10645
10646 if (receiver == null) {
10647 return sticky;
10648 }
10649
10650 ReceiverList rl
10651 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10652 if (rl == null) {
10653 rl = new ReceiverList(this, callerApp,
10654 Binder.getCallingPid(),
10655 Binder.getCallingUid(), receiver);
10656 if (rl.app != null) {
10657 rl.app.receivers.add(rl);
10658 } else {
10659 try {
10660 receiver.asBinder().linkToDeath(rl, 0);
10661 } catch (RemoteException e) {
10662 return sticky;
10663 }
10664 rl.linkedToDeath = true;
10665 }
10666 mRegisteredReceivers.put(receiver.asBinder(), rl);
10667 }
10668 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10669 rl.add(bf);
10670 if (!bf.debugCheck()) {
10671 Log.w(TAG, "==> For Dynamic broadast");
10672 }
10673 mReceiverResolver.addFilter(bf);
10674
10675 // Enqueue broadcasts for all existing stickies that match
10676 // this filter.
10677 if (allSticky != null) {
10678 ArrayList receivers = new ArrayList();
10679 receivers.add(bf);
10680
10681 int N = allSticky.size();
10682 for (int i=0; i<N; i++) {
10683 Intent intent = (Intent)allSticky.get(i);
10684 BroadcastRecord r = new BroadcastRecord(intent, null,
10685 null, -1, -1, null, receivers, null, 0, null, null,
10686 false);
10687 if (mParallelBroadcasts.size() == 0) {
10688 scheduleBroadcastsLocked();
10689 }
10690 mParallelBroadcasts.add(r);
10691 }
10692 }
10693
10694 return sticky;
10695 }
10696 }
10697
10698 public void unregisterReceiver(IIntentReceiver receiver) {
10699 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10700
10701 boolean doNext = false;
10702
10703 synchronized(this) {
10704 ReceiverList rl
10705 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10706 if (rl != null) {
10707 if (rl.curBroadcast != null) {
10708 BroadcastRecord r = rl.curBroadcast;
10709 doNext = finishReceiverLocked(
10710 receiver.asBinder(), r.resultCode, r.resultData,
10711 r.resultExtras, r.resultAbort, true);
10712 }
10713
10714 if (rl.app != null) {
10715 rl.app.receivers.remove(rl);
10716 }
10717 removeReceiverLocked(rl);
10718 if (rl.linkedToDeath) {
10719 rl.linkedToDeath = false;
10720 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10721 }
10722 }
10723 }
10724
10725 if (!doNext) {
10726 return;
10727 }
10728
10729 final long origId = Binder.clearCallingIdentity();
10730 processNextBroadcast(false);
10731 trimApplications();
10732 Binder.restoreCallingIdentity(origId);
10733 }
10734
10735 void removeReceiverLocked(ReceiverList rl) {
10736 mRegisteredReceivers.remove(rl.receiver.asBinder());
10737 int N = rl.size();
10738 for (int i=0; i<N; i++) {
10739 mReceiverResolver.removeFilter(rl.get(i));
10740 }
10741 }
10742
10743 private final int broadcastIntentLocked(ProcessRecord callerApp,
10744 String callerPackage, Intent intent, String resolvedType,
10745 IIntentReceiver resultTo, int resultCode, String resultData,
10746 Bundle map, String requiredPermission,
10747 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10748 intent = new Intent(intent);
10749
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010750 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010751 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10752 + " ordered=" + ordered);
10753 if ((resultTo != null) && !ordered) {
10754 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10755 }
10756
10757 // Handle special intents: if this broadcast is from the package
10758 // manager about a package being removed, we need to remove all of
10759 // its activities from the history stack.
10760 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10761 intent.getAction());
10762 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10763 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10764 || uidRemoved) {
10765 if (checkComponentPermission(
10766 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10767 callingPid, callingUid, -1)
10768 == PackageManager.PERMISSION_GRANTED) {
10769 if (uidRemoved) {
10770 final Bundle intentExtras = intent.getExtras();
10771 final int uid = intentExtras != null
10772 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10773 if (uid >= 0) {
10774 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10775 synchronized (bs) {
10776 bs.removeUidStatsLocked(uid);
10777 }
10778 }
10779 } else {
10780 Uri data = intent.getData();
10781 String ssp;
10782 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10783 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10784 uninstallPackageLocked(ssp,
10785 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010786 AttributeCache ac = AttributeCache.instance();
10787 if (ac != null) {
10788 ac.removePackage(ssp);
10789 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010790 }
10791 }
10792 }
10793 } else {
10794 String msg = "Permission Denial: " + intent.getAction()
10795 + " broadcast from " + callerPackage + " (pid=" + callingPid
10796 + ", uid=" + callingUid + ")"
10797 + " requires "
10798 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10799 Log.w(TAG, msg);
10800 throw new SecurityException(msg);
10801 }
10802 }
10803
10804 /*
10805 * If this is the time zone changed action, queue up a message that will reset the timezone
10806 * of all currently running processes. This message will get queued up before the broadcast
10807 * happens.
10808 */
10809 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10810 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10811 }
10812
10813 // Add to the sticky list if requested.
10814 if (sticky) {
10815 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10816 callingPid, callingUid)
10817 != PackageManager.PERMISSION_GRANTED) {
10818 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10819 + callingPid + ", uid=" + callingUid
10820 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10821 Log.w(TAG, msg);
10822 throw new SecurityException(msg);
10823 }
10824 if (requiredPermission != null) {
10825 Log.w(TAG, "Can't broadcast sticky intent " + intent
10826 + " and enforce permission " + requiredPermission);
10827 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10828 }
10829 if (intent.getComponent() != null) {
10830 throw new SecurityException(
10831 "Sticky broadcasts can't target a specific component");
10832 }
10833 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10834 if (list == null) {
10835 list = new ArrayList<Intent>();
10836 mStickyBroadcasts.put(intent.getAction(), list);
10837 }
10838 int N = list.size();
10839 int i;
10840 for (i=0; i<N; i++) {
10841 if (intent.filterEquals(list.get(i))) {
10842 // This sticky already exists, replace it.
10843 list.set(i, new Intent(intent));
10844 break;
10845 }
10846 }
10847 if (i >= N) {
10848 list.add(new Intent(intent));
10849 }
10850 }
10851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010852 // Figure out who all will receive this broadcast.
10853 List receivers = null;
10854 List<BroadcastFilter> registeredReceivers = null;
10855 try {
10856 if (intent.getComponent() != null) {
10857 // Broadcast is going to one specific receiver class...
10858 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010859 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010860 if (ai != null) {
10861 receivers = new ArrayList();
10862 ResolveInfo ri = new ResolveInfo();
10863 ri.activityInfo = ai;
10864 receivers.add(ri);
10865 }
10866 } else {
10867 // Need to resolve the intent to interested receivers...
10868 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10869 == 0) {
10870 receivers =
10871 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010872 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010873 }
Mihai Preda074edef2009-05-18 17:13:31 +020010874 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010875 }
10876 } catch (RemoteException ex) {
10877 // pm is in same process, this will never happen.
10878 }
10879
10880 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10881 if (!ordered && NR > 0) {
10882 // If we are not serializing this broadcast, then send the
10883 // registered receivers separately so they don't wait for the
10884 // components to be launched.
10885 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10886 callerPackage, callingPid, callingUid, requiredPermission,
10887 registeredReceivers, resultTo, resultCode, resultData, map,
10888 ordered);
10889 if (DEBUG_BROADCAST) Log.v(
10890 TAG, "Enqueueing parallel broadcast " + r
10891 + ": prev had " + mParallelBroadcasts.size());
10892 mParallelBroadcasts.add(r);
10893 scheduleBroadcastsLocked();
10894 registeredReceivers = null;
10895 NR = 0;
10896 }
10897
10898 // Merge into one list.
10899 int ir = 0;
10900 if (receivers != null) {
10901 // A special case for PACKAGE_ADDED: do not allow the package
10902 // being added to see this broadcast. This prevents them from
10903 // using this as a back door to get run as soon as they are
10904 // installed. Maybe in the future we want to have a special install
10905 // broadcast or such for apps, but we'd like to deliberately make
10906 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010907 boolean skip = false;
10908 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010909 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010910 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10911 skip = true;
10912 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10913 skip = true;
10914 }
10915 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010916 ? intent.getData().getSchemeSpecificPart()
10917 : null;
10918 if (skipPackage != null && receivers != null) {
10919 int NT = receivers.size();
10920 for (int it=0; it<NT; it++) {
10921 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10922 if (curt.activityInfo.packageName.equals(skipPackage)) {
10923 receivers.remove(it);
10924 it--;
10925 NT--;
10926 }
10927 }
10928 }
10929
10930 int NT = receivers != null ? receivers.size() : 0;
10931 int it = 0;
10932 ResolveInfo curt = null;
10933 BroadcastFilter curr = null;
10934 while (it < NT && ir < NR) {
10935 if (curt == null) {
10936 curt = (ResolveInfo)receivers.get(it);
10937 }
10938 if (curr == null) {
10939 curr = registeredReceivers.get(ir);
10940 }
10941 if (curr.getPriority() >= curt.priority) {
10942 // Insert this broadcast record into the final list.
10943 receivers.add(it, curr);
10944 ir++;
10945 curr = null;
10946 it++;
10947 NT++;
10948 } else {
10949 // Skip to the next ResolveInfo in the final list.
10950 it++;
10951 curt = null;
10952 }
10953 }
10954 }
10955 while (ir < NR) {
10956 if (receivers == null) {
10957 receivers = new ArrayList();
10958 }
10959 receivers.add(registeredReceivers.get(ir));
10960 ir++;
10961 }
10962
10963 if ((receivers != null && receivers.size() > 0)
10964 || resultTo != null) {
10965 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10966 callerPackage, callingPid, callingUid, requiredPermission,
10967 receivers, resultTo, resultCode, resultData, map, ordered);
10968 if (DEBUG_BROADCAST) Log.v(
10969 TAG, "Enqueueing ordered broadcast " + r
10970 + ": prev had " + mOrderedBroadcasts.size());
10971 if (DEBUG_BROADCAST) {
10972 int seq = r.intent.getIntExtra("seq", -1);
10973 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10974 }
10975 mOrderedBroadcasts.add(r);
10976 scheduleBroadcastsLocked();
10977 }
10978
10979 return BROADCAST_SUCCESS;
10980 }
10981
10982 public final int broadcastIntent(IApplicationThread caller,
10983 Intent intent, String resolvedType, IIntentReceiver resultTo,
10984 int resultCode, String resultData, Bundle map,
10985 String requiredPermission, boolean serialized, boolean sticky) {
10986 // Refuse possible leaked file descriptors
10987 if (intent != null && intent.hasFileDescriptors() == true) {
10988 throw new IllegalArgumentException("File descriptors passed in Intent");
10989 }
10990
10991 synchronized(this) {
10992 if (!mSystemReady) {
10993 // if the caller really truly claims to know what they're doing, go
10994 // ahead and allow the broadcast without launching any receivers
10995 int flags = intent.getFlags();
10996 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10997 intent = new Intent(intent);
10998 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10999 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11000 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11001 + " before boot completion");
11002 throw new IllegalStateException("Cannot broadcast before boot completed");
11003 }
11004 }
11005
11006 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11007 final int callingPid = Binder.getCallingPid();
11008 final int callingUid = Binder.getCallingUid();
11009 final long origId = Binder.clearCallingIdentity();
11010 int res = broadcastIntentLocked(callerApp,
11011 callerApp != null ? callerApp.info.packageName : null,
11012 intent, resolvedType, resultTo,
11013 resultCode, resultData, map, requiredPermission, serialized,
11014 sticky, callingPid, callingUid);
11015 Binder.restoreCallingIdentity(origId);
11016 return res;
11017 }
11018 }
11019
11020 int broadcastIntentInPackage(String packageName, int uid,
11021 Intent intent, String resolvedType, IIntentReceiver resultTo,
11022 int resultCode, String resultData, Bundle map,
11023 String requiredPermission, boolean serialized, boolean sticky) {
11024 synchronized(this) {
11025 final long origId = Binder.clearCallingIdentity();
11026 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11027 resultTo, resultCode, resultData, map, requiredPermission,
11028 serialized, sticky, -1, uid);
11029 Binder.restoreCallingIdentity(origId);
11030 return res;
11031 }
11032 }
11033
11034 public final void unbroadcastIntent(IApplicationThread caller,
11035 Intent intent) {
11036 // Refuse possible leaked file descriptors
11037 if (intent != null && intent.hasFileDescriptors() == true) {
11038 throw new IllegalArgumentException("File descriptors passed in Intent");
11039 }
11040
11041 synchronized(this) {
11042 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11043 != PackageManager.PERMISSION_GRANTED) {
11044 String msg = "Permission Denial: unbroadcastIntent() from pid="
11045 + Binder.getCallingPid()
11046 + ", uid=" + Binder.getCallingUid()
11047 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11048 Log.w(TAG, msg);
11049 throw new SecurityException(msg);
11050 }
11051 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11052 if (list != null) {
11053 int N = list.size();
11054 int i;
11055 for (i=0; i<N; i++) {
11056 if (intent.filterEquals(list.get(i))) {
11057 list.remove(i);
11058 break;
11059 }
11060 }
11061 }
11062 }
11063 }
11064
11065 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11066 String resultData, Bundle resultExtras, boolean resultAbort,
11067 boolean explicit) {
11068 if (mOrderedBroadcasts.size() == 0) {
11069 if (explicit) {
11070 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11071 }
11072 return false;
11073 }
11074 BroadcastRecord r = mOrderedBroadcasts.get(0);
11075 if (r.receiver == null) {
11076 if (explicit) {
11077 Log.w(TAG, "finishReceiver called but none active");
11078 }
11079 return false;
11080 }
11081 if (r.receiver != receiver) {
11082 Log.w(TAG, "finishReceiver called but active receiver is different");
11083 return false;
11084 }
11085 int state = r.state;
11086 r.state = r.IDLE;
11087 if (state == r.IDLE) {
11088 if (explicit) {
11089 Log.w(TAG, "finishReceiver called but state is IDLE");
11090 }
11091 }
11092 r.receiver = null;
11093 r.intent.setComponent(null);
11094 if (r.curApp != null) {
11095 r.curApp.curReceiver = null;
11096 }
11097 if (r.curFilter != null) {
11098 r.curFilter.receiverList.curBroadcast = null;
11099 }
11100 r.curFilter = null;
11101 r.curApp = null;
11102 r.curComponent = null;
11103 r.curReceiver = null;
11104 mPendingBroadcast = null;
11105
11106 r.resultCode = resultCode;
11107 r.resultData = resultData;
11108 r.resultExtras = resultExtras;
11109 r.resultAbort = resultAbort;
11110
11111 // We will process the next receiver right now if this is finishing
11112 // an app receiver (which is always asynchronous) or after we have
11113 // come back from calling a receiver.
11114 return state == BroadcastRecord.APP_RECEIVE
11115 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11116 }
11117
11118 public void finishReceiver(IBinder who, int resultCode, String resultData,
11119 Bundle resultExtras, boolean resultAbort) {
11120 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11121
11122 // Refuse possible leaked file descriptors
11123 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11124 throw new IllegalArgumentException("File descriptors passed in Bundle");
11125 }
11126
11127 boolean doNext;
11128
11129 final long origId = Binder.clearCallingIdentity();
11130
11131 synchronized(this) {
11132 doNext = finishReceiverLocked(
11133 who, resultCode, resultData, resultExtras, resultAbort, true);
11134 }
11135
11136 if (doNext) {
11137 processNextBroadcast(false);
11138 }
11139 trimApplications();
11140
11141 Binder.restoreCallingIdentity(origId);
11142 }
11143
11144 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11145 if (r.nextReceiver > 0) {
11146 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11147 if (curReceiver instanceof BroadcastFilter) {
11148 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11149 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11150 System.identityHashCode(r),
11151 r.intent.getAction(),
11152 r.nextReceiver - 1,
11153 System.identityHashCode(bf));
11154 } else {
11155 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11156 System.identityHashCode(r),
11157 r.intent.getAction(),
11158 r.nextReceiver - 1,
11159 ((ResolveInfo)curReceiver).toString());
11160 }
11161 } else {
11162 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11163 + r);
11164 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11165 System.identityHashCode(r),
11166 r.intent.getAction(),
11167 r.nextReceiver,
11168 "NONE");
11169 }
11170 }
11171
11172 private final void broadcastTimeout() {
11173 synchronized (this) {
11174 if (mOrderedBroadcasts.size() == 0) {
11175 return;
11176 }
11177 long now = SystemClock.uptimeMillis();
11178 BroadcastRecord r = mOrderedBroadcasts.get(0);
11179 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11180 if (DEBUG_BROADCAST) Log.v(TAG,
11181 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11182 + (r.startTime + BROADCAST_TIMEOUT));
11183 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11184 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11185 return;
11186 }
11187
11188 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11189 r.startTime = now;
11190 r.anrCount++;
11191
11192 // Current receiver has passed its expiration date.
11193 if (r.nextReceiver <= 0) {
11194 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11195 return;
11196 }
11197
11198 ProcessRecord app = null;
11199
11200 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11201 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11202 logBroadcastReceiverDiscard(r);
11203 if (curReceiver instanceof BroadcastFilter) {
11204 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11205 if (bf.receiverList.pid != 0
11206 && bf.receiverList.pid != MY_PID) {
11207 synchronized (this.mPidsSelfLocked) {
11208 app = this.mPidsSelfLocked.get(
11209 bf.receiverList.pid);
11210 }
11211 }
11212 } else {
11213 app = r.curApp;
11214 }
11215
11216 if (app != null) {
11217 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11218 }
11219
11220 if (mPendingBroadcast == r) {
11221 mPendingBroadcast = null;
11222 }
11223
11224 // Move on to the next receiver.
11225 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11226 r.resultExtras, r.resultAbort, true);
11227 scheduleBroadcastsLocked();
11228 }
11229 }
11230
11231 private final void processCurBroadcastLocked(BroadcastRecord r,
11232 ProcessRecord app) throws RemoteException {
11233 if (app.thread == null) {
11234 throw new RemoteException();
11235 }
11236 r.receiver = app.thread.asBinder();
11237 r.curApp = app;
11238 app.curReceiver = r;
11239 updateLRUListLocked(app, true);
11240
11241 // Tell the application to launch this receiver.
11242 r.intent.setComponent(r.curComponent);
11243
11244 boolean started = false;
11245 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011246 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011247 "Delivering to component " + r.curComponent
11248 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011249 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011250 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11251 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11252 started = true;
11253 } finally {
11254 if (!started) {
11255 r.receiver = null;
11256 r.curApp = null;
11257 app.curReceiver = null;
11258 }
11259 }
11260
11261 }
11262
11263 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11264 Intent intent, int resultCode, String data,
11265 Bundle extras, boolean ordered) throws RemoteException {
11266 if (app != null && app.thread != null) {
11267 // If we have an app thread, do the call through that so it is
11268 // correctly ordered with other one-way calls.
11269 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11270 data, extras, ordered);
11271 } else {
11272 receiver.performReceive(intent, resultCode, data, extras, ordered);
11273 }
11274 }
11275
11276 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11277 BroadcastFilter filter, boolean ordered) {
11278 boolean skip = false;
11279 if (filter.requiredPermission != null) {
11280 int perm = checkComponentPermission(filter.requiredPermission,
11281 r.callingPid, r.callingUid, -1);
11282 if (perm != PackageManager.PERMISSION_GRANTED) {
11283 Log.w(TAG, "Permission Denial: broadcasting "
11284 + r.intent.toString()
11285 + " from " + r.callerPackage + " (pid="
11286 + r.callingPid + ", uid=" + r.callingUid + ")"
11287 + " requires " + filter.requiredPermission
11288 + " due to registered receiver " + filter);
11289 skip = true;
11290 }
11291 }
11292 if (r.requiredPermission != null) {
11293 int perm = checkComponentPermission(r.requiredPermission,
11294 filter.receiverList.pid, filter.receiverList.uid, -1);
11295 if (perm != PackageManager.PERMISSION_GRANTED) {
11296 Log.w(TAG, "Permission Denial: receiving "
11297 + r.intent.toString()
11298 + " to " + filter.receiverList.app
11299 + " (pid=" + filter.receiverList.pid
11300 + ", uid=" + filter.receiverList.uid + ")"
11301 + " requires " + r.requiredPermission
11302 + " due to sender " + r.callerPackage
11303 + " (uid " + r.callingUid + ")");
11304 skip = true;
11305 }
11306 }
11307
11308 if (!skip) {
11309 // If this is not being sent as an ordered broadcast, then we
11310 // don't want to touch the fields that keep track of the current
11311 // state of ordered broadcasts.
11312 if (ordered) {
11313 r.receiver = filter.receiverList.receiver.asBinder();
11314 r.curFilter = filter;
11315 filter.receiverList.curBroadcast = r;
11316 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011317 if (filter.receiverList.app != null) {
11318 // Bump hosting application to no longer be in background
11319 // scheduling class. Note that we can't do that if there
11320 // isn't an app... but we can only be in that case for
11321 // things that directly call the IActivityManager API, which
11322 // are already core system stuff so don't matter for this.
11323 r.curApp = filter.receiverList.app;
11324 filter.receiverList.app.curReceiver = r;
11325 updateOomAdjLocked();
11326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011327 }
11328 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011329 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011330 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011331 Log.i(TAG, "Delivering to " + filter.receiverList.app
11332 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011333 }
11334 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11335 new Intent(r.intent), r.resultCode,
11336 r.resultData, r.resultExtras, r.ordered);
11337 if (ordered) {
11338 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11339 }
11340 } catch (RemoteException e) {
11341 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11342 if (ordered) {
11343 r.receiver = null;
11344 r.curFilter = null;
11345 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011346 if (filter.receiverList.app != null) {
11347 filter.receiverList.app.curReceiver = null;
11348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011349 }
11350 }
11351 }
11352 }
11353
11354 private final void processNextBroadcast(boolean fromMsg) {
11355 synchronized(this) {
11356 BroadcastRecord r;
11357
11358 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11359 + mParallelBroadcasts.size() + " broadcasts, "
11360 + mOrderedBroadcasts.size() + " serialized broadcasts");
11361
11362 updateCpuStats();
11363
11364 if (fromMsg) {
11365 mBroadcastsScheduled = false;
11366 }
11367
11368 // First, deliver any non-serialized broadcasts right away.
11369 while (mParallelBroadcasts.size() > 0) {
11370 r = mParallelBroadcasts.remove(0);
11371 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011372 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11373 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011374 for (int i=0; i<N; i++) {
11375 Object target = r.receivers.get(i);
11376 if (DEBUG_BROADCAST) Log.v(TAG,
11377 "Delivering non-serialized to registered "
11378 + target + ": " + r);
11379 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11380 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011381 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11382 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011383 }
11384
11385 // Now take care of the next serialized one...
11386
11387 // If we are waiting for a process to come up to handle the next
11388 // broadcast, then do nothing at this point. Just in case, we
11389 // check that the process we're waiting for still exists.
11390 if (mPendingBroadcast != null) {
11391 Log.i(TAG, "processNextBroadcast: waiting for "
11392 + mPendingBroadcast.curApp);
11393
11394 boolean isDead;
11395 synchronized (mPidsSelfLocked) {
11396 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11397 }
11398 if (!isDead) {
11399 // It's still alive, so keep waiting
11400 return;
11401 } else {
11402 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11403 + " died before responding to broadcast");
11404 mPendingBroadcast = null;
11405 }
11406 }
11407
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011408 boolean looped = false;
11409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011410 do {
11411 if (mOrderedBroadcasts.size() == 0) {
11412 // No more broadcasts pending, so all done!
11413 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011414 if (looped) {
11415 // If we had finished the last ordered broadcast, then
11416 // make sure all processes have correct oom and sched
11417 // adjustments.
11418 updateOomAdjLocked();
11419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011420 return;
11421 }
11422 r = mOrderedBroadcasts.get(0);
11423 boolean forceReceive = false;
11424
11425 // Ensure that even if something goes awry with the timeout
11426 // detection, we catch "hung" broadcasts here, discard them,
11427 // and continue to make progress.
11428 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11429 long now = SystemClock.uptimeMillis();
11430 if (r.dispatchTime > 0) {
11431 if ((numReceivers > 0) &&
11432 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11433 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11434 + " now=" + now
11435 + " dispatchTime=" + r.dispatchTime
11436 + " startTime=" + r.startTime
11437 + " intent=" + r.intent
11438 + " numReceivers=" + numReceivers
11439 + " nextReceiver=" + r.nextReceiver
11440 + " state=" + r.state);
11441 broadcastTimeout(); // forcibly finish this broadcast
11442 forceReceive = true;
11443 r.state = BroadcastRecord.IDLE;
11444 }
11445 }
11446
11447 if (r.state != BroadcastRecord.IDLE) {
11448 if (DEBUG_BROADCAST) Log.d(TAG,
11449 "processNextBroadcast() called when not idle (state="
11450 + r.state + ")");
11451 return;
11452 }
11453
11454 if (r.receivers == null || r.nextReceiver >= numReceivers
11455 || r.resultAbort || forceReceive) {
11456 // No more receivers for this broadcast! Send the final
11457 // result if requested...
11458 if (r.resultTo != null) {
11459 try {
11460 if (DEBUG_BROADCAST) {
11461 int seq = r.intent.getIntExtra("seq", -1);
11462 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11463 + " seq=" + seq + " app=" + r.callerApp);
11464 }
11465 performReceive(r.callerApp, r.resultTo,
11466 new Intent(r.intent), r.resultCode,
11467 r.resultData, r.resultExtras, false);
11468 } catch (RemoteException e) {
11469 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11470 }
11471 }
11472
11473 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11474 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11475
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011476 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11477 + r);
11478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011479 // ... and on to the next...
11480 mOrderedBroadcasts.remove(0);
11481 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011482 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011483 continue;
11484 }
11485 } while (r == null);
11486
11487 // Get the next receiver...
11488 int recIdx = r.nextReceiver++;
11489
11490 // Keep track of when this receiver started, and make sure there
11491 // is a timeout message pending to kill it if need be.
11492 r.startTime = SystemClock.uptimeMillis();
11493 if (recIdx == 0) {
11494 r.dispatchTime = r.startTime;
11495
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011496 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11497 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011498 if (DEBUG_BROADCAST) Log.v(TAG,
11499 "Submitting 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 }
11504
11505 Object nextReceiver = r.receivers.get(recIdx);
11506 if (nextReceiver instanceof BroadcastFilter) {
11507 // Simple case: this is a registered receiver who gets
11508 // a direct call.
11509 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11510 if (DEBUG_BROADCAST) Log.v(TAG,
11511 "Delivering serialized to registered "
11512 + filter + ": " + r);
11513 deliverToRegisteredReceiver(r, filter, r.ordered);
11514 if (r.receiver == null || !r.ordered) {
11515 // The receiver has already finished, so schedule to
11516 // process the next one.
11517 r.state = BroadcastRecord.IDLE;
11518 scheduleBroadcastsLocked();
11519 }
11520 return;
11521 }
11522
11523 // Hard case: need to instantiate the receiver, possibly
11524 // starting its application process to host it.
11525
11526 ResolveInfo info =
11527 (ResolveInfo)nextReceiver;
11528
11529 boolean skip = false;
11530 int perm = checkComponentPermission(info.activityInfo.permission,
11531 r.callingPid, r.callingUid,
11532 info.activityInfo.exported
11533 ? -1 : info.activityInfo.applicationInfo.uid);
11534 if (perm != PackageManager.PERMISSION_GRANTED) {
11535 Log.w(TAG, "Permission Denial: broadcasting "
11536 + r.intent.toString()
11537 + " from " + r.callerPackage + " (pid=" + r.callingPid
11538 + ", uid=" + r.callingUid + ")"
11539 + " requires " + info.activityInfo.permission
11540 + " due to receiver " + info.activityInfo.packageName
11541 + "/" + info.activityInfo.name);
11542 skip = true;
11543 }
11544 if (r.callingUid != Process.SYSTEM_UID &&
11545 r.requiredPermission != null) {
11546 try {
11547 perm = ActivityThread.getPackageManager().
11548 checkPermission(r.requiredPermission,
11549 info.activityInfo.applicationInfo.packageName);
11550 } catch (RemoteException e) {
11551 perm = PackageManager.PERMISSION_DENIED;
11552 }
11553 if (perm != PackageManager.PERMISSION_GRANTED) {
11554 Log.w(TAG, "Permission Denial: receiving "
11555 + r.intent + " to "
11556 + info.activityInfo.applicationInfo.packageName
11557 + " requires " + r.requiredPermission
11558 + " due to sender " + r.callerPackage
11559 + " (uid " + r.callingUid + ")");
11560 skip = true;
11561 }
11562 }
11563 if (r.curApp != null && r.curApp.crashing) {
11564 // If the target process is crashing, just skip it.
11565 skip = true;
11566 }
11567
11568 if (skip) {
11569 r.receiver = null;
11570 r.curFilter = null;
11571 r.state = BroadcastRecord.IDLE;
11572 scheduleBroadcastsLocked();
11573 return;
11574 }
11575
11576 r.state = BroadcastRecord.APP_RECEIVE;
11577 String targetProcess = info.activityInfo.processName;
11578 r.curComponent = new ComponentName(
11579 info.activityInfo.applicationInfo.packageName,
11580 info.activityInfo.name);
11581 r.curReceiver = info.activityInfo;
11582
11583 // Is this receiver's application already running?
11584 ProcessRecord app = getProcessRecordLocked(targetProcess,
11585 info.activityInfo.applicationInfo.uid);
11586 if (app != null && app.thread != null) {
11587 try {
11588 processCurBroadcastLocked(r, app);
11589 return;
11590 } catch (RemoteException e) {
11591 Log.w(TAG, "Exception when sending broadcast to "
11592 + r.curComponent, e);
11593 }
11594
11595 // If a dead object exception was thrown -- fall through to
11596 // restart the application.
11597 }
11598
11599 // Not running -- get it started, and enqueue this history record
11600 // to be executed when the app comes up.
11601 if ((r.curApp=startProcessLocked(targetProcess,
11602 info.activityInfo.applicationInfo, true,
11603 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11604 "broadcast", r.curComponent)) == null) {
11605 // Ah, this recipient is unavailable. Finish it if necessary,
11606 // and mark the broadcast record as ready for the next.
11607 Log.w(TAG, "Unable to launch app "
11608 + info.activityInfo.applicationInfo.packageName + "/"
11609 + info.activityInfo.applicationInfo.uid + " for broadcast "
11610 + r.intent + ": process is bad");
11611 logBroadcastReceiverDiscard(r);
11612 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11613 r.resultExtras, r.resultAbort, true);
11614 scheduleBroadcastsLocked();
11615 r.state = BroadcastRecord.IDLE;
11616 return;
11617 }
11618
11619 mPendingBroadcast = r;
11620 }
11621 }
11622
11623 // =========================================================
11624 // INSTRUMENTATION
11625 // =========================================================
11626
11627 public boolean startInstrumentation(ComponentName className,
11628 String profileFile, int flags, Bundle arguments,
11629 IInstrumentationWatcher watcher) {
11630 // Refuse possible leaked file descriptors
11631 if (arguments != null && arguments.hasFileDescriptors()) {
11632 throw new IllegalArgumentException("File descriptors passed in Bundle");
11633 }
11634
11635 synchronized(this) {
11636 InstrumentationInfo ii = null;
11637 ApplicationInfo ai = null;
11638 try {
11639 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011640 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011641 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011642 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011643 } catch (PackageManager.NameNotFoundException e) {
11644 }
11645 if (ii == null) {
11646 reportStartInstrumentationFailure(watcher, className,
11647 "Unable to find instrumentation info for: " + className);
11648 return false;
11649 }
11650 if (ai == null) {
11651 reportStartInstrumentationFailure(watcher, className,
11652 "Unable to find instrumentation target package: " + ii.targetPackage);
11653 return false;
11654 }
11655
11656 int match = mContext.getPackageManager().checkSignatures(
11657 ii.targetPackage, ii.packageName);
11658 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11659 String msg = "Permission Denial: starting instrumentation "
11660 + className + " from pid="
11661 + Binder.getCallingPid()
11662 + ", uid=" + Binder.getCallingPid()
11663 + " not allowed because package " + ii.packageName
11664 + " does not have a signature matching the target "
11665 + ii.targetPackage;
11666 reportStartInstrumentationFailure(watcher, className, msg);
11667 throw new SecurityException(msg);
11668 }
11669
11670 final long origId = Binder.clearCallingIdentity();
11671 uninstallPackageLocked(ii.targetPackage, -1, true);
11672 ProcessRecord app = addAppLocked(ai);
11673 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011674 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011675 app.instrumentationProfileFile = profileFile;
11676 app.instrumentationArguments = arguments;
11677 app.instrumentationWatcher = watcher;
11678 app.instrumentationResultClass = className;
11679 Binder.restoreCallingIdentity(origId);
11680 }
11681
11682 return true;
11683 }
11684
11685 /**
11686 * Report errors that occur while attempting to start Instrumentation. Always writes the
11687 * error to the logs, but if somebody is watching, send the report there too. This enables
11688 * the "am" command to report errors with more information.
11689 *
11690 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11691 * @param cn The component name of the instrumentation.
11692 * @param report The error report.
11693 */
11694 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11695 ComponentName cn, String report) {
11696 Log.w(TAG, report);
11697 try {
11698 if (watcher != null) {
11699 Bundle results = new Bundle();
11700 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11701 results.putString("Error", report);
11702 watcher.instrumentationStatus(cn, -1, results);
11703 }
11704 } catch (RemoteException e) {
11705 Log.w(TAG, e);
11706 }
11707 }
11708
11709 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11710 if (app.instrumentationWatcher != null) {
11711 try {
11712 // NOTE: IInstrumentationWatcher *must* be oneway here
11713 app.instrumentationWatcher.instrumentationFinished(
11714 app.instrumentationClass,
11715 resultCode,
11716 results);
11717 } catch (RemoteException e) {
11718 }
11719 }
11720 app.instrumentationWatcher = null;
11721 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011722 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011723 app.instrumentationProfileFile = null;
11724 app.instrumentationArguments = null;
11725
11726 uninstallPackageLocked(app.processName, -1, false);
11727 }
11728
11729 public void finishInstrumentation(IApplicationThread target,
11730 int resultCode, Bundle results) {
11731 // Refuse possible leaked file descriptors
11732 if (results != null && results.hasFileDescriptors()) {
11733 throw new IllegalArgumentException("File descriptors passed in Intent");
11734 }
11735
11736 synchronized(this) {
11737 ProcessRecord app = getRecordForAppLocked(target);
11738 if (app == null) {
11739 Log.w(TAG, "finishInstrumentation: no app for " + target);
11740 return;
11741 }
11742 final long origId = Binder.clearCallingIdentity();
11743 finishInstrumentationLocked(app, resultCode, results);
11744 Binder.restoreCallingIdentity(origId);
11745 }
11746 }
11747
11748 // =========================================================
11749 // CONFIGURATION
11750 // =========================================================
11751
11752 public ConfigurationInfo getDeviceConfigurationInfo() {
11753 ConfigurationInfo config = new ConfigurationInfo();
11754 synchronized (this) {
11755 config.reqTouchScreen = mConfiguration.touchscreen;
11756 config.reqKeyboardType = mConfiguration.keyboard;
11757 config.reqNavigation = mConfiguration.navigation;
11758 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11759 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11760 }
11761 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11762 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11763 }
11764 }
11765 return config;
11766 }
11767
11768 public Configuration getConfiguration() {
11769 Configuration ci;
11770 synchronized(this) {
11771 ci = new Configuration(mConfiguration);
11772 }
11773 return ci;
11774 }
11775
11776 public void updateConfiguration(Configuration values) {
11777 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11778 "updateConfiguration()");
11779
11780 synchronized(this) {
11781 if (values == null && mWindowManager != null) {
11782 // sentinel: fetch the current configuration from the window manager
11783 values = mWindowManager.computeNewConfiguration();
11784 }
11785
11786 final long origId = Binder.clearCallingIdentity();
11787 updateConfigurationLocked(values, null);
11788 Binder.restoreCallingIdentity(origId);
11789 }
11790 }
11791
11792 /**
11793 * Do either or both things: (1) change the current configuration, and (2)
11794 * make sure the given activity is running with the (now) current
11795 * configuration. Returns true if the activity has been left running, or
11796 * false if <var>starting</var> is being destroyed to match the new
11797 * configuration.
11798 */
11799 public boolean updateConfigurationLocked(Configuration values,
11800 HistoryRecord starting) {
11801 int changes = 0;
11802
11803 boolean kept = true;
11804
11805 if (values != null) {
11806 Configuration newConfig = new Configuration(mConfiguration);
11807 changes = newConfig.updateFrom(values);
11808 if (changes != 0) {
11809 if (DEBUG_SWITCH) {
11810 Log.i(TAG, "Updating configuration to: " + values);
11811 }
11812
11813 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11814
11815 if (values.locale != null) {
11816 saveLocaleLocked(values.locale,
11817 !values.locale.equals(mConfiguration.locale),
11818 values.userSetLocale);
11819 }
11820
11821 mConfiguration = newConfig;
11822
11823 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11824 msg.obj = new Configuration(mConfiguration);
11825 mHandler.sendMessage(msg);
11826
11827 final int N = mLRUProcesses.size();
11828 for (int i=0; i<N; i++) {
11829 ProcessRecord app = mLRUProcesses.get(i);
11830 try {
11831 if (app.thread != null) {
11832 app.thread.scheduleConfigurationChanged(mConfiguration);
11833 }
11834 } catch (Exception e) {
11835 }
11836 }
11837 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11838 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11839 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011840
11841 AttributeCache ac = AttributeCache.instance();
11842 if (ac != null) {
11843 ac.updateConfiguration(mConfiguration);
11844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011845 }
11846 }
11847
11848 if (changes != 0 && starting == null) {
11849 // If the configuration changed, and the caller is not already
11850 // in the process of starting an activity, then find the top
11851 // activity to check if its configuration needs to change.
11852 starting = topRunningActivityLocked(null);
11853 }
11854
11855 if (starting != null) {
11856 kept = ensureActivityConfigurationLocked(starting, changes);
11857 if (kept) {
11858 // If this didn't result in the starting activity being
11859 // destroyed, then we need to make sure at this point that all
11860 // other activities are made visible.
11861 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11862 + ", ensuring others are correct.");
11863 ensureActivitiesVisibleLocked(starting, changes);
11864 }
11865 }
11866
11867 return kept;
11868 }
11869
11870 private final boolean relaunchActivityLocked(HistoryRecord r,
11871 int changes, boolean andResume) {
11872 List<ResultInfo> results = null;
11873 List<Intent> newIntents = null;
11874 if (andResume) {
11875 results = r.results;
11876 newIntents = r.newIntents;
11877 }
11878 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11879 + " with results=" + results + " newIntents=" + newIntents
11880 + " andResume=" + andResume);
11881 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11882 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11883 r.task.taskId, r.shortComponentName);
11884
11885 r.startFreezingScreenLocked(r.app, 0);
11886
11887 try {
11888 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11889 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11890 changes, !andResume);
11891 // Note: don't need to call pauseIfSleepingLocked() here, because
11892 // the caller will only pass in 'andResume' if this activity is
11893 // currently resumed, which implies we aren't sleeping.
11894 } catch (RemoteException e) {
11895 return false;
11896 }
11897
11898 if (andResume) {
11899 r.results = null;
11900 r.newIntents = null;
11901 }
11902
11903 return true;
11904 }
11905
11906 /**
11907 * Make sure the given activity matches the current configuration. Returns
11908 * false if the activity had to be destroyed. Returns true if the
11909 * configuration is the same, or the activity will remain running as-is
11910 * for whatever reason. Ensures the HistoryRecord is updated with the
11911 * correct configuration and all other bookkeeping is handled.
11912 */
11913 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11914 int globalChanges) {
11915 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11916
11917 // Short circuit: if the two configurations are the exact same
11918 // object (the common case), then there is nothing to do.
11919 Configuration newConfig = mConfiguration;
11920 if (r.configuration == newConfig) {
11921 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11922 return true;
11923 }
11924
11925 // We don't worry about activities that are finishing.
11926 if (r.finishing) {
11927 if (DEBUG_SWITCH) Log.i(TAG,
11928 "Configuration doesn't matter in finishing " + r);
11929 r.stopFreezingScreenLocked(false);
11930 return true;
11931 }
11932
11933 // Okay we now are going to make this activity have the new config.
11934 // But then we need to figure out how it needs to deal with that.
11935 Configuration oldConfig = r.configuration;
11936 r.configuration = newConfig;
11937
11938 // If the activity isn't currently running, just leave the new
11939 // configuration and it will pick that up next time it starts.
11940 if (r.app == null || r.app.thread == null) {
11941 if (DEBUG_SWITCH) Log.i(TAG,
11942 "Configuration doesn't matter not running " + r);
11943 r.stopFreezingScreenLocked(false);
11944 return true;
11945 }
11946
11947 // If the activity isn't persistent, there is a chance we will
11948 // need to restart it.
11949 if (!r.persistent) {
11950
11951 // Figure out what has changed between the two configurations.
11952 int changes = oldConfig.diff(newConfig);
11953 if (DEBUG_SWITCH) {
11954 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11955 + Integer.toHexString(changes) + ", handles=0x"
11956 + Integer.toHexString(r.info.configChanges));
11957 }
11958 if ((changes&(~r.info.configChanges)) != 0) {
11959 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11960 r.configChangeFlags |= changes;
11961 r.startFreezingScreenLocked(r.app, globalChanges);
11962 if (r.app == null || r.app.thread == null) {
11963 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11964 destroyActivityLocked(r, true);
11965 } else if (r.state == ActivityState.PAUSING) {
11966 // A little annoying: we are waiting for this activity to
11967 // finish pausing. Let's not do anything now, but just
11968 // flag that it needs to be restarted when done pausing.
11969 r.configDestroy = true;
11970 return true;
11971 } else if (r.state == ActivityState.RESUMED) {
11972 // Try to optimize this case: the configuration is changing
11973 // and we need to restart the top, resumed activity.
11974 // Instead of doing the normal handshaking, just say
11975 // "restart!".
11976 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11977 relaunchActivityLocked(r, r.configChangeFlags, true);
11978 r.configChangeFlags = 0;
11979 } else {
11980 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11981 relaunchActivityLocked(r, r.configChangeFlags, false);
11982 r.configChangeFlags = 0;
11983 }
11984
11985 // All done... tell the caller we weren't able to keep this
11986 // activity around.
11987 return false;
11988 }
11989 }
11990
11991 // Default case: the activity can handle this new configuration, so
11992 // hand it over. Note that we don't need to give it the new
11993 // configuration, since we always send configuration changes to all
11994 // process when they happen so it can just use whatever configuration
11995 // it last got.
11996 if (r.app != null && r.app.thread != null) {
11997 try {
11998 r.app.thread.scheduleActivityConfigurationChanged(r);
11999 } catch (RemoteException e) {
12000 // If process died, whatever.
12001 }
12002 }
12003 r.stopFreezingScreenLocked(false);
12004
12005 return true;
12006 }
12007
12008 /**
12009 * Save the locale. You must be inside a synchronized (this) block.
12010 */
12011 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12012 if(isDiff) {
12013 SystemProperties.set("user.language", l.getLanguage());
12014 SystemProperties.set("user.region", l.getCountry());
12015 }
12016
12017 if(isPersist) {
12018 SystemProperties.set("persist.sys.language", l.getLanguage());
12019 SystemProperties.set("persist.sys.country", l.getCountry());
12020 SystemProperties.set("persist.sys.localevar", l.getVariant());
12021 }
12022 }
12023
12024 // =========================================================
12025 // LIFETIME MANAGEMENT
12026 // =========================================================
12027
12028 private final int computeOomAdjLocked(
12029 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12030 if (mAdjSeq == app.adjSeq) {
12031 // This adjustment has already been computed.
12032 return app.curAdj;
12033 }
12034
12035 if (app.thread == null) {
12036 app.adjSeq = mAdjSeq;
12037 return (app.curAdj=EMPTY_APP_ADJ);
12038 }
12039
12040 app.isForeground = false;
12041
The Android Open Source Project4df24232009-03-05 14:34:35 -080012042 // Determine the importance of the process, starting with most
12043 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012044 int adj;
12045 int N;
12046 if (app == TOP_APP || app.instrumentationClass != null
12047 || app.persistentActivities > 0) {
12048 // The last app on the list is the foreground app.
12049 adj = FOREGROUND_APP_ADJ;
12050 app.isForeground = true;
12051 } else if (app.curReceiver != null ||
12052 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12053 // An app that is currently receiving a broadcast also
12054 // counts as being in the foreground.
12055 adj = FOREGROUND_APP_ADJ;
12056 } else if (app.executingServices.size() > 0) {
12057 // An app that is currently executing a service callback also
12058 // counts as being in the foreground.
12059 adj = FOREGROUND_APP_ADJ;
12060 } else if (app.foregroundServices || app.forcingToForeground != null) {
12061 // The user is aware of this app, so make it visible.
12062 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012063 } else if (app == mHomeProcess) {
12064 // This process is hosting what we currently consider to be the
12065 // home app, so we don't want to let it go into the background.
12066 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012067 } else if ((N=app.activities.size()) != 0) {
12068 // This app is in the background with paused activities.
12069 adj = hiddenAdj;
12070 for (int j=0; j<N; j++) {
12071 if (((HistoryRecord)app.activities.get(j)).visible) {
12072 // This app has a visible activity!
12073 adj = VISIBLE_APP_ADJ;
12074 break;
12075 }
12076 }
12077 } else {
12078 // A very not-needed process.
12079 adj = EMPTY_APP_ADJ;
12080 }
12081
The Android Open Source Project4df24232009-03-05 14:34:35 -080012082 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012083 // there are applications dependent on our services or providers, but
12084 // this gives us a baseline and makes sure we don't get into an
12085 // infinite recursion.
12086 app.adjSeq = mAdjSeq;
12087 app.curRawAdj = adj;
12088 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12089
Christopher Tate6fa95972009-06-05 18:43:55 -070012090 if (mBackupTarget != null && app == mBackupTarget.app) {
12091 // If possible we want to avoid killing apps while they're being backed up
12092 if (adj > BACKUP_APP_ADJ) {
12093 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12094 adj = BACKUP_APP_ADJ;
12095 }
12096 }
12097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012098 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12099 // If this process has active services running in it, we would
12100 // like to avoid killing it unless it would prevent the current
12101 // application from running.
12102 if (adj > hiddenAdj) {
12103 adj = hiddenAdj;
12104 }
12105 final long now = SystemClock.uptimeMillis();
12106 // This process is more important if the top activity is
12107 // bound to the service.
12108 Iterator jt = app.services.iterator();
12109 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12110 ServiceRecord s = (ServiceRecord)jt.next();
12111 if (s.startRequested) {
12112 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12113 // This service has seen some activity within
12114 // recent memory, so we will keep its process ahead
12115 // of the background processes.
12116 if (adj > SECONDARY_SERVER_ADJ) {
12117 adj = SECONDARY_SERVER_ADJ;
12118 }
12119 } else {
12120 // This service has been inactive for too long, just
12121 // put it with the rest of the background processes.
12122 if (adj > hiddenAdj) {
12123 adj = hiddenAdj;
12124 }
12125 }
12126 }
12127 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12128 Iterator<ConnectionRecord> kt
12129 = s.connections.values().iterator();
12130 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12131 // XXX should compute this based on the max of
12132 // all connected clients.
12133 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012134 if (cr.binding.client == app) {
12135 // Binding to ourself is not interesting.
12136 continue;
12137 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012138 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12139 ProcessRecord client = cr.binding.client;
12140 int myHiddenAdj = hiddenAdj;
12141 if (myHiddenAdj > client.hiddenAdj) {
12142 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12143 myHiddenAdj = client.hiddenAdj;
12144 } else {
12145 myHiddenAdj = VISIBLE_APP_ADJ;
12146 }
12147 }
12148 int clientAdj = computeOomAdjLocked(
12149 client, myHiddenAdj, TOP_APP);
12150 if (adj > clientAdj) {
12151 adj = clientAdj > VISIBLE_APP_ADJ
12152 ? clientAdj : VISIBLE_APP_ADJ;
12153 }
12154 }
12155 HistoryRecord a = cr.activity;
12156 //if (a != null) {
12157 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12158 //}
12159 if (a != null && adj > FOREGROUND_APP_ADJ &&
12160 (a.state == ActivityState.RESUMED
12161 || a.state == ActivityState.PAUSING)) {
12162 adj = FOREGROUND_APP_ADJ;
12163 }
12164 }
12165 }
12166 }
12167 }
12168
12169 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12170 // If this process has published any content providers, then
12171 // its adjustment makes it at least as important as any of the
12172 // processes using those providers, and no less important than
12173 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12174 if (adj > CONTENT_PROVIDER_ADJ) {
12175 adj = CONTENT_PROVIDER_ADJ;
12176 }
12177 Iterator jt = app.pubProviders.values().iterator();
12178 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12179 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12180 if (cpr.clients.size() != 0) {
12181 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12182 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12183 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012184 if (client == app) {
12185 // Being our own client is not interesting.
12186 continue;
12187 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012188 int myHiddenAdj = hiddenAdj;
12189 if (myHiddenAdj > client.hiddenAdj) {
12190 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12191 myHiddenAdj = client.hiddenAdj;
12192 } else {
12193 myHiddenAdj = FOREGROUND_APP_ADJ;
12194 }
12195 }
12196 int clientAdj = computeOomAdjLocked(
12197 client, myHiddenAdj, TOP_APP);
12198 if (adj > clientAdj) {
12199 adj = clientAdj > FOREGROUND_APP_ADJ
12200 ? clientAdj : FOREGROUND_APP_ADJ;
12201 }
12202 }
12203 }
12204 // If the provider has external (non-framework) process
12205 // dependencies, ensure that its adjustment is at least
12206 // FOREGROUND_APP_ADJ.
12207 if (cpr.externals != 0) {
12208 if (adj > FOREGROUND_APP_ADJ) {
12209 adj = FOREGROUND_APP_ADJ;
12210 }
12211 }
12212 }
12213 }
12214
12215 app.curRawAdj = adj;
12216
12217 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12218 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12219 if (adj > app.maxAdj) {
12220 adj = app.maxAdj;
12221 }
12222
12223 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012224 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12225 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12226 : Process.THREAD_GROUP_DEFAULT;
12227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012228 return adj;
12229 }
12230
12231 /**
12232 * Ask a given process to GC right now.
12233 */
12234 final void performAppGcLocked(ProcessRecord app) {
12235 try {
12236 app.lastRequestedGc = SystemClock.uptimeMillis();
12237 if (app.thread != null) {
12238 app.thread.processInBackground();
12239 }
12240 } catch (Exception e) {
12241 // whatever.
12242 }
12243 }
12244
12245 /**
12246 * Returns true if things are idle enough to perform GCs.
12247 */
12248 private final boolean canGcNow() {
12249 return mParallelBroadcasts.size() == 0
12250 && mOrderedBroadcasts.size() == 0
12251 && (mSleeping || (mResumedActivity != null &&
12252 mResumedActivity.idle));
12253 }
12254
12255 /**
12256 * Perform GCs on all processes that are waiting for it, but only
12257 * if things are idle.
12258 */
12259 final void performAppGcsLocked() {
12260 final int N = mProcessesToGc.size();
12261 if (N <= 0) {
12262 return;
12263 }
12264 if (canGcNow()) {
12265 while (mProcessesToGc.size() > 0) {
12266 ProcessRecord proc = mProcessesToGc.remove(0);
12267 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12268 // To avoid spamming the system, we will GC processes one
12269 // at a time, waiting a few seconds between each.
12270 performAppGcLocked(proc);
12271 scheduleAppGcsLocked();
12272 return;
12273 }
12274 }
12275 }
12276 }
12277
12278 /**
12279 * If all looks good, perform GCs on all processes waiting for them.
12280 */
12281 final void performAppGcsIfAppropriateLocked() {
12282 if (canGcNow()) {
12283 performAppGcsLocked();
12284 return;
12285 }
12286 // Still not idle, wait some more.
12287 scheduleAppGcsLocked();
12288 }
12289
12290 /**
12291 * Schedule the execution of all pending app GCs.
12292 */
12293 final void scheduleAppGcsLocked() {
12294 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12295 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12296 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12297 }
12298
12299 /**
12300 * Set up to ask a process to GC itself. This will either do it
12301 * immediately, or put it on the list of processes to gc the next
12302 * time things are idle.
12303 */
12304 final void scheduleAppGcLocked(ProcessRecord app) {
12305 long now = SystemClock.uptimeMillis();
12306 if ((app.lastRequestedGc+5000) > now) {
12307 return;
12308 }
12309 if (!mProcessesToGc.contains(app)) {
12310 mProcessesToGc.add(app);
12311 scheduleAppGcsLocked();
12312 }
12313 }
12314
12315 private final boolean updateOomAdjLocked(
12316 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12317 app.hiddenAdj = hiddenAdj;
12318
12319 if (app.thread == null) {
12320 return true;
12321 }
12322
12323 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12324
12325 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12326 //Thread priority adjustment is disabled out to see
12327 //how the kernel scheduler performs.
12328 if (false) {
12329 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12330 app.setIsForeground = app.isForeground;
12331 if (app.pid != MY_PID) {
12332 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12333 + " to " + (app.isForeground
12334 ? Process.THREAD_PRIORITY_FOREGROUND
12335 : Process.THREAD_PRIORITY_DEFAULT));
12336 try {
12337 Process.setThreadPriority(app.pid, app.isForeground
12338 ? Process.THREAD_PRIORITY_FOREGROUND
12339 : Process.THREAD_PRIORITY_DEFAULT);
12340 } catch (RuntimeException e) {
12341 Log.w(TAG, "Exception trying to set priority of application thread "
12342 + app.pid, e);
12343 }
12344 }
12345 }
12346 }
12347 if (app.pid != 0 && app.pid != MY_PID) {
12348 if (app.curRawAdj != app.setRawAdj) {
12349 if (app.curRawAdj > FOREGROUND_APP_ADJ
12350 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12351 // If this app is transitioning from foreground to
12352 // non-foreground, have it do a gc.
12353 scheduleAppGcLocked(app);
12354 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12355 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12356 // Likewise do a gc when an app is moving in to the
12357 // background (such as a service stopping).
12358 scheduleAppGcLocked(app);
12359 }
12360 app.setRawAdj = app.curRawAdj;
12361 }
12362 if (adj != app.setAdj) {
12363 if (Process.setOomAdj(app.pid, adj)) {
12364 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12365 TAG, "Set app " + app.processName +
12366 " oom adj to " + adj);
12367 app.setAdj = adj;
12368 } else {
12369 return false;
12370 }
12371 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012372 if (app.setSchedGroup != app.curSchedGroup) {
12373 app.setSchedGroup = app.curSchedGroup;
12374 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12375 "Setting process group of " + app.processName
12376 + " to " + app.curSchedGroup);
12377 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012378 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012379 try {
12380 Process.setProcessGroup(app.pid, app.curSchedGroup);
12381 } catch (Exception e) {
12382 Log.w(TAG, "Failed setting process group of " + app.pid
12383 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012384 e.printStackTrace();
12385 } finally {
12386 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012387 }
12388 }
12389 if (false) {
12390 if (app.thread != null) {
12391 try {
12392 app.thread.setSchedulingGroup(app.curSchedGroup);
12393 } catch (RemoteException e) {
12394 }
12395 }
12396 }
12397 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012398 }
12399
12400 return true;
12401 }
12402
12403 private final HistoryRecord resumedAppLocked() {
12404 HistoryRecord resumedActivity = mResumedActivity;
12405 if (resumedActivity == null || resumedActivity.app == null) {
12406 resumedActivity = mPausingActivity;
12407 if (resumedActivity == null || resumedActivity.app == null) {
12408 resumedActivity = topRunningActivityLocked(null);
12409 }
12410 }
12411 return resumedActivity;
12412 }
12413
12414 private final boolean updateOomAdjLocked(ProcessRecord app) {
12415 final HistoryRecord TOP_ACT = resumedAppLocked();
12416 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12417 int curAdj = app.curAdj;
12418 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12419 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12420
12421 mAdjSeq++;
12422
12423 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12424 if (res) {
12425 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12426 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12427 if (nowHidden != wasHidden) {
12428 // Changed to/from hidden state, so apps after it in the LRU
12429 // list may also be changed.
12430 updateOomAdjLocked();
12431 }
12432 }
12433 return res;
12434 }
12435
12436 private final boolean updateOomAdjLocked() {
12437 boolean didOomAdj = true;
12438 final HistoryRecord TOP_ACT = resumedAppLocked();
12439 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12440
12441 if (false) {
12442 RuntimeException e = new RuntimeException();
12443 e.fillInStackTrace();
12444 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12445 }
12446
12447 mAdjSeq++;
12448
12449 // First try updating the OOM adjustment for each of the
12450 // application processes based on their current state.
12451 int i = mLRUProcesses.size();
12452 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12453 while (i > 0) {
12454 i--;
12455 ProcessRecord app = mLRUProcesses.get(i);
12456 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12457 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12458 && app.curAdj == curHiddenAdj) {
12459 curHiddenAdj++;
12460 }
12461 } else {
12462 didOomAdj = false;
12463 }
12464 }
12465
12466 // todo: for now pretend like OOM ADJ didn't work, because things
12467 // aren't behaving as expected on Linux -- it's not killing processes.
12468 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12469 }
12470
12471 private final void trimApplications() {
12472 synchronized (this) {
12473 int i;
12474
12475 // First remove any unused application processes whose package
12476 // has been removed.
12477 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12478 final ProcessRecord app = mRemovedProcesses.get(i);
12479 if (app.activities.size() == 0
12480 && app.curReceiver == null && app.services.size() == 0) {
12481 Log.i(
12482 TAG, "Exiting empty application process "
12483 + app.processName + " ("
12484 + (app.thread != null ? app.thread.asBinder() : null)
12485 + ")\n");
12486 if (app.pid > 0 && app.pid != MY_PID) {
12487 Process.killProcess(app.pid);
12488 } else {
12489 try {
12490 app.thread.scheduleExit();
12491 } catch (Exception e) {
12492 // Ignore exceptions.
12493 }
12494 }
12495 cleanUpApplicationRecordLocked(app, false, -1);
12496 mRemovedProcesses.remove(i);
12497
12498 if (app.persistent) {
12499 if (app.persistent) {
12500 addAppLocked(app.info);
12501 }
12502 }
12503 }
12504 }
12505
12506 // Now try updating the OOM adjustment for each of the
12507 // application processes based on their current state.
12508 // If the setOomAdj() API is not supported, then go with our
12509 // back-up plan...
12510 if (!updateOomAdjLocked()) {
12511
12512 // Count how many processes are running services.
12513 int numServiceProcs = 0;
12514 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12515 final ProcessRecord app = mLRUProcesses.get(i);
12516
12517 if (app.persistent || app.services.size() != 0
12518 || app.curReceiver != null
12519 || app.persistentActivities > 0) {
12520 // Don't count processes holding services against our
12521 // maximum process count.
12522 if (localLOGV) Log.v(
12523 TAG, "Not trimming app " + app + " with services: "
12524 + app.services);
12525 numServiceProcs++;
12526 }
12527 }
12528
12529 int curMaxProcs = mProcessLimit;
12530 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12531 if (mAlwaysFinishActivities) {
12532 curMaxProcs = 1;
12533 }
12534 curMaxProcs += numServiceProcs;
12535
12536 // Quit as many processes as we can to get down to the desired
12537 // process count. First remove any processes that no longer
12538 // have activites running in them.
12539 for ( i=0;
12540 i<mLRUProcesses.size()
12541 && mLRUProcesses.size() > curMaxProcs;
12542 i++) {
12543 final ProcessRecord app = mLRUProcesses.get(i);
12544 // Quit an application only if it is not currently
12545 // running any activities.
12546 if (!app.persistent && app.activities.size() == 0
12547 && app.curReceiver == null && app.services.size() == 0) {
12548 Log.i(
12549 TAG, "Exiting empty application process "
12550 + app.processName + " ("
12551 + (app.thread != null ? app.thread.asBinder() : null)
12552 + ")\n");
12553 if (app.pid > 0 && app.pid != MY_PID) {
12554 Process.killProcess(app.pid);
12555 } else {
12556 try {
12557 app.thread.scheduleExit();
12558 } catch (Exception e) {
12559 // Ignore exceptions.
12560 }
12561 }
12562 // todo: For now we assume the application is not buggy
12563 // or evil, and will quit as a result of our request.
12564 // Eventually we need to drive this off of the death
12565 // notification, and kill the process if it takes too long.
12566 cleanUpApplicationRecordLocked(app, false, i);
12567 i--;
12568 }
12569 }
12570
12571 // If we still have too many processes, now from the least
12572 // recently used process we start finishing activities.
12573 if (Config.LOGV) Log.v(
12574 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12575 " of " + curMaxProcs + " processes");
12576 for ( i=0;
12577 i<mLRUProcesses.size()
12578 && mLRUProcesses.size() > curMaxProcs;
12579 i++) {
12580 final ProcessRecord app = mLRUProcesses.get(i);
12581 // Quit the application only if we have a state saved for
12582 // all of its activities.
12583 boolean canQuit = !app.persistent && app.curReceiver == null
12584 && app.services.size() == 0
12585 && app.persistentActivities == 0;
12586 int NUMA = app.activities.size();
12587 int j;
12588 if (Config.LOGV) Log.v(
12589 TAG, "Looking to quit " + app.processName);
12590 for (j=0; j<NUMA && canQuit; j++) {
12591 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12592 if (Config.LOGV) Log.v(
12593 TAG, " " + r.intent.getComponent().flattenToShortString()
12594 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12595 canQuit = (r.haveState || !r.stateNotNeeded)
12596 && !r.visible && r.stopped;
12597 }
12598 if (canQuit) {
12599 // Finish all of the activities, and then the app itself.
12600 for (j=0; j<NUMA; j++) {
12601 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12602 if (!r.finishing) {
12603 destroyActivityLocked(r, false);
12604 }
12605 r.resultTo = null;
12606 }
12607 Log.i(TAG, "Exiting application process "
12608 + app.processName + " ("
12609 + (app.thread != null ? app.thread.asBinder() : null)
12610 + ")\n");
12611 if (app.pid > 0 && app.pid != MY_PID) {
12612 Process.killProcess(app.pid);
12613 } else {
12614 try {
12615 app.thread.scheduleExit();
12616 } catch (Exception e) {
12617 // Ignore exceptions.
12618 }
12619 }
12620 // todo: For now we assume the application is not buggy
12621 // or evil, and will quit as a result of our request.
12622 // Eventually we need to drive this off of the death
12623 // notification, and kill the process if it takes too long.
12624 cleanUpApplicationRecordLocked(app, false, i);
12625 i--;
12626 //dump();
12627 }
12628 }
12629
12630 }
12631
12632 int curMaxActivities = MAX_ACTIVITIES;
12633 if (mAlwaysFinishActivities) {
12634 curMaxActivities = 1;
12635 }
12636
12637 // Finally, if there are too many activities now running, try to
12638 // finish as many as we can to get back down to the limit.
12639 for ( i=0;
12640 i<mLRUActivities.size()
12641 && mLRUActivities.size() > curMaxActivities;
12642 i++) {
12643 final HistoryRecord r
12644 = (HistoryRecord)mLRUActivities.get(i);
12645
12646 // We can finish this one if we have its icicle saved and
12647 // it is not persistent.
12648 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12649 && r.stopped && !r.persistent && !r.finishing) {
12650 final int origSize = mLRUActivities.size();
12651 destroyActivityLocked(r, true);
12652
12653 // This will remove it from the LRU list, so keep
12654 // our index at the same value. Note that this check to
12655 // see if the size changes is just paranoia -- if
12656 // something unexpected happens, we don't want to end up
12657 // in an infinite loop.
12658 if (origSize > mLRUActivities.size()) {
12659 i--;
12660 }
12661 }
12662 }
12663 }
12664 }
12665
12666 /** This method sends the specified signal to each of the persistent apps */
12667 public void signalPersistentProcesses(int sig) throws RemoteException {
12668 if (sig != Process.SIGNAL_USR1) {
12669 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12670 }
12671
12672 synchronized (this) {
12673 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12674 != PackageManager.PERMISSION_GRANTED) {
12675 throw new SecurityException("Requires permission "
12676 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12677 }
12678
12679 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12680 ProcessRecord r = mLRUProcesses.get(i);
12681 if (r.thread != null && r.persistent) {
12682 Process.sendSignal(r.pid, sig);
12683 }
12684 }
12685 }
12686 }
12687
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012688 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012689 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012690
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012691 try {
12692 synchronized (this) {
12693 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12694 // its own permission.
12695 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12696 != PackageManager.PERMISSION_GRANTED) {
12697 throw new SecurityException("Requires permission "
12698 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012699 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012700
12701 if (start && fd == null) {
12702 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012703 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012704
12705 ProcessRecord proc = null;
12706 try {
12707 int pid = Integer.parseInt(process);
12708 synchronized (mPidsSelfLocked) {
12709 proc = mPidsSelfLocked.get(pid);
12710 }
12711 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012712 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012713
12714 if (proc == null) {
12715 HashMap<String, SparseArray<ProcessRecord>> all
12716 = mProcessNames.getMap();
12717 SparseArray<ProcessRecord> procs = all.get(process);
12718 if (procs != null && procs.size() > 0) {
12719 proc = procs.valueAt(0);
12720 }
12721 }
12722
12723 if (proc == null || proc.thread == null) {
12724 throw new IllegalArgumentException("Unknown process: " + process);
12725 }
12726
12727 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12728 if (isSecure) {
12729 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12730 throw new SecurityException("Process not debuggable: " + proc);
12731 }
12732 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012733
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012734 proc.thread.profilerControl(start, path, fd);
12735 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012736 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012737 }
12738 } catch (RemoteException e) {
12739 throw new IllegalStateException("Process disappeared");
12740 } finally {
12741 if (fd != null) {
12742 try {
12743 fd.close();
12744 } catch (IOException e) {
12745 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012746 }
12747 }
12748 }
12749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012750 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12751 public void monitor() {
12752 synchronized (this) { }
12753 }
12754}