blob: c0d4496e00c0389ae14484b6fad59b12035ed8b2 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import com.android.server.IntentResolver;
21import com.android.server.ProcessMap;
22import com.android.server.ProcessStats;
23import com.android.server.SystemServer;
24import com.android.server.Watchdog;
25import com.android.server.WindowManagerService;
26
27import android.app.Activity;
28import android.app.ActivityManager;
29import android.app.ActivityManagerNative;
30import android.app.ActivityThread;
31import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020032import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.app.Dialog;
34import android.app.IActivityWatcher;
35import android.app.IApplicationThread;
36import android.app.IInstrumentationWatcher;
37import android.app.IIntentReceiver;
38import android.app.IIntentSender;
39import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
42import android.app.PendingIntent;
43import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070044import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020045import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
47import android.content.ContentResolver;
48import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
51import android.content.pm.ActivityInfo;
52import android.content.pm.ApplicationInfo;
53import android.content.pm.ConfigurationInfo;
54import android.content.pm.IPackageDataObserver;
55import android.content.pm.IPackageManager;
56import android.content.pm.InstrumentationInfo;
57import android.content.pm.PackageManager;
58import android.content.pm.ProviderInfo;
59import android.content.pm.ResolveInfo;
60import android.content.pm.ServiceInfo;
61import android.content.res.Configuration;
62import android.graphics.Bitmap;
63import android.net.Uri;
64import android.os.Binder;
65import android.os.Bundle;
66import android.os.Environment;
67import android.os.FileUtils;
68import android.os.Handler;
69import android.os.IBinder;
70import android.os.IPermissionController;
71import android.os.Looper;
72import android.os.Message;
73import android.os.Parcel;
74import android.os.ParcelFileDescriptor;
75import android.os.PowerManager;
76import android.os.Process;
77import android.os.RemoteException;
78import android.os.ServiceManager;
79import android.os.SystemClock;
80import android.os.SystemProperties;
81import android.provider.Checkin;
82import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020083import android.server.data.CrashData;
84import android.server.data.StackTraceElementData;
85import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.text.TextUtils;
87import android.util.Config;
88import android.util.EventLog;
89import android.util.Log;
90import android.util.PrintWriterPrinter;
91import android.util.SparseArray;
92import android.view.Gravity;
93import android.view.LayoutInflater;
94import android.view.View;
95import android.view.WindowManager;
96import android.view.WindowManagerPolicy;
97
98import dalvik.system.Zygote;
99
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200100import java.io.ByteArrayInputStream;
101import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102import java.io.File;
103import java.io.FileDescriptor;
104import java.io.FileInputStream;
105import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200106import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.io.PrintWriter;
108import java.lang.IllegalStateException;
109import java.lang.ref.WeakReference;
110import java.util.ArrayList;
111import java.util.HashMap;
112import java.util.HashSet;
113import java.util.Iterator;
114import java.util.List;
115import java.util.Locale;
116import java.util.Map;
117
118public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
119 static final String TAG = "ActivityManager";
120 static final boolean DEBUG = false;
121 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
122 static final boolean DEBUG_SWITCH = localLOGV || false;
123 static final boolean DEBUG_TASKS = localLOGV || false;
124 static final boolean DEBUG_PAUSE = localLOGV || false;
125 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
126 static final boolean DEBUG_TRANSITION = localLOGV || false;
127 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700128 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 static final boolean DEBUG_SERVICE = localLOGV || false;
130 static final boolean DEBUG_VISBILITY = localLOGV || false;
131 static final boolean DEBUG_PROCESSES = localLOGV || false;
132 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700133 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700134 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 static final boolean VALIDATE_TOKENS = false;
136 static final boolean SHOW_ACTIVITY_START_TIME = true;
137
138 // Control over CPU and battery monitoring.
139 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
140 static final boolean MONITOR_CPU_USAGE = true;
141 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
142 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
143 static final boolean MONITOR_THREAD_CPU_USAGE = false;
144
145 // Event log tags
146 static final int LOG_CONFIGURATION_CHANGED = 2719;
147 static final int LOG_CPU = 2721;
148 static final int LOG_AM_FINISH_ACTIVITY = 30001;
149 static final int LOG_TASK_TO_FRONT = 30002;
150 static final int LOG_AM_NEW_INTENT = 30003;
151 static final int LOG_AM_CREATE_TASK = 30004;
152 static final int LOG_AM_CREATE_ACTIVITY = 30005;
153 static final int LOG_AM_RESTART_ACTIVITY = 30006;
154 static final int LOG_AM_RESUME_ACTIVITY = 30007;
155 static final int LOG_ANR = 30008;
156 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
157 static final int LOG_AM_PROCESS_BOUND = 30010;
158 static final int LOG_AM_PROCESS_DIED = 30011;
159 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
160 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
161 static final int LOG_AM_PROCESS_START = 30014;
162 static final int LOG_AM_PROCESS_BAD = 30015;
163 static final int LOG_AM_PROCESS_GOOD = 30016;
164 static final int LOG_AM_LOW_MEMORY = 30017;
165 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
166 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
167 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
168 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
169 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
170 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
171 static final int LOG_AM_CREATE_SERVICE = 30030;
172 static final int LOG_AM_DESTROY_SERVICE = 30031;
173 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
174 static final int LOG_AM_DROP_PROCESS = 30033;
175 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
176 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
177 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
178
179 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
180 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
181
Dianne Hackborn1655be42009-05-08 14:29:01 -0700182 // The flags that are set for all calls we make to the package manager.
183 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Mitsuru Oshima9189cab2009-06-03 11:19:12 -0700184 | PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 private static final String SYSTEM_SECURE = "ro.secure";
187
188 // This is the maximum number of application processes we would like
189 // to have running. Due to the asynchronous nature of things, we can
190 // temporarily go beyond this limit.
191 static final int MAX_PROCESSES = 2;
192
193 // Set to false to leave processes running indefinitely, relying on
194 // the kernel killing them as resources are required.
195 static final boolean ENFORCE_PROCESS_LIMIT = false;
196
197 // This is the maximum number of activities that we would like to have
198 // running at a given time.
199 static final int MAX_ACTIVITIES = 20;
200
201 // Maximum number of recent tasks that we can remember.
202 static final int MAX_RECENT_TASKS = 20;
203
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700204 // Amount of time after a call to stopAppSwitches() during which we will
205 // prevent further untrusted switches from happening.
206 static final long APP_SWITCH_DELAY_TIME = 5*1000;
207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 // How long until we reset a task when the user returns to it. Currently
209 // 30 minutes.
210 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
211
212 // Set to true to disable the icon that is shown while a new activity
213 // is being started.
214 static final boolean SHOW_APP_STARTING_ICON = true;
215
216 // How long we wait until giving up on the last activity to pause. This
217 // is short because it directly impacts the responsiveness of starting the
218 // next activity.
219 static final int PAUSE_TIMEOUT = 500;
220
221 /**
222 * How long we can hold the launch wake lock before giving up.
223 */
224 static final int LAUNCH_TIMEOUT = 10*1000;
225
226 // How long we wait for a launched process to attach to the activity manager
227 // before we decide it's never going to come up for real.
228 static final int PROC_START_TIMEOUT = 10*1000;
229
230 // How long we wait until giving up on the last activity telling us it
231 // is idle.
232 static final int IDLE_TIMEOUT = 10*1000;
233
234 // How long to wait after going idle before forcing apps to GC.
235 static final int GC_TIMEOUT = 5*1000;
236
237 // How long we wait until giving up on an activity telling us it has
238 // finished destroying itself.
239 static final int DESTROY_TIMEOUT = 10*1000;
240
241 // How long we allow a receiver to run before giving up on it.
242 static final int BROADCAST_TIMEOUT = 10*1000;
243
244 // How long we wait for a service to finish executing.
245 static final int SERVICE_TIMEOUT = 20*1000;
246
247 // How long a service needs to be running until restarting its process
248 // is no longer considered to be a relaunch of the service.
249 static final int SERVICE_RESTART_DURATION = 5*1000;
250
251 // Maximum amount of time for there to be no activity on a service before
252 // we consider it non-essential and allow its process to go on the
253 // LRU background list.
254 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
255
256 // How long we wait until we timeout on key dispatching.
257 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
258
259 // The minimum time we allow between crashes, for us to consider this
260 // application to be bad and stop and its services and reject broadcasts.
261 static final int MIN_CRASH_INTERVAL = 60*1000;
262
263 // How long we wait until we timeout on key dispatching during instrumentation.
264 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
265
266 // OOM adjustments for processes in various states:
267
268 // This is a process without anything currently running in it. Definitely
269 // the first to go! Value set in system/rootdir/init.rc on startup.
270 // This value is initalized in the constructor, careful when refering to
271 // this static variable externally.
272 static int EMPTY_APP_ADJ;
273
274 // This is a process with a content provider that does not have any clients
275 // attached to it. If it did have any clients, its adjustment would be the
276 // one for the highest-priority of those processes.
277 static int CONTENT_PROVIDER_ADJ;
278
279 // This is a process only hosting activities that are not visible,
280 // so it can be killed without any disruption. Value set in
281 // system/rootdir/init.rc on startup.
282 final int HIDDEN_APP_MAX_ADJ;
283 static int HIDDEN_APP_MIN_ADJ;
284
The Android Open Source Project4df24232009-03-05 14:34:35 -0800285 // This is a process holding the home application -- we want to try
286 // avoiding killing it, even if it would normally be in the background,
287 // because the user interacts with it so much.
288 final int HOME_APP_ADJ;
289
Christopher Tate6fa95972009-06-05 18:43:55 -0700290 // This is a process currently hosting a backup operation. Killing it
291 // is not entirely fatal but is generally a bad idea.
292 final int BACKUP_APP_ADJ;
293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 // This is a process holding a secondary server -- killing it will not
295 // have much of an impact as far as the user is concerned. Value set in
296 // system/rootdir/init.rc on startup.
297 final int SECONDARY_SERVER_ADJ;
298
299 // This is a process only hosting activities that are visible to the
300 // user, so we'd prefer they don't disappear. Value set in
301 // system/rootdir/init.rc on startup.
302 final int VISIBLE_APP_ADJ;
303
304 // This is the process running the current foreground app. We'd really
305 // rather not kill it! Value set in system/rootdir/init.rc on startup.
306 final int FOREGROUND_APP_ADJ;
307
308 // This is a process running a core server, such as telephony. Definitely
309 // don't want to kill it, but doing so is not completely fatal.
310 static final int CORE_SERVER_ADJ = -12;
311
312 // The system process runs at the default adjustment.
313 static final int SYSTEM_ADJ = -16;
314
315 // Memory pages are 4K.
316 static final int PAGE_SIZE = 4*1024;
317
318 // Corresponding memory levels for above adjustments.
319 final int EMPTY_APP_MEM;
320 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800321 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700322 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 final int SECONDARY_SERVER_MEM;
324 final int VISIBLE_APP_MEM;
325 final int FOREGROUND_APP_MEM;
326
327 final int MY_PID;
328
329 static final String[] EMPTY_STRING_ARRAY = new String[0];
330
331 enum ActivityState {
332 INITIALIZING,
333 RESUMED,
334 PAUSING,
335 PAUSED,
336 STOPPING,
337 STOPPED,
338 FINISHING,
339 DESTROYING,
340 DESTROYED
341 }
342
343 /**
344 * The back history of all previous (and possibly still
345 * running) activities. It contains HistoryRecord objects.
346 */
347 final ArrayList mHistory = new ArrayList();
348
349 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700350 * Description of a request to start a new activity, which has been held
351 * due to app switches being disabled.
352 */
353 class PendingActivityLaunch {
354 HistoryRecord r;
355 HistoryRecord sourceRecord;
356 Uri[] grantedUriPermissions;
357 int grantedMode;
358 boolean onlyIfNeeded;
359 }
360
361 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
362 = new ArrayList<PendingActivityLaunch>();
363
364 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 * List of all active broadcasts that are to be executed immediately
366 * (without waiting for another broadcast to finish). Currently this only
367 * contains broadcasts to registered receivers, to avoid spinning up
368 * a bunch of processes to execute IntentReceiver components.
369 */
370 final ArrayList<BroadcastRecord> mParallelBroadcasts
371 = new ArrayList<BroadcastRecord>();
372
373 /**
374 * List of all active broadcasts that are to be executed one at a time.
375 * The object at the top of the list is the currently activity broadcasts;
376 * those after it are waiting for the top to finish..
377 */
378 final ArrayList<BroadcastRecord> mOrderedBroadcasts
379 = new ArrayList<BroadcastRecord>();
380
381 /**
382 * Set when we current have a BROADCAST_INTENT_MSG in flight.
383 */
384 boolean mBroadcastsScheduled = false;
385
386 /**
387 * Set to indicate whether to issue an onUserLeaving callback when a
388 * newly launched activity is being brought in front of us.
389 */
390 boolean mUserLeaving = false;
391
392 /**
393 * When we are in the process of pausing an activity, before starting the
394 * next one, this variable holds the activity that is currently being paused.
395 */
396 HistoryRecord mPausingActivity = null;
397
398 /**
399 * Current activity that is resumed, or null if there is none.
400 */
401 HistoryRecord mResumedActivity = null;
402
403 /**
404 * Activity we have told the window manager to have key focus.
405 */
406 HistoryRecord mFocusedActivity = null;
407
408 /**
409 * This is the last activity that we put into the paused state. This is
410 * used to determine if we need to do an activity transition while sleeping,
411 * when we normally hold the top activity paused.
412 */
413 HistoryRecord mLastPausedActivity = null;
414
415 /**
416 * List of activities that are waiting for a new activity
417 * to become visible before completing whatever operation they are
418 * supposed to do.
419 */
420 final ArrayList mWaitingVisibleActivities = new ArrayList();
421
422 /**
423 * List of activities that are ready to be stopped, but waiting
424 * for the next activity to settle down before doing so. It contains
425 * HistoryRecord objects.
426 */
427 final ArrayList<HistoryRecord> mStoppingActivities
428 = new ArrayList<HistoryRecord>();
429
430 /**
431 * List of intents that were used to start the most recent tasks.
432 */
433 final ArrayList<TaskRecord> mRecentTasks
434 = new ArrayList<TaskRecord>();
435
436 /**
437 * List of activities that are ready to be finished, but waiting
438 * for the previous activity to settle down before doing so. It contains
439 * HistoryRecord objects.
440 */
441 final ArrayList mFinishingActivities = new ArrayList();
442
443 /**
444 * All of the applications we currently have running organized by name.
445 * The keys are strings of the application package name (as
446 * returned by the package manager), and the keys are ApplicationRecord
447 * objects.
448 */
449 final ProcessMap<ProcessRecord> mProcessNames
450 = new ProcessMap<ProcessRecord>();
451
452 /**
453 * The last time that various processes have crashed.
454 */
455 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
456
457 /**
458 * Set of applications that we consider to be bad, and will reject
459 * incoming broadcasts from (which the user has no control over).
460 * Processes are added to this set when they have crashed twice within
461 * a minimum amount of time; they are removed from it when they are
462 * later restarted (hopefully due to some user action). The value is the
463 * time it was added to the list.
464 */
465 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
466
467 /**
468 * All of the processes we currently have running organized by pid.
469 * The keys are the pid running the application.
470 *
471 * <p>NOTE: This object is protected by its own lock, NOT the global
472 * activity manager lock!
473 */
474 final SparseArray<ProcessRecord> mPidsSelfLocked
475 = new SparseArray<ProcessRecord>();
476
477 /**
478 * All of the processes that have been forced to be foreground. The key
479 * is the pid of the caller who requested it (we hold a death
480 * link on it).
481 */
482 abstract class ForegroundToken implements IBinder.DeathRecipient {
483 int pid;
484 IBinder token;
485 }
486 final SparseArray<ForegroundToken> mForegroundProcesses
487 = new SparseArray<ForegroundToken>();
488
489 /**
490 * List of records for processes that someone had tried to start before the
491 * system was ready. We don't start them at that point, but ensure they
492 * are started by the time booting is complete.
493 */
494 final ArrayList<ProcessRecord> mProcessesOnHold
495 = new ArrayList<ProcessRecord>();
496
497 /**
498 * List of records for processes that we have started and are waiting
499 * for them to call back. This is really only needed when running in
500 * single processes mode, in which case we do not have a unique pid for
501 * each process.
502 */
503 final ArrayList<ProcessRecord> mStartingProcesses
504 = new ArrayList<ProcessRecord>();
505
506 /**
507 * List of persistent applications that are in the process
508 * of being started.
509 */
510 final ArrayList<ProcessRecord> mPersistentStartingProcesses
511 = new ArrayList<ProcessRecord>();
512
513 /**
514 * Processes that are being forcibly torn down.
515 */
516 final ArrayList<ProcessRecord> mRemovedProcesses
517 = new ArrayList<ProcessRecord>();
518
519 /**
520 * List of running applications, sorted by recent usage.
521 * The first entry in the list is the least recently used.
522 * It contains ApplicationRecord objects. This list does NOT include
523 * any persistent application records (since we never want to exit them).
524 */
525 final ArrayList<ProcessRecord> mLRUProcesses
526 = new ArrayList<ProcessRecord>();
527
528 /**
529 * List of processes that should gc as soon as things are idle.
530 */
531 final ArrayList<ProcessRecord> mProcessesToGc
532 = new ArrayList<ProcessRecord>();
533
534 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800535 * This is the process holding what we currently consider to be
536 * the "home" activity.
537 */
538 private ProcessRecord mHomeProcess;
539
540 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 * List of running activities, sorted by recent usage.
542 * The first entry in the list is the least recently used.
543 * It contains HistoryRecord objects.
544 */
545 private final ArrayList mLRUActivities = new ArrayList();
546
547 /**
548 * Set of PendingResultRecord objects that are currently active.
549 */
550 final HashSet mPendingResultRecords = new HashSet();
551
552 /**
553 * Set of IntentSenderRecord objects that are currently active.
554 */
555 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
556 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
557
558 /**
559 * Intent broadcast that we have tried to start, but are
560 * waiting for its application's process to be created. We only
561 * need one (instead of a list) because we always process broadcasts
562 * one at a time, so no others can be started while waiting for this
563 * one.
564 */
565 BroadcastRecord mPendingBroadcast = null;
566
567 /**
568 * Keeps track of all IIntentReceivers that have been registered for
569 * broadcasts. Hash keys are the receiver IBinder, hash value is
570 * a ReceiverList.
571 */
572 final HashMap mRegisteredReceivers = new HashMap();
573
574 /**
575 * Resolver for broadcast intents to registered receivers.
576 * Holds BroadcastFilter (subclass of IntentFilter).
577 */
578 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
579 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
580 @Override
581 protected boolean allowFilterResult(
582 BroadcastFilter filter, List<BroadcastFilter> dest) {
583 IBinder target = filter.receiverList.receiver.asBinder();
584 for (int i=dest.size()-1; i>=0; i--) {
585 if (dest.get(i).receiverList.receiver.asBinder() == target) {
586 return false;
587 }
588 }
589 return true;
590 }
591 };
592
593 /**
594 * State of all active sticky broadcasts. Keys are the action of the
595 * sticky Intent, values are an ArrayList of all broadcasted intents with
596 * that action (which should usually be one).
597 */
598 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
599 new HashMap<String, ArrayList<Intent>>();
600
601 /**
602 * All currently running services.
603 */
604 final HashMap<ComponentName, ServiceRecord> mServices =
605 new HashMap<ComponentName, ServiceRecord>();
606
607 /**
608 * All currently running services indexed by the Intent used to start them.
609 */
610 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
611 new HashMap<Intent.FilterComparison, ServiceRecord>();
612
613 /**
614 * All currently bound service connections. Keys are the IBinder of
615 * the client's IServiceConnection.
616 */
617 final HashMap<IBinder, ConnectionRecord> mServiceConnections
618 = new HashMap<IBinder, ConnectionRecord>();
619
620 /**
621 * List of services that we have been asked to start,
622 * but haven't yet been able to. It is used to hold start requests
623 * while waiting for their corresponding application thread to get
624 * going.
625 */
626 final ArrayList<ServiceRecord> mPendingServices
627 = new ArrayList<ServiceRecord>();
628
629 /**
630 * List of services that are scheduled to restart following a crash.
631 */
632 final ArrayList<ServiceRecord> mRestartingServices
633 = new ArrayList<ServiceRecord>();
634
635 /**
636 * List of services that are in the process of being stopped.
637 */
638 final ArrayList<ServiceRecord> mStoppingServices
639 = new ArrayList<ServiceRecord>();
640
641 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700642 * Backup/restore process management
643 */
644 String mBackupAppName = null;
645 BackupRecord mBackupTarget = null;
646
647 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 * List of PendingThumbnailsRecord objects of clients who are still
649 * waiting to receive all of the thumbnails for a task.
650 */
651 final ArrayList mPendingThumbnails = new ArrayList();
652
653 /**
654 * List of HistoryRecord objects that have been finished and must
655 * still report back to a pending thumbnail receiver.
656 */
657 final ArrayList mCancelledThumbnails = new ArrayList();
658
659 /**
660 * All of the currently running global content providers. Keys are a
661 * string containing the provider name and values are a
662 * ContentProviderRecord object containing the data about it. Note
663 * that a single provider may be published under multiple names, so
664 * there may be multiple entries here for a single one in mProvidersByClass.
665 */
666 final HashMap mProvidersByName = new HashMap();
667
668 /**
669 * All of the currently running global content providers. Keys are a
670 * string containing the provider's implementation class and values are a
671 * ContentProviderRecord object containing the data about it.
672 */
673 final HashMap mProvidersByClass = new HashMap();
674
675 /**
676 * List of content providers who have clients waiting for them. The
677 * application is currently being launched and the provider will be
678 * removed from this list once it is published.
679 */
680 final ArrayList mLaunchingProviders = new ArrayList();
681
682 /**
683 * Global set of specific Uri permissions that have been granted.
684 */
685 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
686 = new SparseArray<HashMap<Uri, UriPermission>>();
687
688 /**
689 * Thread-local storage used to carry caller permissions over through
690 * indirect content-provider access.
691 * @see #ActivityManagerService.openContentUri()
692 */
693 private class Identity {
694 public int pid;
695 public int uid;
696
697 Identity(int _pid, int _uid) {
698 pid = _pid;
699 uid = _uid;
700 }
701 }
702 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
703
704 /**
705 * All information we have collected about the runtime performance of
706 * any user id that can impact battery performance.
707 */
708 final BatteryStatsService mBatteryStatsService;
709
710 /**
711 * information about component usage
712 */
713 final UsageStatsService mUsageStatsService;
714
715 /**
716 * Current configuration information. HistoryRecord objects are given
717 * a reference to this object to indicate which configuration they are
718 * currently running in, so this object must be kept immutable.
719 */
720 Configuration mConfiguration = new Configuration();
721
722 /**
723 * List of initialization arguments to pass to all processes when binding applications to them.
724 * For example, references to the commonly used services.
725 */
726 HashMap<String, IBinder> mAppBindArgs;
727
728 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700729 * Temporary to avoid allocations. Protected by main lock.
730 */
731 final StringBuilder mStringBuilder = new StringBuilder(256);
732
733 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 * Used to control how we initialize the service.
735 */
736 boolean mStartRunning = false;
737 ComponentName mTopComponent;
738 String mTopAction;
739 String mTopData;
740 boolean mSystemReady = false;
741 boolean mBooting = false;
742
743 Context mContext;
744
745 int mFactoryTest;
746
747 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700748 * The time at which we will allow normal application switches again,
749 * after a call to {@link #stopAppSwitches()}.
750 */
751 long mAppSwitchesAllowedTime;
752
753 /**
754 * This is set to true after the first switch after mAppSwitchesAllowedTime
755 * is set; any switches after that will clear the time.
756 */
757 boolean mDidAppSwitch;
758
759 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 * Set while we are wanting to sleep, to prevent any
761 * activities from being started/resumed.
762 */
763 boolean mSleeping = false;
764
765 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700766 * Set if we are shutting down the system, similar to sleeping.
767 */
768 boolean mShuttingDown = false;
769
770 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 * Set when the system is going to sleep, until we have
772 * successfully paused the current activity and released our wake lock.
773 * At that point the system is allowed to actually sleep.
774 */
775 PowerManager.WakeLock mGoingToSleep;
776
777 /**
778 * We don't want to allow the device to go to sleep while in the process
779 * of launching an activity. This is primarily to allow alarm intent
780 * receivers to launch an activity and get that to run before the device
781 * goes back to sleep.
782 */
783 PowerManager.WakeLock mLaunchingActivity;
784
785 /**
786 * Task identifier that activities are currently being started
787 * in. Incremented each time a new task is created.
788 * todo: Replace this with a TokenSpace class that generates non-repeating
789 * integers that won't wrap.
790 */
791 int mCurTask = 1;
792
793 /**
794 * Current sequence id for oom_adj computation traversal.
795 */
796 int mAdjSeq = 0;
797
798 /**
799 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
800 * is set, indicating the user wants processes started in such a way
801 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
802 * running in each process (thus no pre-initialized process, etc).
803 */
804 boolean mSimpleProcessManagement = false;
805
806 /**
807 * System monitoring: number of processes that died since the last
808 * N procs were started.
809 */
810 int[] mProcDeaths = new int[20];
811
812 String mDebugApp = null;
813 boolean mWaitForDebugger = false;
814 boolean mDebugTransient = false;
815 String mOrigDebugApp = null;
816 boolean mOrigWaitForDebugger = false;
817 boolean mAlwaysFinishActivities = false;
818 IActivityWatcher mWatcher = null;
819
820 /**
821 * Callback of last caller to {@link #requestPss}.
822 */
823 Runnable mRequestPssCallback;
824
825 /**
826 * Remaining processes for which we are waiting results from the last
827 * call to {@link #requestPss}.
828 */
829 final ArrayList<ProcessRecord> mRequestPssList
830 = new ArrayList<ProcessRecord>();
831
832 /**
833 * Runtime statistics collection thread. This object's lock is used to
834 * protect all related state.
835 */
836 final Thread mProcessStatsThread;
837
838 /**
839 * Used to collect process stats when showing not responding dialog.
840 * Protected by mProcessStatsThread.
841 */
842 final ProcessStats mProcessStats = new ProcessStats(
843 MONITOR_THREAD_CPU_USAGE);
844 long mLastCpuTime = 0;
845 long mLastWriteTime = 0;
846
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700847 long mInitialStartTime = 0;
848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 /**
850 * Set to true after the system has finished booting.
851 */
852 boolean mBooted = false;
853
854 int mProcessLimit = 0;
855
856 WindowManagerService mWindowManager;
857
858 static ActivityManagerService mSelf;
859 static ActivityThread mSystemThread;
860
861 private final class AppDeathRecipient implements IBinder.DeathRecipient {
862 final ProcessRecord mApp;
863 final int mPid;
864 final IApplicationThread mAppThread;
865
866 AppDeathRecipient(ProcessRecord app, int pid,
867 IApplicationThread thread) {
868 if (localLOGV) Log.v(
869 TAG, "New death recipient " + this
870 + " for thread " + thread.asBinder());
871 mApp = app;
872 mPid = pid;
873 mAppThread = thread;
874 }
875
876 public void binderDied() {
877 if (localLOGV) Log.v(
878 TAG, "Death received in " + this
879 + " for thread " + mAppThread.asBinder());
880 removeRequestedPss(mApp);
881 synchronized(ActivityManagerService.this) {
882 appDiedLocked(mApp, mPid, mAppThread);
883 }
884 }
885 }
886
887 static final int SHOW_ERROR_MSG = 1;
888 static final int SHOW_NOT_RESPONDING_MSG = 2;
889 static final int SHOW_FACTORY_ERROR_MSG = 3;
890 static final int UPDATE_CONFIGURATION_MSG = 4;
891 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
892 static final int WAIT_FOR_DEBUGGER_MSG = 6;
893 static final int BROADCAST_INTENT_MSG = 7;
894 static final int BROADCAST_TIMEOUT_MSG = 8;
895 static final int PAUSE_TIMEOUT_MSG = 9;
896 static final int IDLE_TIMEOUT_MSG = 10;
897 static final int IDLE_NOW_MSG = 11;
898 static final int SERVICE_TIMEOUT_MSG = 12;
899 static final int UPDATE_TIME_ZONE = 13;
900 static final int SHOW_UID_ERROR_MSG = 14;
901 static final int IM_FEELING_LUCKY_MSG = 15;
902 static final int LAUNCH_TIMEOUT_MSG = 16;
903 static final int DESTROY_TIMEOUT_MSG = 17;
904 static final int SERVICE_ERROR_MSG = 18;
905 static final int RESUME_TOP_ACTIVITY_MSG = 19;
906 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700907 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908
909 AlertDialog mUidAlert;
910
911 final Handler mHandler = new Handler() {
912 //public Handler() {
913 // if (localLOGV) Log.v(TAG, "Handler started!");
914 //}
915
916 public void handleMessage(Message msg) {
917 switch (msg.what) {
918 case SHOW_ERROR_MSG: {
919 HashMap data = (HashMap) msg.obj;
920 byte[] crashData = (byte[])data.get("crashData");
921 if (crashData != null) {
922 // This needs to be *un*synchronized to avoid deadlock.
923 ContentResolver resolver = mContext.getContentResolver();
924 Checkin.reportCrash(resolver, crashData);
925 }
926 synchronized (ActivityManagerService.this) {
927 ProcessRecord proc = (ProcessRecord)data.get("app");
928 if (proc != null && proc.crashDialog != null) {
929 Log.e(TAG, "App already has crash dialog: " + proc);
930 return;
931 }
932 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700933 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 Dialog d = new AppErrorDialog(
935 mContext, res, proc,
936 (Integer)data.get("flags"),
937 (String)data.get("shortMsg"),
938 (String)data.get("longMsg"));
939 d.show();
940 proc.crashDialog = d;
941 } else {
942 // The device is asleep, so just pretend that the user
943 // saw a crash dialog and hit "force quit".
944 res.set(0);
945 }
946 }
947 } break;
948 case SHOW_NOT_RESPONDING_MSG: {
949 synchronized (ActivityManagerService.this) {
950 HashMap data = (HashMap) msg.obj;
951 ProcessRecord proc = (ProcessRecord)data.get("app");
952 if (proc != null && proc.anrDialog != null) {
953 Log.e(TAG, "App already has anr dialog: " + proc);
954 return;
955 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800956
957 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
958 null, null, 0, null, null, null,
959 false, false, MY_PID, Process.SYSTEM_UID);
960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
962 mContext, proc, (HistoryRecord)data.get("activity"));
963 d.show();
964 proc.anrDialog = d;
965 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700966
967 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 } break;
969 case SHOW_FACTORY_ERROR_MSG: {
970 Dialog d = new FactoryErrorDialog(
971 mContext, msg.getData().getCharSequence("msg"));
972 d.show();
973 enableScreenAfterBoot();
974 } break;
975 case UPDATE_CONFIGURATION_MSG: {
976 final ContentResolver resolver = mContext.getContentResolver();
977 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
978 } break;
979 case GC_BACKGROUND_PROCESSES_MSG: {
980 synchronized (ActivityManagerService.this) {
981 performAppGcsIfAppropriateLocked();
982 }
983 } break;
984 case WAIT_FOR_DEBUGGER_MSG: {
985 synchronized (ActivityManagerService.this) {
986 ProcessRecord app = (ProcessRecord)msg.obj;
987 if (msg.arg1 != 0) {
988 if (!app.waitedForDebugger) {
989 Dialog d = new AppWaitingForDebuggerDialog(
990 ActivityManagerService.this,
991 mContext, app);
992 app.waitDialog = d;
993 app.waitedForDebugger = true;
994 d.show();
995 }
996 } else {
997 if (app.waitDialog != null) {
998 app.waitDialog.dismiss();
999 app.waitDialog = null;
1000 }
1001 }
1002 }
1003 } break;
1004 case BROADCAST_INTENT_MSG: {
1005 if (DEBUG_BROADCAST) Log.v(
1006 TAG, "Received BROADCAST_INTENT_MSG");
1007 processNextBroadcast(true);
1008 } break;
1009 case BROADCAST_TIMEOUT_MSG: {
1010 broadcastTimeout();
1011 } break;
1012 case PAUSE_TIMEOUT_MSG: {
1013 IBinder token = (IBinder)msg.obj;
1014 // We don't at this point know if the activity is fullscreen,
1015 // so we need to be conservative and assume it isn't.
1016 Log.w(TAG, "Activity pause timeout for " + token);
1017 activityPaused(token, null, true);
1018 } break;
1019 case IDLE_TIMEOUT_MSG: {
1020 IBinder token = (IBinder)msg.obj;
1021 // We don't at this point know if the activity is fullscreen,
1022 // so we need to be conservative and assume it isn't.
1023 Log.w(TAG, "Activity idle timeout for " + token);
1024 activityIdleInternal(token, true);
1025 } break;
1026 case DESTROY_TIMEOUT_MSG: {
1027 IBinder token = (IBinder)msg.obj;
1028 // We don't at this point know if the activity is fullscreen,
1029 // so we need to be conservative and assume it isn't.
1030 Log.w(TAG, "Activity destroy timeout for " + token);
1031 activityDestroyed(token);
1032 } break;
1033 case IDLE_NOW_MSG: {
1034 IBinder token = (IBinder)msg.obj;
1035 activityIdle(token);
1036 } break;
1037 case SERVICE_TIMEOUT_MSG: {
1038 serviceTimeout((ProcessRecord)msg.obj);
1039 } break;
1040 case UPDATE_TIME_ZONE: {
1041 synchronized (ActivityManagerService.this) {
1042 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1043 ProcessRecord r = mLRUProcesses.get(i);
1044 if (r.thread != null) {
1045 try {
1046 r.thread.updateTimeZone();
1047 } catch (RemoteException ex) {
1048 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1049 }
1050 }
1051 }
1052 }
1053 break;
1054 }
1055 case SHOW_UID_ERROR_MSG: {
1056 // XXX This is a temporary dialog, no need to localize.
1057 AlertDialog d = new BaseErrorDialog(mContext);
1058 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1059 d.setCancelable(false);
1060 d.setTitle("System UIDs Inconsistent");
1061 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1062 d.setButton("I'm Feeling Lucky",
1063 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1064 mUidAlert = d;
1065 d.show();
1066 } break;
1067 case IM_FEELING_LUCKY_MSG: {
1068 if (mUidAlert != null) {
1069 mUidAlert.dismiss();
1070 mUidAlert = null;
1071 }
1072 } break;
1073 case LAUNCH_TIMEOUT_MSG: {
1074 synchronized (ActivityManagerService.this) {
1075 if (mLaunchingActivity.isHeld()) {
1076 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1077 mLaunchingActivity.release();
1078 }
1079 }
1080 } break;
1081 case SERVICE_ERROR_MSG: {
1082 ServiceRecord srv = (ServiceRecord)msg.obj;
1083 // This needs to be *un*synchronized to avoid deadlock.
1084 Checkin.logEvent(mContext.getContentResolver(),
1085 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1086 srv.name.toShortString());
1087 } break;
1088 case RESUME_TOP_ACTIVITY_MSG: {
1089 synchronized (ActivityManagerService.this) {
1090 resumeTopActivityLocked(null);
1091 }
1092 }
1093 case PROC_START_TIMEOUT_MSG: {
1094 ProcessRecord app = (ProcessRecord)msg.obj;
1095 synchronized (ActivityManagerService.this) {
1096 processStartTimedOutLocked(app);
1097 }
1098 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001099 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1100 synchronized (ActivityManagerService.this) {
1101 doPendingActivityLaunchesLocked(true);
1102 }
1103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 }
1105 }
1106 };
1107
1108 public static void setSystemProcess() {
1109 try {
1110 ActivityManagerService m = mSelf;
1111
1112 ServiceManager.addService("activity", m);
1113 ServiceManager.addService("meminfo", new MemBinder(m));
1114 if (MONITOR_CPU_USAGE) {
1115 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1116 }
1117 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1118 ServiceManager.addService("activity.services", new ServicesBinder(m));
1119 ServiceManager.addService("activity.senders", new SendersBinder(m));
1120 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1121 ServiceManager.addService("permission", new PermissionController(m));
1122
1123 ApplicationInfo info =
1124 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001125 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 synchronized (mSelf) {
1127 ProcessRecord app = mSelf.newProcessRecordLocked(
1128 mSystemThread.getApplicationThread(), info,
1129 info.processName);
1130 app.persistent = true;
1131 app.pid = Process.myPid();
1132 app.maxAdj = SYSTEM_ADJ;
1133 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1134 synchronized (mSelf.mPidsSelfLocked) {
1135 mSelf.mPidsSelfLocked.put(app.pid, app);
1136 }
1137 mSelf.updateLRUListLocked(app, true);
1138 }
1139 } catch (PackageManager.NameNotFoundException e) {
1140 throw new RuntimeException(
1141 "Unable to find android system package", e);
1142 }
1143 }
1144
1145 public void setWindowManager(WindowManagerService wm) {
1146 mWindowManager = wm;
1147 }
1148
1149 public static final Context main(int factoryTest) {
1150 AThread thr = new AThread();
1151 thr.start();
1152
1153 synchronized (thr) {
1154 while (thr.mService == null) {
1155 try {
1156 thr.wait();
1157 } catch (InterruptedException e) {
1158 }
1159 }
1160 }
1161
1162 ActivityManagerService m = thr.mService;
1163 mSelf = m;
1164 ActivityThread at = ActivityThread.systemMain();
1165 mSystemThread = at;
1166 Context context = at.getSystemContext();
1167 m.mContext = context;
1168 m.mFactoryTest = factoryTest;
1169 PowerManager pm =
1170 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1171 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1172 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1173 m.mLaunchingActivity.setReferenceCounted(false);
1174
1175 m.mBatteryStatsService.publish(context);
1176 m.mUsageStatsService.publish(context);
1177
1178 synchronized (thr) {
1179 thr.mReady = true;
1180 thr.notifyAll();
1181 }
1182
1183 m.startRunning(null, null, null, null);
1184
1185 return context;
1186 }
1187
1188 public static ActivityManagerService self() {
1189 return mSelf;
1190 }
1191
1192 static class AThread extends Thread {
1193 ActivityManagerService mService;
1194 boolean mReady = false;
1195
1196 public AThread() {
1197 super("ActivityManager");
1198 }
1199
1200 public void run() {
1201 Looper.prepare();
1202
1203 android.os.Process.setThreadPriority(
1204 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1205
1206 ActivityManagerService m = new ActivityManagerService();
1207
1208 synchronized (this) {
1209 mService = m;
1210 notifyAll();
1211 }
1212
1213 synchronized (this) {
1214 while (!mReady) {
1215 try {
1216 wait();
1217 } catch (InterruptedException e) {
1218 }
1219 }
1220 }
1221
1222 Looper.loop();
1223 }
1224 }
1225
1226 static class BroadcastsBinder extends Binder {
1227 ActivityManagerService mActivityManagerService;
1228 BroadcastsBinder(ActivityManagerService activityManagerService) {
1229 mActivityManagerService = activityManagerService;
1230 }
1231
1232 @Override
1233 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1234 mActivityManagerService.dumpBroadcasts(pw);
1235 }
1236 }
1237
1238 static class ServicesBinder extends Binder {
1239 ActivityManagerService mActivityManagerService;
1240 ServicesBinder(ActivityManagerService activityManagerService) {
1241 mActivityManagerService = activityManagerService;
1242 }
1243
1244 @Override
1245 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1246 mActivityManagerService.dumpServices(pw);
1247 }
1248 }
1249
1250 static class SendersBinder extends Binder {
1251 ActivityManagerService mActivityManagerService;
1252 SendersBinder(ActivityManagerService activityManagerService) {
1253 mActivityManagerService = activityManagerService;
1254 }
1255
1256 @Override
1257 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1258 mActivityManagerService.dumpSenders(pw);
1259 }
1260 }
1261
1262 static class ProvidersBinder extends Binder {
1263 ActivityManagerService mActivityManagerService;
1264 ProvidersBinder(ActivityManagerService activityManagerService) {
1265 mActivityManagerService = activityManagerService;
1266 }
1267
1268 @Override
1269 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1270 mActivityManagerService.dumpProviders(pw);
1271 }
1272 }
1273
1274 static class MemBinder extends Binder {
1275 ActivityManagerService mActivityManagerService;
1276 MemBinder(ActivityManagerService activityManagerService) {
1277 mActivityManagerService = activityManagerService;
1278 }
1279
1280 @Override
1281 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1282 ActivityManagerService service = mActivityManagerService;
1283 ArrayList<ProcessRecord> procs;
1284 synchronized (mActivityManagerService) {
1285 if (args != null && args.length > 0
1286 && args[0].charAt(0) != '-') {
1287 procs = new ArrayList<ProcessRecord>();
1288 int pid = -1;
1289 try {
1290 pid = Integer.parseInt(args[0]);
1291 } catch (NumberFormatException e) {
1292
1293 }
1294 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1295 ProcessRecord proc = service.mLRUProcesses.get(i);
1296 if (proc.pid == pid) {
1297 procs.add(proc);
1298 } else if (proc.processName.equals(args[0])) {
1299 procs.add(proc);
1300 }
1301 }
1302 if (procs.size() <= 0) {
1303 pw.println("No process found for: " + args[0]);
1304 return;
1305 }
1306 } else {
1307 procs = service.mLRUProcesses;
1308 }
1309 }
1310 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1311 }
1312 }
1313
1314 static class CpuBinder extends Binder {
1315 ActivityManagerService mActivityManagerService;
1316 CpuBinder(ActivityManagerService activityManagerService) {
1317 mActivityManagerService = activityManagerService;
1318 }
1319
1320 @Override
1321 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1322 synchronized (mActivityManagerService.mProcessStatsThread) {
1323 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1324 }
1325 }
1326 }
1327
1328 private ActivityManagerService() {
1329 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1330 if (v != null && Integer.getInteger(v) != 0) {
1331 mSimpleProcessManagement = true;
1332 }
1333 v = System.getenv("ANDROID_DEBUG_APP");
1334 if (v != null) {
1335 mSimpleProcessManagement = true;
1336 }
1337
1338 MY_PID = Process.myPid();
1339
1340 File dataDir = Environment.getDataDirectory();
1341 File systemDir = new File(dataDir, "system");
1342 systemDir.mkdirs();
1343 mBatteryStatsService = new BatteryStatsService(new File(
1344 systemDir, "batterystats.bin").toString());
1345 mBatteryStatsService.getActiveStatistics().readLocked();
1346 mBatteryStatsService.getActiveStatistics().writeLocked();
1347
1348 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001349 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350
1351 mConfiguration.makeDefault();
1352 mProcessStats.init();
1353
1354 // Add ourself to the Watchdog monitors.
1355 Watchdog.getInstance().addMonitor(this);
1356
1357 // These values are set in system/rootdir/init.rc on startup.
1358 FOREGROUND_APP_ADJ =
1359 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1360 VISIBLE_APP_ADJ =
1361 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1362 SECONDARY_SERVER_ADJ =
1363 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001364 BACKUP_APP_ADJ =
1365 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001366 HOME_APP_ADJ =
1367 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368 HIDDEN_APP_MIN_ADJ =
1369 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1370 CONTENT_PROVIDER_ADJ =
1371 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1372 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1373 EMPTY_APP_ADJ =
1374 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1375 FOREGROUND_APP_MEM =
1376 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1377 VISIBLE_APP_MEM =
1378 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1379 SECONDARY_SERVER_MEM =
1380 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001381 BACKUP_APP_MEM =
1382 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001383 HOME_APP_MEM =
1384 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 HIDDEN_APP_MEM =
1386 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1387 EMPTY_APP_MEM =
1388 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1389
1390 mProcessStatsThread = new Thread("ProcessStats") {
1391 public void run() {
1392 while (true) {
1393 try {
1394 try {
1395 synchronized(this) {
1396 final long now = SystemClock.uptimeMillis();
1397 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1398 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1399 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1400 // + ", write delay=" + nextWriteDelay);
1401 if (nextWriteDelay < nextCpuDelay) {
1402 nextCpuDelay = nextWriteDelay;
1403 }
1404 if (nextCpuDelay > 0) {
1405 this.wait(nextCpuDelay);
1406 }
1407 }
1408 } catch (InterruptedException e) {
1409 }
1410
1411 updateCpuStatsNow();
1412 } catch (Exception e) {
1413 Log.e(TAG, "Unexpected exception collecting process stats", e);
1414 }
1415 }
1416 }
1417 };
1418 mProcessStatsThread.start();
1419 }
1420
1421 @Override
1422 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1423 throws RemoteException {
1424 try {
1425 return super.onTransact(code, data, reply, flags);
1426 } catch (RuntimeException e) {
1427 // The activity manager only throws security exceptions, so let's
1428 // log all others.
1429 if (!(e instanceof SecurityException)) {
1430 Log.e(TAG, "Activity Manager Crash", e);
1431 }
1432 throw e;
1433 }
1434 }
1435
1436 void updateCpuStats() {
1437 synchronized (mProcessStatsThread) {
1438 final long now = SystemClock.uptimeMillis();
1439 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1440 mProcessStatsThread.notify();
1441 }
1442 }
1443 }
1444
1445 void updateCpuStatsNow() {
1446 synchronized (mProcessStatsThread) {
1447 final long now = SystemClock.uptimeMillis();
1448 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450 if (MONITOR_CPU_USAGE &&
1451 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1452 mLastCpuTime = now;
1453 haveNewCpuStats = true;
1454 mProcessStats.update();
1455 //Log.i(TAG, mProcessStats.printCurrentState());
1456 //Log.i(TAG, "Total CPU usage: "
1457 // + mProcessStats.getTotalCpuPercent() + "%");
1458
1459 // Log the cpu usage if the property is set.
1460 if ("true".equals(SystemProperties.get("events.cpu"))) {
1461 int user = mProcessStats.getLastUserTime();
1462 int system = mProcessStats.getLastSystemTime();
1463 int iowait = mProcessStats.getLastIoWaitTime();
1464 int irq = mProcessStats.getLastIrqTime();
1465 int softIrq = mProcessStats.getLastSoftIrqTime();
1466 int idle = mProcessStats.getLastIdleTime();
1467
1468 int total = user + system + iowait + irq + softIrq + idle;
1469 if (total == 0) total = 1;
1470
1471 EventLog.writeEvent(LOG_CPU,
1472 ((user+system+iowait+irq+softIrq) * 100) / total,
1473 (user * 100) / total,
1474 (system * 100) / total,
1475 (iowait * 100) / total,
1476 (irq * 100) / total,
1477 (softIrq * 100) / total);
1478 }
1479 }
1480
1481 synchronized(mBatteryStatsService.getActiveStatistics()) {
1482 synchronized(mPidsSelfLocked) {
1483 if (haveNewCpuStats) {
1484 if (mBatteryStatsService.isOnBattery()) {
1485 final int N = mProcessStats.countWorkingStats();
1486 for (int i=0; i<N; i++) {
1487 ProcessStats.Stats st
1488 = mProcessStats.getWorkingStats(i);
1489 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1490 if (pr != null) {
1491 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1492 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1493 }
1494 }
1495 }
1496 }
1497 }
1498
1499 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1500 mLastWriteTime = now;
1501 mBatteryStatsService.getActiveStatistics().writeLocked();
1502 }
1503 }
1504 }
1505 }
1506
1507 /**
1508 * Initialize the application bind args. These are passed to each
1509 * process when the bindApplication() IPC is sent to the process. They're
1510 * lazily setup to make sure the services are running when they're asked for.
1511 */
1512 private HashMap<String, IBinder> getCommonServicesLocked() {
1513 if (mAppBindArgs == null) {
1514 mAppBindArgs = new HashMap<String, IBinder>();
1515
1516 // Setup the application init args
1517 mAppBindArgs.put("package", ServiceManager.getService("package"));
1518 mAppBindArgs.put("window", ServiceManager.getService("window"));
1519 mAppBindArgs.put(Context.ALARM_SERVICE,
1520 ServiceManager.getService(Context.ALARM_SERVICE));
1521 }
1522 return mAppBindArgs;
1523 }
1524
1525 private final void setFocusedActivityLocked(HistoryRecord r) {
1526 if (mFocusedActivity != r) {
1527 mFocusedActivity = r;
1528 mWindowManager.setFocusedApp(r, true);
1529 }
1530 }
1531
1532 private final void updateLRUListLocked(ProcessRecord app,
1533 boolean oomAdj) {
1534 // put it on the LRU to keep track of when it should be exited.
1535 int lrui = mLRUProcesses.indexOf(app);
1536 if (lrui >= 0) mLRUProcesses.remove(lrui);
1537 mLRUProcesses.add(app);
1538 //Log.i(TAG, "Putting proc to front: " + app.processName);
1539 if (oomAdj) {
1540 updateOomAdjLocked();
1541 }
1542 }
1543
1544 private final boolean updateLRUListLocked(HistoryRecord r) {
1545 final boolean hadit = mLRUActivities.remove(r);
1546 mLRUActivities.add(r);
1547 return hadit;
1548 }
1549
1550 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1551 int i = mHistory.size()-1;
1552 while (i >= 0) {
1553 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1554 if (!r.finishing && r != notTop) {
1555 return r;
1556 }
1557 i--;
1558 }
1559 return null;
1560 }
1561
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001562 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1563 int i = mHistory.size()-1;
1564 while (i >= 0) {
1565 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1566 if (!r.finishing && !r.delayedResume && r != notTop) {
1567 return r;
1568 }
1569 i--;
1570 }
1571 return null;
1572 }
1573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 /**
1575 * This is a simplified version of topRunningActivityLocked that provides a number of
1576 * optional skip-over modes. It is intended for use with the ActivityWatcher hook only.
1577 *
1578 * @param token If non-null, any history records matching this token will be skipped.
1579 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1580 *
1581 * @return Returns the HistoryRecord of the next activity on the stack.
1582 */
1583 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1584 int i = mHistory.size()-1;
1585 while (i >= 0) {
1586 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1587 // Note: the taskId check depends on real taskId fields being non-zero
1588 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1589 return r;
1590 }
1591 i--;
1592 }
1593 return null;
1594 }
1595
1596 private final ProcessRecord getProcessRecordLocked(
1597 String processName, int uid) {
1598 if (uid == Process.SYSTEM_UID) {
1599 // The system gets to run in any process. If there are multiple
1600 // processes with the same uid, just pick the first (this
1601 // should never happen).
1602 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1603 processName);
1604 return procs != null ? procs.valueAt(0) : null;
1605 }
1606 ProcessRecord proc = mProcessNames.get(processName, uid);
1607 return proc;
1608 }
1609
1610 private boolean isNextTransitionForward() {
1611 int transit = mWindowManager.getPendingAppTransition();
1612 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1613 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1614 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1615 }
1616
1617 private final boolean realStartActivityLocked(HistoryRecord r,
1618 ProcessRecord app, boolean andResume, boolean checkConfig)
1619 throws RemoteException {
1620
1621 r.startFreezingScreenLocked(app, 0);
1622 mWindowManager.setAppVisibility(r, true);
1623
1624 // Have the window manager re-evaluate the orientation of
1625 // the screen based on the new activity order. Note that
1626 // as a result of this, it can call back into the activity
1627 // manager with a new orientation. We don't care about that,
1628 // because the activity is not currently running so we are
1629 // just restarting it anyway.
1630 if (checkConfig) {
1631 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001632 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 r.mayFreezeScreenLocked(app) ? r : null);
1634 updateConfigurationLocked(config, r);
1635 }
1636
1637 r.app = app;
1638
1639 if (localLOGV) Log.v(TAG, "Launching: " + r);
1640
1641 int idx = app.activities.indexOf(r);
1642 if (idx < 0) {
1643 app.activities.add(r);
1644 }
1645 updateLRUListLocked(app, true);
1646
1647 try {
1648 if (app.thread == null) {
1649 throw new RemoteException();
1650 }
1651 List<ResultInfo> results = null;
1652 List<Intent> newIntents = null;
1653 if (andResume) {
1654 results = r.results;
1655 newIntents = r.newIntents;
1656 }
1657 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1658 + " icicle=" + r.icicle
1659 + " with results=" + results + " newIntents=" + newIntents
1660 + " andResume=" + andResume);
1661 if (andResume) {
1662 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1663 System.identityHashCode(r),
1664 r.task.taskId, r.shortComponentName);
1665 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001666 if (r.isHomeActivity) {
1667 mHomeProcess = app;
1668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
1670 r.info, r.icicle, results, newIntents, !andResume,
1671 isNextTransitionForward());
1672 // Update usage stats for launched activity
1673 updateUsageStats(r, true);
1674 } catch (RemoteException e) {
1675 if (r.launchFailed) {
1676 // This is the second time we failed -- finish activity
1677 // and give up.
1678 Log.e(TAG, "Second failure launching "
1679 + r.intent.getComponent().flattenToShortString()
1680 + ", giving up", e);
1681 appDiedLocked(app, app.pid, app.thread);
1682 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1683 "2nd-crash");
1684 return false;
1685 }
1686
1687 // This is the first time we failed -- restart process and
1688 // retry.
1689 app.activities.remove(r);
1690 throw e;
1691 }
1692
1693 r.launchFailed = false;
1694 if (updateLRUListLocked(r)) {
1695 Log.w(TAG, "Activity " + r
1696 + " being launched, but already in LRU list");
1697 }
1698
1699 if (andResume) {
1700 // As part of the process of launching, ActivityThread also performs
1701 // a resume.
1702 r.state = ActivityState.RESUMED;
1703 r.icicle = null;
1704 r.haveState = false;
1705 r.stopped = false;
1706 mResumedActivity = r;
1707 r.task.touchActiveTime();
1708 completeResumeLocked(r);
1709 pauseIfSleepingLocked();
1710 } else {
1711 // This activity is not starting in the resumed state... which
1712 // should look like we asked it to pause+stop (but remain visible),
1713 // and it has done so and reported back the current icicle and
1714 // other state.
1715 r.state = ActivityState.STOPPED;
1716 r.stopped = true;
1717 }
1718
1719 return true;
1720 }
1721
1722 private final void startSpecificActivityLocked(HistoryRecord r,
1723 boolean andResume, boolean checkConfig) {
1724 // Is this activity's application already running?
1725 ProcessRecord app = getProcessRecordLocked(r.processName,
1726 r.info.applicationInfo.uid);
1727
1728 if (r.startTime == 0) {
1729 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001730 if (mInitialStartTime == 0) {
1731 mInitialStartTime = r.startTime;
1732 }
1733 } else if (mInitialStartTime == 0) {
1734 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 }
1736
1737 if (app != null && app.thread != null) {
1738 try {
1739 realStartActivityLocked(r, app, andResume, checkConfig);
1740 return;
1741 } catch (RemoteException e) {
1742 Log.w(TAG, "Exception when starting activity "
1743 + r.intent.getComponent().flattenToShortString(), e);
1744 }
1745
1746 // If a dead object exception was thrown -- fall through to
1747 // restart the application.
1748 }
1749
1750 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1751 "activity", r.intent.getComponent());
1752 }
1753
1754 private final ProcessRecord startProcessLocked(String processName,
1755 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1756 String hostingType, ComponentName hostingName) {
1757 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1758 // We don't have to do anything more if:
1759 // (1) There is an existing application record; and
1760 // (2) The caller doesn't think it is dead, OR there is no thread
1761 // object attached to it so we know it couldn't have crashed; and
1762 // (3) There is a pid assigned to it, so it is either starting or
1763 // already running.
1764 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1765 + " app=" + app + " knownToBeDead=" + knownToBeDead
1766 + " thread=" + (app != null ? app.thread : null)
1767 + " pid=" + (app != null ? app.pid : -1));
1768 if (app != null &&
1769 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1770 return app;
1771 }
1772
1773 String hostingNameStr = hostingName != null
1774 ? hostingName.flattenToShortString() : null;
1775
1776 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1777 // If we are in the background, then check to see if this process
1778 // is bad. If so, we will just silently fail.
1779 if (mBadProcesses.get(info.processName, info.uid) != null) {
1780 return null;
1781 }
1782 } else {
1783 // When the user is explicitly starting a process, then clear its
1784 // crash count so that we won't make it bad until they see at
1785 // least one crash dialog again, and make the process good again
1786 // if it had been bad.
1787 mProcessCrashTimes.remove(info.processName, info.uid);
1788 if (mBadProcesses.get(info.processName, info.uid) != null) {
1789 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1790 info.processName);
1791 mBadProcesses.remove(info.processName, info.uid);
1792 if (app != null) {
1793 app.bad = false;
1794 }
1795 }
1796 }
1797
1798 if (app == null) {
1799 app = newProcessRecordLocked(null, info, processName);
1800 mProcessNames.put(processName, info.uid, app);
1801 } else {
1802 // If this is a new package in the process, add the package to the list
1803 app.addPackage(info.packageName);
1804 }
1805
1806 // If the system is not ready yet, then hold off on starting this
1807 // process until it is.
1808 if (!mSystemReady
1809 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1810 if (!mProcessesOnHold.contains(app)) {
1811 mProcessesOnHold.add(app);
1812 }
1813 return app;
1814 }
1815
1816 startProcessLocked(app, hostingType, hostingNameStr);
1817 return (app.pid != 0) ? app : null;
1818 }
1819
1820 private final void startProcessLocked(ProcessRecord app,
1821 String hostingType, String hostingNameStr) {
1822 if (app.pid > 0 && app.pid != MY_PID) {
1823 synchronized (mPidsSelfLocked) {
1824 mPidsSelfLocked.remove(app.pid);
1825 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1826 }
1827 app.pid = 0;
1828 }
1829
1830 mProcessesOnHold.remove(app);
1831
1832 updateCpuStats();
1833
1834 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1835 mProcDeaths[0] = 0;
1836
1837 try {
1838 int uid = app.info.uid;
1839 int[] gids = null;
1840 try {
1841 gids = mContext.getPackageManager().getPackageGids(
1842 app.info.packageName);
1843 } catch (PackageManager.NameNotFoundException e) {
1844 Log.w(TAG, "Unable to retrieve gids", e);
1845 }
1846 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1847 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1848 && mTopComponent != null
1849 && app.processName.equals(mTopComponent.getPackageName())) {
1850 uid = 0;
1851 }
1852 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1853 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1854 uid = 0;
1855 }
1856 }
1857 int debugFlags = 0;
1858 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1859 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1860 }
1861 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1862 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1863 }
1864 if ("1".equals(SystemProperties.get("debug.assert"))) {
1865 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1866 }
1867 int pid = Process.start("android.app.ActivityThread",
1868 mSimpleProcessManagement ? app.processName : null, uid, uid,
1869 gids, debugFlags, null);
1870 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1871 synchronized (bs) {
1872 if (bs.isOnBattery()) {
1873 app.batteryStats.incStartsLocked();
1874 }
1875 }
1876
1877 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1878 app.processName, hostingType,
1879 hostingNameStr != null ? hostingNameStr : "");
1880
1881 if (app.persistent) {
1882 Watchdog.getInstance().processStarted(app, app.processName, pid);
1883 }
1884
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001885 StringBuilder buf = mStringBuilder;
1886 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 buf.append("Start proc ");
1888 buf.append(app.processName);
1889 buf.append(" for ");
1890 buf.append(hostingType);
1891 if (hostingNameStr != null) {
1892 buf.append(" ");
1893 buf.append(hostingNameStr);
1894 }
1895 buf.append(": pid=");
1896 buf.append(pid);
1897 buf.append(" uid=");
1898 buf.append(uid);
1899 buf.append(" gids={");
1900 if (gids != null) {
1901 for (int gi=0; gi<gids.length; gi++) {
1902 if (gi != 0) buf.append(", ");
1903 buf.append(gids[gi]);
1904
1905 }
1906 }
1907 buf.append("}");
1908 Log.i(TAG, buf.toString());
1909 if (pid == 0 || pid == MY_PID) {
1910 // Processes are being emulated with threads.
1911 app.pid = MY_PID;
1912 app.removed = false;
1913 mStartingProcesses.add(app);
1914 } else if (pid > 0) {
1915 app.pid = pid;
1916 app.removed = false;
1917 synchronized (mPidsSelfLocked) {
1918 this.mPidsSelfLocked.put(pid, app);
1919 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1920 msg.obj = app;
1921 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1922 }
1923 } else {
1924 app.pid = 0;
1925 RuntimeException e = new RuntimeException(
1926 "Failure starting process " + app.processName
1927 + ": returned pid=" + pid);
1928 Log.e(TAG, e.getMessage(), e);
1929 }
1930 } catch (RuntimeException e) {
1931 // XXX do better error recovery.
1932 app.pid = 0;
1933 Log.e(TAG, "Failure starting process " + app.processName, e);
1934 }
1935 }
1936
1937 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
1938 if (mPausingActivity != null) {
1939 RuntimeException e = new RuntimeException();
1940 Log.e(TAG, "Trying to pause when pause is already pending for "
1941 + mPausingActivity, e);
1942 }
1943 HistoryRecord prev = mResumedActivity;
1944 if (prev == null) {
1945 RuntimeException e = new RuntimeException();
1946 Log.e(TAG, "Trying to pause when nothing is resumed", e);
1947 resumeTopActivityLocked(null);
1948 return;
1949 }
1950 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
1951 mResumedActivity = null;
1952 mPausingActivity = prev;
1953 mLastPausedActivity = prev;
1954 prev.state = ActivityState.PAUSING;
1955 prev.task.touchActiveTime();
1956
1957 updateCpuStats();
1958
1959 if (prev.app != null && prev.app.thread != null) {
1960 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
1961 try {
1962 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
1963 System.identityHashCode(prev),
1964 prev.shortComponentName);
1965 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
1966 prev.configChangeFlags);
1967 updateUsageStats(prev, false);
1968 } catch (Exception e) {
1969 // Ignore exception, if process died other code will cleanup.
1970 Log.w(TAG, "Exception thrown during pause", e);
1971 mPausingActivity = null;
1972 mLastPausedActivity = null;
1973 }
1974 } else {
1975 mPausingActivity = null;
1976 mLastPausedActivity = null;
1977 }
1978
1979 // If we are not going to sleep, we want to ensure the device is
1980 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07001981 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 mLaunchingActivity.acquire();
1983 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
1984 // To be safe, don't allow the wake lock to be held for too long.
1985 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1986 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
1987 }
1988 }
1989
1990
1991 if (mPausingActivity != null) {
1992 // Have the window manager pause its key dispatching until the new
1993 // activity has started. If we're pausing the activity just because
1994 // the screen is being turned off and the UI is sleeping, don't interrupt
1995 // key dispatch; the same activity will pick it up again on wakeup.
1996 if (!uiSleeping) {
1997 prev.pauseKeyDispatchingLocked();
1998 } else {
1999 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2000 }
2001
2002 // Schedule a pause timeout in case the app doesn't respond.
2003 // We don't give it much time because this directly impacts the
2004 // responsiveness seen by the user.
2005 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2006 msg.obj = prev;
2007 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2008 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2009 } else {
2010 // This activity failed to schedule the
2011 // pause, so just treat it as being paused now.
2012 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2013 resumeTopActivityLocked(null);
2014 }
2015 }
2016
2017 private final void completePauseLocked() {
2018 HistoryRecord prev = mPausingActivity;
2019 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2020
2021 if (prev != null) {
2022 if (prev.finishing) {
2023 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2024 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2025 } else if (prev.app != null) {
2026 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2027 if (prev.waitingVisible) {
2028 prev.waitingVisible = false;
2029 mWaitingVisibleActivities.remove(prev);
2030 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2031 TAG, "Complete pause, no longer waiting: " + prev);
2032 }
2033 if (prev.configDestroy) {
2034 // The previous is being paused because the configuration
2035 // is changing, which means it is actually stopping...
2036 // To juggle the fact that we are also starting a new
2037 // instance right now, we need to first completely stop
2038 // the current instance before starting the new one.
2039 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2040 destroyActivityLocked(prev, true);
2041 } else {
2042 mStoppingActivities.add(prev);
2043 if (mStoppingActivities.size() > 3) {
2044 // If we already have a few activities waiting to stop,
2045 // then give up on things going idle and start clearing
2046 // them out.
2047 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2048 Message msg = Message.obtain();
2049 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2050 mHandler.sendMessage(msg);
2051 }
2052 }
2053 } else {
2054 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2055 prev = null;
2056 }
2057 mPausingActivity = null;
2058 }
2059
Dianne Hackborn55280a92009-05-07 15:53:46 -07002060 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 resumeTopActivityLocked(prev);
2062 } else {
2063 if (mGoingToSleep.isHeld()) {
2064 mGoingToSleep.release();
2065 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002066 if (mShuttingDown) {
2067 notifyAll();
2068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 }
2070
2071 if (prev != null) {
2072 prev.resumeKeyDispatchingLocked();
2073 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002074
2075 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2076 long diff = 0;
2077 synchronized (mProcessStatsThread) {
2078 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2079 }
2080 if (diff > 0) {
2081 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2082 synchronized (bsi) {
2083 BatteryStatsImpl.Uid.Proc ps =
2084 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2085 prev.info.packageName);
2086 if (ps != null) {
2087 ps.addForegroundTimeLocked(diff);
2088 }
2089 }
2090 }
2091 }
2092 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 }
2094
2095 /**
2096 * Once we know that we have asked an application to put an activity in
2097 * the resumed state (either by launching it or explicitly telling it),
2098 * this function updates the rest of our state to match that fact.
2099 */
2100 private final void completeResumeLocked(HistoryRecord next) {
2101 next.idle = false;
2102 next.results = null;
2103 next.newIntents = null;
2104
2105 // schedule an idle timeout in case the app doesn't do it for us.
2106 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2107 msg.obj = next;
2108 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2109
2110 if (false) {
2111 // The activity was never told to pause, so just keep
2112 // things going as-is. To maintain our own state,
2113 // we need to emulate it coming back and saying it is
2114 // idle.
2115 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2116 msg.obj = next;
2117 mHandler.sendMessage(msg);
2118 }
2119
2120 next.thumbnail = null;
2121 setFocusedActivityLocked(next);
2122 next.resumeKeyDispatchingLocked();
2123 ensureActivitiesVisibleLocked(null, 0);
2124 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002125
2126 // Mark the point when the activity is resuming
2127 // TODO: To be more accurate, the mark should be before the onCreate,
2128 // not after the onResume. But for subsequent starts, onResume is fine.
2129 if (next.app != null) {
2130 synchronized (mProcessStatsThread) {
2131 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2132 }
2133 } else {
2134 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 }
2137
2138 /**
2139 * Make sure that all activities that need to be visible (that is, they
2140 * currently can be seen by the user) actually are.
2141 */
2142 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2143 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2144 if (DEBUG_VISBILITY) Log.v(
2145 TAG, "ensureActivitiesVisible behind " + top
2146 + " configChanges=0x" + Integer.toHexString(configChanges));
2147
2148 // If the top activity is not fullscreen, then we need to
2149 // make sure any activities under it are now visible.
2150 final int count = mHistory.size();
2151 int i = count-1;
2152 while (mHistory.get(i) != top) {
2153 i--;
2154 }
2155 HistoryRecord r;
2156 boolean behindFullscreen = false;
2157 for (; i>=0; i--) {
2158 r = (HistoryRecord)mHistory.get(i);
2159 if (DEBUG_VISBILITY) Log.v(
2160 TAG, "Make visible? " + r + " finishing=" + r.finishing
2161 + " state=" + r.state);
2162 if (r.finishing) {
2163 continue;
2164 }
2165
2166 final boolean doThisProcess = onlyThisProcess == null
2167 || onlyThisProcess.equals(r.processName);
2168
2169 // First: if this is not the current activity being started, make
2170 // sure it matches the current configuration.
2171 if (r != starting && doThisProcess) {
2172 ensureActivityConfigurationLocked(r, 0);
2173 }
2174
2175 if (r.app == null || r.app.thread == null) {
2176 if (onlyThisProcess == null
2177 || onlyThisProcess.equals(r.processName)) {
2178 // This activity needs to be visible, but isn't even
2179 // running... get it started, but don't resume it
2180 // at this point.
2181 if (DEBUG_VISBILITY) Log.v(
2182 TAG, "Start and freeze screen for " + r);
2183 if (r != starting) {
2184 r.startFreezingScreenLocked(r.app, configChanges);
2185 }
2186 if (!r.visible) {
2187 if (DEBUG_VISBILITY) Log.v(
2188 TAG, "Starting and making visible: " + r);
2189 mWindowManager.setAppVisibility(r, true);
2190 }
2191 if (r != starting) {
2192 startSpecificActivityLocked(r, false, false);
2193 }
2194 }
2195
2196 } else if (r.visible) {
2197 // If this activity is already visible, then there is nothing
2198 // else to do here.
2199 if (DEBUG_VISBILITY) Log.v(
2200 TAG, "Skipping: already visible at " + r);
2201 r.stopFreezingScreenLocked(false);
2202
2203 } else if (onlyThisProcess == null) {
2204 // This activity is not currently visible, but is running.
2205 // Tell it to become visible.
2206 r.visible = true;
2207 if (r.state != ActivityState.RESUMED && r != starting) {
2208 // If this activity is paused, tell it
2209 // to now show its window.
2210 if (DEBUG_VISBILITY) Log.v(
2211 TAG, "Making visible and scheduling visibility: " + r);
2212 try {
2213 mWindowManager.setAppVisibility(r, true);
2214 r.app.thread.scheduleWindowVisibility(r, true);
2215 r.stopFreezingScreenLocked(false);
2216 } catch (Exception e) {
2217 // Just skip on any failure; we'll make it
2218 // visible when it next restarts.
2219 Log.w(TAG, "Exception thrown making visibile: "
2220 + r.intent.getComponent(), e);
2221 }
2222 }
2223 }
2224
2225 // Aggregate current change flags.
2226 configChanges |= r.configChangeFlags;
2227
2228 if (r.fullscreen) {
2229 // At this point, nothing else needs to be shown
2230 if (DEBUG_VISBILITY) Log.v(
2231 TAG, "Stopping: fullscreen at " + r);
2232 behindFullscreen = true;
2233 i--;
2234 break;
2235 }
2236 }
2237
2238 // Now for any activities that aren't visible to the user, make
2239 // sure they no longer are keeping the screen frozen.
2240 while (i >= 0) {
2241 r = (HistoryRecord)mHistory.get(i);
2242 if (DEBUG_VISBILITY) Log.v(
2243 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2244 + " state=" + r.state
2245 + " behindFullscreen=" + behindFullscreen);
2246 if (!r.finishing) {
2247 if (behindFullscreen) {
2248 if (r.visible) {
2249 if (DEBUG_VISBILITY) Log.v(
2250 TAG, "Making invisible: " + r);
2251 r.visible = false;
2252 try {
2253 mWindowManager.setAppVisibility(r, false);
2254 if ((r.state == ActivityState.STOPPING
2255 || r.state == ActivityState.STOPPED)
2256 && r.app != null && r.app.thread != null) {
2257 if (DEBUG_VISBILITY) Log.v(
2258 TAG, "Scheduling invisibility: " + r);
2259 r.app.thread.scheduleWindowVisibility(r, false);
2260 }
2261 } catch (Exception e) {
2262 // Just skip on any failure; we'll make it
2263 // visible when it next restarts.
2264 Log.w(TAG, "Exception thrown making hidden: "
2265 + r.intent.getComponent(), e);
2266 }
2267 } else {
2268 if (DEBUG_VISBILITY) Log.v(
2269 TAG, "Already invisible: " + r);
2270 }
2271 } else if (r.fullscreen) {
2272 if (DEBUG_VISBILITY) Log.v(
2273 TAG, "Now behindFullscreen: " + r);
2274 behindFullscreen = true;
2275 }
2276 }
2277 i--;
2278 }
2279 }
2280
2281 /**
2282 * Version of ensureActivitiesVisible that can easily be called anywhere.
2283 */
2284 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2285 int configChanges) {
2286 HistoryRecord r = topRunningActivityLocked(null);
2287 if (r != null) {
2288 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2289 }
2290 }
2291
2292 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2293 if (resumed) {
2294 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2295 } else {
2296 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2297 }
2298 }
2299
2300 /**
2301 * Ensure that the top activity in the stack is resumed.
2302 *
2303 * @param prev The previously resumed activity, for when in the process
2304 * of pausing; can be null to call from elsewhere.
2305 *
2306 * @return Returns true if something is being resumed, or false if
2307 * nothing happened.
2308 */
2309 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2310 // Find the first activity that is not finishing.
2311 HistoryRecord next = topRunningActivityLocked(null);
2312
2313 // Remember how we'll process this pause/resume situation, and ensure
2314 // that the state is reset however we wind up proceeding.
2315 final boolean userLeaving = mUserLeaving;
2316 mUserLeaving = false;
2317
2318 if (next == null) {
2319 // There are no more activities! Let's just start up the
2320 // Launcher...
2321 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2322 && mTopAction == null) {
2323 // We are running in factory test mode, but unable to find
2324 // the factory test app, so just sit around displaying the
2325 // error message and don't try to start anything.
2326 return false;
2327 }
2328 Intent intent = new Intent(
2329 mTopAction,
2330 mTopData != null ? Uri.parse(mTopData) : null);
2331 intent.setComponent(mTopComponent);
2332 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2333 intent.addCategory(Intent.CATEGORY_HOME);
2334 }
2335 ActivityInfo aInfo =
2336 intent.resolveActivityInfo(mContext.getPackageManager(),
Dianne Hackborn1655be42009-05-08 14:29:01 -07002337 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002338 if (aInfo != null) {
2339 intent.setComponent(new ComponentName(
2340 aInfo.applicationInfo.packageName, aInfo.name));
2341 // Don't do this if the home app is currently being
2342 // instrumented.
2343 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2344 aInfo.applicationInfo.uid);
2345 if (app == null || app.instrumentationClass == null) {
2346 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2347 startActivityLocked(null, intent, null, null, 0, aInfo,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002348 null, null, 0, 0, 0, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002349 }
2350 }
2351 return true;
2352 }
2353
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002354 next.delayedResume = false;
2355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356 // If the top activity is the resumed one, nothing to do.
2357 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2358 // Make sure we have executed any pending transitions, since there
2359 // should be nothing left to do at this point.
2360 mWindowManager.executeAppTransition();
2361 return false;
2362 }
2363
2364 // If we are sleeping, and there is no resumed activity, and the top
2365 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002366 if ((mSleeping || mShuttingDown)
2367 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002368 // Make sure we have executed any pending transitions, since there
2369 // should be nothing left to do at this point.
2370 mWindowManager.executeAppTransition();
2371 return false;
2372 }
2373
2374 // The activity may be waiting for stop, but that is no longer
2375 // appropriate for it.
2376 mStoppingActivities.remove(next);
2377 mWaitingVisibleActivities.remove(next);
2378
2379 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2380
2381 // If we are currently pausing an activity, then don't do anything
2382 // until that is done.
2383 if (mPausingActivity != null) {
2384 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2385 return false;
2386 }
2387
2388 // We need to start pausing the current activity so the top one
2389 // can be resumed...
2390 if (mResumedActivity != null) {
2391 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2392 startPausingLocked(userLeaving, false);
2393 return true;
2394 }
2395
2396 if (prev != null && prev != next) {
2397 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2398 prev.waitingVisible = true;
2399 mWaitingVisibleActivities.add(prev);
2400 if (DEBUG_SWITCH) Log.v(
2401 TAG, "Resuming top, waiting visible to hide: " + prev);
2402 } else {
2403 // The next activity is already visible, so hide the previous
2404 // activity's windows right now so we can show the new one ASAP.
2405 // We only do this if the previous is finishing, which should mean
2406 // it is on top of the one being resumed so hiding it quickly
2407 // is good. Otherwise, we want to do the normal route of allowing
2408 // the resumed activity to be shown so we can decide if the
2409 // previous should actually be hidden depending on whether the
2410 // new one is found to be full-screen or not.
2411 if (prev.finishing) {
2412 mWindowManager.setAppVisibility(prev, false);
2413 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2414 + prev + ", waitingVisible="
2415 + (prev != null ? prev.waitingVisible : null)
2416 + ", nowVisible=" + next.nowVisible);
2417 } else {
2418 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2419 + prev + ", waitingVisible="
2420 + (prev != null ? prev.waitingVisible : null)
2421 + ", nowVisible=" + next.nowVisible);
2422 }
2423 }
2424 }
2425
2426 // We are starting up the next activity, so tell the window manager
2427 // that the previous one will be hidden soon. This way it can know
2428 // to ignore it when computing the desired screen orientation.
2429 if (prev != null) {
2430 if (prev.finishing) {
2431 if (DEBUG_TRANSITION) Log.v(TAG,
2432 "Prepare close transition: prev=" + prev);
2433 mWindowManager.prepareAppTransition(prev.task == next.task
2434 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2435 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2436 mWindowManager.setAppWillBeHidden(prev);
2437 mWindowManager.setAppVisibility(prev, false);
2438 } else {
2439 if (DEBUG_TRANSITION) Log.v(TAG,
2440 "Prepare open transition: prev=" + prev);
2441 mWindowManager.prepareAppTransition(prev.task == next.task
2442 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2443 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2444 }
2445 if (false) {
2446 mWindowManager.setAppWillBeHidden(prev);
2447 mWindowManager.setAppVisibility(prev, false);
2448 }
2449 } else if (mHistory.size() > 1) {
2450 if (DEBUG_TRANSITION) Log.v(TAG,
2451 "Prepare open transition: no previous");
2452 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2453 }
2454
2455 if (next.app != null && next.app.thread != null) {
2456 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2457
2458 // This activity is now becoming visible.
2459 mWindowManager.setAppVisibility(next, true);
2460
2461 HistoryRecord lastResumedActivity = mResumedActivity;
2462 ActivityState lastState = next.state;
2463
2464 updateCpuStats();
2465
2466 next.state = ActivityState.RESUMED;
2467 mResumedActivity = next;
2468 next.task.touchActiveTime();
2469 updateLRUListLocked(next.app, true);
2470 updateLRUListLocked(next);
2471
2472 // Have the window manager re-evaluate the orientation of
2473 // the screen based on the new activity order.
2474 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002475 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002476 next.mayFreezeScreenLocked(next.app) ? next : null);
2477 if (config != null) {
2478 next.frozenBeforeDestroy = true;
2479 }
2480 if (!updateConfigurationLocked(config, next)) {
2481 // The configuration update wasn't able to keep the existing
2482 // instance of the activity, and instead started a new one.
2483 // We should be all done, but let's just make sure our activity
2484 // is still at the top and schedule another run if something
2485 // weird happened.
2486 HistoryRecord nextNext = topRunningActivityLocked(null);
2487 if (DEBUG_SWITCH) Log.i(TAG,
2488 "Activity config changed during resume: " + next
2489 + ", new next: " + nextNext);
2490 if (nextNext != next) {
2491 // Do over!
2492 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2493 }
2494 mWindowManager.executeAppTransition();
2495 return true;
2496 }
2497
2498 try {
2499 // Deliver all pending results.
2500 ArrayList a = next.results;
2501 if (a != null) {
2502 final int N = a.size();
2503 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002504 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002505 TAG, "Delivering results to " + next
2506 + ": " + a);
2507 next.app.thread.scheduleSendResult(next, a);
2508 }
2509 }
2510
2511 if (next.newIntents != null) {
2512 next.app.thread.scheduleNewIntent(next.newIntents, next);
2513 }
2514
2515 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2516 System.identityHashCode(next),
2517 next.task.taskId, next.shortComponentName);
2518 updateUsageStats(next, true);
2519
2520 next.app.thread.scheduleResumeActivity(next,
2521 isNextTransitionForward());
2522 pauseIfSleepingLocked();
2523
2524 } catch (Exception e) {
2525 // Whoops, need to restart this activity!
2526 next.state = lastState;
2527 mResumedActivity = lastResumedActivity;
2528 if (Config.LOGD) Log.d(TAG,
2529 "Restarting because process died: " + next);
2530 if (!next.hasBeenLaunched) {
2531 next.hasBeenLaunched = true;
2532 } else {
2533 if (SHOW_APP_STARTING_ICON) {
2534 mWindowManager.setAppStartingWindow(
2535 next, next.packageName, next.theme,
2536 next.nonLocalizedLabel,
2537 next.labelRes, next.icon, null, true);
2538 }
2539 }
2540 startSpecificActivityLocked(next, true, false);
2541 return true;
2542 }
2543
2544 // From this point on, if something goes wrong there is no way
2545 // to recover the activity.
2546 try {
2547 next.visible = true;
2548 completeResumeLocked(next);
2549 } catch (Exception e) {
2550 // If any exception gets thrown, toss away this
2551 // activity and try the next one.
2552 Log.w(TAG, "Exception thrown during resume of " + next, e);
2553 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2554 "resume-exception");
2555 return true;
2556 }
2557
2558 // Didn't need to use the icicle, and it is now out of date.
2559 next.icicle = null;
2560 next.haveState = false;
2561 next.stopped = false;
2562
2563 } else {
2564 // Whoops, need to restart this activity!
2565 if (!next.hasBeenLaunched) {
2566 next.hasBeenLaunched = true;
2567 } else {
2568 if (SHOW_APP_STARTING_ICON) {
2569 mWindowManager.setAppStartingWindow(
2570 next, next.packageName, next.theme,
2571 next.nonLocalizedLabel,
2572 next.labelRes, next.icon, null, true);
2573 }
2574 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2575 }
2576 startSpecificActivityLocked(next, true, true);
2577 }
2578
2579 return true;
2580 }
2581
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002582 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2583 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002584 final int NH = mHistory.size();
2585
2586 int addPos = -1;
2587
2588 if (!newTask) {
2589 // If starting in an existing task, find where that is...
2590 HistoryRecord next = null;
2591 boolean startIt = true;
2592 for (int i = NH-1; i >= 0; i--) {
2593 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2594 if (p.finishing) {
2595 continue;
2596 }
2597 if (p.task == r.task) {
2598 // Here it is! Now, if this is not yet visible to the
2599 // user, then just add it without starting; it will
2600 // get started when the user navigates back to it.
2601 addPos = i+1;
2602 if (!startIt) {
2603 mHistory.add(addPos, r);
2604 r.inHistory = true;
2605 r.task.numActivities++;
2606 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2607 r.info.screenOrientation, r.fullscreen);
2608 if (VALIDATE_TOKENS) {
2609 mWindowManager.validateAppTokens(mHistory);
2610 }
2611 return;
2612 }
2613 break;
2614 }
2615 if (p.fullscreen) {
2616 startIt = false;
2617 }
2618 next = p;
2619 }
2620 }
2621
2622 // Place a new activity at top of stack, so it is next to interact
2623 // with the user.
2624 if (addPos < 0) {
2625 addPos = mHistory.size();
2626 }
2627
2628 // If we are not placing the new activity frontmost, we do not want
2629 // to deliver the onUserLeaving callback to the actual frontmost
2630 // activity
2631 if (addPos < NH) {
2632 mUserLeaving = false;
2633 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2634 }
2635
2636 // Slot the activity into the history stack and proceed
2637 mHistory.add(addPos, r);
2638 r.inHistory = true;
2639 r.frontOfTask = newTask;
2640 r.task.numActivities++;
2641 if (NH > 0) {
2642 // We want to show the starting preview window if we are
2643 // switching to a new task, or the next activity's process is
2644 // not currently running.
2645 boolean showStartingIcon = newTask;
2646 ProcessRecord proc = r.app;
2647 if (proc == null) {
2648 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2649 }
2650 if (proc == null || proc.thread == null) {
2651 showStartingIcon = true;
2652 }
2653 if (DEBUG_TRANSITION) Log.v(TAG,
2654 "Prepare open transition: starting " + r);
2655 mWindowManager.prepareAppTransition(newTask
2656 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2657 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2658 mWindowManager.addAppToken(
2659 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2660 boolean doShow = true;
2661 if (newTask) {
2662 // Even though this activity is starting fresh, we still need
2663 // to reset it to make sure we apply affinities to move any
2664 // existing activities from other tasks in to it.
2665 // If the caller has requested that the target task be
2666 // reset, then do so.
2667 if ((r.intent.getFlags()
2668 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2669 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002670 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 }
2672 }
2673 if (SHOW_APP_STARTING_ICON && doShow) {
2674 // Figure out if we are transitioning from another activity that is
2675 // "has the same starting icon" as the next one. This allows the
2676 // window manager to keep the previous window it had previously
2677 // created, if it still had one.
2678 HistoryRecord prev = mResumedActivity;
2679 if (prev != null) {
2680 // We don't want to reuse the previous starting preview if:
2681 // (1) The current activity is in a different task.
2682 if (prev.task != r.task) prev = null;
2683 // (2) The current activity is already displayed.
2684 else if (prev.nowVisible) prev = null;
2685 }
2686 mWindowManager.setAppStartingWindow(
2687 r, r.packageName, r.theme, r.nonLocalizedLabel,
2688 r.labelRes, r.icon, prev, showStartingIcon);
2689 }
2690 } else {
2691 // If this is the first activity, don't do any fancy animations,
2692 // because there is nothing for it to animate on top of.
2693 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2694 r.info.screenOrientation, r.fullscreen);
2695 }
2696 if (VALIDATE_TOKENS) {
2697 mWindowManager.validateAppTokens(mHistory);
2698 }
2699
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002700 if (doResume) {
2701 resumeTopActivityLocked(null);
2702 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 }
2704
2705 /**
2706 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002707 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2708 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 * an instance of that activity in the stack and, if found, finish all
2710 * activities on top of it and return the instance.
2711 *
2712 * @param newR Description of the new activity being started.
2713 * @return Returns the old activity that should be continue to be used,
2714 * or null if none was found.
2715 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002716 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 HistoryRecord newR, boolean doClear) {
2718 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002719
2720 // First find the requested task.
2721 while (i > 0) {
2722 i--;
2723 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2724 if (r.task.taskId == taskId) {
2725 i++;
2726 break;
2727 }
2728 }
2729
2730 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731 while (i > 0) {
2732 i--;
2733 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2734 if (r.finishing) {
2735 continue;
2736 }
2737 if (r.task.taskId != taskId) {
2738 return null;
2739 }
2740 if (r.realActivity.equals(newR.realActivity)) {
2741 // Here it is! Now finish everything in front...
2742 HistoryRecord ret = r;
2743 if (doClear) {
2744 while (i < (mHistory.size()-1)) {
2745 i++;
2746 r = (HistoryRecord)mHistory.get(i);
2747 if (r.finishing) {
2748 continue;
2749 }
2750 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2751 null, "clear")) {
2752 i--;
2753 }
2754 }
2755 }
2756
2757 // Finally, if this is a normal launch mode (that is, not
2758 // expecting onNewIntent()), then we will finish the current
2759 // instance of the activity so a new fresh one can be started.
2760 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2761 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002762 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002763 if (index >= 0) {
2764 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2765 null, "clear");
2766 }
2767 return null;
2768 }
2769 }
2770
2771 return ret;
2772 }
2773 }
2774
2775 return null;
2776 }
2777
2778 /**
2779 * Find the activity in the history stack within the given task. Returns
2780 * the index within the history at which it's found, or < 0 if not found.
2781 */
2782 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2783 int i = mHistory.size();
2784 while (i > 0) {
2785 i--;
2786 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2787 if (candidate.task.taskId != task) {
2788 break;
2789 }
2790 if (candidate.realActivity.equals(r.realActivity)) {
2791 return i;
2792 }
2793 }
2794
2795 return -1;
2796 }
2797
2798 /**
2799 * Reorder the history stack so that the activity at the given index is
2800 * brought to the front.
2801 */
2802 private final HistoryRecord moveActivityToFrontLocked(int where) {
2803 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2804 int top = mHistory.size();
2805 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2806 mHistory.add(top, newTop);
2807 oldTop.frontOfTask = false;
2808 newTop.frontOfTask = true;
2809 return newTop;
2810 }
2811
2812 /**
2813 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2814 * method will be called at the proper time.
2815 */
2816 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2817 boolean sent = false;
2818 if (r.state == ActivityState.RESUMED
2819 && r.app != null && r.app.thread != null) {
2820 try {
2821 ArrayList<Intent> ar = new ArrayList<Intent>();
2822 ar.add(new Intent(intent));
2823 r.app.thread.scheduleNewIntent(ar, r);
2824 sent = true;
2825 } catch (Exception e) {
2826 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2827 }
2828 }
2829 if (!sent) {
2830 r.addNewIntentLocked(new Intent(intent));
2831 }
2832 }
2833
2834 private final void logStartActivity(int tag, HistoryRecord r,
2835 TaskRecord task) {
2836 EventLog.writeEvent(tag,
2837 System.identityHashCode(r), task.taskId,
2838 r.shortComponentName, r.intent.getAction(),
2839 r.intent.getType(), r.intent.getDataString(),
2840 r.intent.getFlags());
2841 }
2842
2843 private final int startActivityLocked(IApplicationThread caller,
2844 Intent intent, String resolvedType,
2845 Uri[] grantedUriPermissions,
2846 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
2847 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002848 int callingPid, int callingUid, boolean onlyIfNeeded,
2849 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850 Log.i(TAG, "Starting activity: " + intent);
2851
2852 HistoryRecord sourceRecord = null;
2853 HistoryRecord resultRecord = null;
2854 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002855 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07002856 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 TAG, "Sending result to " + resultTo + " (index " + index + ")");
2858 if (index >= 0) {
2859 sourceRecord = (HistoryRecord)mHistory.get(index);
2860 if (requestCode >= 0 && !sourceRecord.finishing) {
2861 resultRecord = sourceRecord;
2862 }
2863 }
2864 }
2865
2866 int launchFlags = intent.getFlags();
2867
2868 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
2869 && sourceRecord != null) {
2870 // Transfer the result target from the source activity to the new
2871 // one being started, including any failures.
2872 if (requestCode >= 0) {
2873 return START_FORWARD_AND_REQUEST_CONFLICT;
2874 }
2875 resultRecord = sourceRecord.resultTo;
2876 resultWho = sourceRecord.resultWho;
2877 requestCode = sourceRecord.requestCode;
2878 sourceRecord.resultTo = null;
2879 if (resultRecord != null) {
2880 resultRecord.removeResultsLocked(
2881 sourceRecord, resultWho, requestCode);
2882 }
2883 }
2884
2885 int err = START_SUCCESS;
2886
2887 if (intent.getComponent() == null) {
2888 // We couldn't find a class that can handle the given Intent.
2889 // That's the end of that!
2890 err = START_INTENT_NOT_RESOLVED;
2891 }
2892
2893 if (err == START_SUCCESS && aInfo == null) {
2894 // We couldn't find the specific class specified in the Intent.
2895 // Also the end of the line.
2896 err = START_CLASS_NOT_FOUND;
2897 }
2898
2899 ProcessRecord callerApp = null;
2900 if (err == START_SUCCESS && caller != null) {
2901 callerApp = getRecordForAppLocked(caller);
2902 if (callerApp != null) {
2903 callingPid = callerApp.pid;
2904 callingUid = callerApp.info.uid;
2905 } else {
2906 Log.w(TAG, "Unable to find app for caller " + caller
2907 + " (pid=" + callingPid + ") when starting: "
2908 + intent.toString());
2909 err = START_PERMISSION_DENIED;
2910 }
2911 }
2912
2913 if (err != START_SUCCESS) {
2914 if (resultRecord != null) {
2915 sendActivityResultLocked(-1,
2916 resultRecord, resultWho, requestCode,
2917 Activity.RESULT_CANCELED, null);
2918 }
2919 return err;
2920 }
2921
2922 final int perm = checkComponentPermission(aInfo.permission, callingPid,
2923 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
2924 if (perm != PackageManager.PERMISSION_GRANTED) {
2925 if (resultRecord != null) {
2926 sendActivityResultLocked(-1,
2927 resultRecord, resultWho, requestCode,
2928 Activity.RESULT_CANCELED, null);
2929 }
2930 String msg = "Permission Denial: starting " + intent.toString()
2931 + " from " + callerApp + " (pid=" + callingPid
2932 + ", uid=" + callingUid + ")"
2933 + " requires " + aInfo.permission;
2934 Log.w(TAG, msg);
2935 throw new SecurityException(msg);
2936 }
2937
2938 if (mWatcher != null) {
2939 boolean abort = false;
2940 try {
2941 // The Intent we give to the watcher has the extra data
2942 // stripped off, since it can contain private information.
2943 Intent watchIntent = intent.cloneFilter();
2944 abort = !mWatcher.activityStarting(watchIntent,
2945 aInfo.applicationInfo.packageName);
2946 } catch (RemoteException e) {
2947 mWatcher = null;
2948 }
2949
2950 if (abort) {
2951 if (resultRecord != null) {
2952 sendActivityResultLocked(-1,
2953 resultRecord, resultWho, requestCode,
2954 Activity.RESULT_CANCELED, null);
2955 }
2956 // We pretend to the caller that it was really started, but
2957 // they will just get a cancel result.
2958 return START_SUCCESS;
2959 }
2960 }
2961
2962 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
2963 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08002964 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002965
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002966 if (mResumedActivity == null
2967 || mResumedActivity.info.applicationInfo.uid != callingUid) {
2968 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
2969 PendingActivityLaunch pal = new PendingActivityLaunch();
2970 pal.r = r;
2971 pal.sourceRecord = sourceRecord;
2972 pal.grantedUriPermissions = grantedUriPermissions;
2973 pal.grantedMode = grantedMode;
2974 pal.onlyIfNeeded = onlyIfNeeded;
2975 mPendingActivityLaunches.add(pal);
2976 return START_SWITCHES_CANCELED;
2977 }
2978 }
2979
2980 if (mDidAppSwitch) {
2981 // This is the second allowed switch since we stopped switches,
2982 // so now just generally allow switches. Use case: user presses
2983 // home (switches disabled, switch to home, mDidAppSwitch now true);
2984 // user taps a home icon (coming from home so allowed, we hit here
2985 // and now allow anyone to switch again).
2986 mAppSwitchesAllowedTime = 0;
2987 } else {
2988 mDidAppSwitch = true;
2989 }
2990
2991 doPendingActivityLaunchesLocked(false);
2992
2993 return startActivityUncheckedLocked(r, sourceRecord,
2994 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
2995 }
2996
2997 private final void doPendingActivityLaunchesLocked(boolean doResume) {
2998 final int N = mPendingActivityLaunches.size();
2999 if (N <= 0) {
3000 return;
3001 }
3002 for (int i=0; i<N; i++) {
3003 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3004 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3005 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3006 doResume && i == (N-1));
3007 }
3008 mPendingActivityLaunches.clear();
3009 }
3010
3011 private final int startActivityUncheckedLocked(HistoryRecord r,
3012 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3013 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3014 final Intent intent = r.intent;
3015 final int callingUid = r.launchedFromUid;
3016
3017 int launchFlags = intent.getFlags();
3018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003019 // We'll invoke onUserLeaving before onPause only if the launching
3020 // activity did not explicitly state that this is an automated launch.
3021 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3022 if (DEBUG_USER_LEAVING) Log.v(TAG,
3023 "startActivity() => mUserLeaving=" + mUserLeaving);
3024
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003025 // If the caller has asked not to resume at this point, we make note
3026 // of this in the record so that we can skip it when trying to find
3027 // the top running activity.
3028 if (!doResume) {
3029 r.delayedResume = true;
3030 }
3031
3032 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3033 != 0 ? r : null;
3034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003035 // If the onlyIfNeeded flag is set, then we can do this if the activity
3036 // being launched is the same as the one making the call... or, as
3037 // a special case, if we do not know the caller then we count the
3038 // current top activity as the caller.
3039 if (onlyIfNeeded) {
3040 HistoryRecord checkedCaller = sourceRecord;
3041 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003042 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003043 }
3044 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3045 // Caller is not the same as launcher, so always needed.
3046 onlyIfNeeded = false;
3047 }
3048 }
3049
3050 if (grantedUriPermissions != null && callingUid > 0) {
3051 for (int i=0; i<grantedUriPermissions.length; i++) {
3052 grantUriPermissionLocked(callingUid, r.packageName,
3053 grantedUriPermissions[i], grantedMode, r);
3054 }
3055 }
3056
3057 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3058 intent, r);
3059
3060 if (sourceRecord == null) {
3061 // This activity is not being started from another... in this
3062 // case we -always- start a new task.
3063 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3064 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3065 + intent);
3066 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3067 }
3068 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3069 // The original activity who is starting us is running as a single
3070 // instance... this new activity it is starting must go on its
3071 // own task.
3072 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3073 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3074 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3075 // The activity being started is a single instance... it always
3076 // gets launched into its own task.
3077 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3078 }
3079
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003080 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003081 // For whatever reason this activity is being launched into a new
3082 // task... yet the caller has requested a result back. Well, that
3083 // is pretty messed up, so instead immediately send back a cancel
3084 // and let the new task continue launched as normal without a
3085 // dependency on its originator.
3086 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3087 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003088 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003089 Activity.RESULT_CANCELED, null);
3090 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 }
3092
3093 boolean addingToTask = false;
3094 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3095 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3096 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3097 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3098 // If bring to front is requested, and no result is requested, and
3099 // we can find a task that was started with this same
3100 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003101 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 // See if there is a task to bring to the front. If this is
3103 // a SINGLE_INSTANCE activity, there can be one and only one
3104 // instance of it in the history, and it is always in its own
3105 // unique task, so we do a special search.
3106 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3107 ? findTaskLocked(intent, r.info)
3108 : findActivityLocked(intent, r.info);
3109 if (taskTop != null) {
3110 if (taskTop.task.intent == null) {
3111 // This task was started because of movement of
3112 // the activity based on affinity... now that we
3113 // are actually launching it, we can assign the
3114 // base intent.
3115 taskTop.task.setIntent(intent, r.info);
3116 }
3117 // If the target task is not in the front, then we need
3118 // to bring it to the front... except... well, with
3119 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3120 // to have the same behavior as if a new instance was
3121 // being started, which means not bringing it to the front
3122 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003123 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124 if (curTop.task != taskTop.task) {
3125 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3126 boolean callerAtFront = sourceRecord == null
3127 || curTop.task == sourceRecord.task;
3128 if (callerAtFront) {
3129 // We really do want to push this one into the
3130 // user's face, right now.
3131 moveTaskToFrontLocked(taskTop.task);
3132 }
3133 }
3134 // If the caller has requested that the target task be
3135 // reset, then do so.
3136 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3137 taskTop = resetTaskIfNeededLocked(taskTop, r);
3138 }
3139 if (onlyIfNeeded) {
3140 // We don't need to start a new activity, and
3141 // the client said not to do anything if that
3142 // is the case, so this is it! And for paranoia, make
3143 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003144 if (doResume) {
3145 resumeTopActivityLocked(null);
3146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 return START_RETURN_INTENT_TO_CALLER;
3148 }
3149 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3150 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3151 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3152 // In this situation we want to remove all activities
3153 // from the task up to the one being started. In most
3154 // cases this means we are resetting the task to its
3155 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003156 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 taskTop.task.taskId, r, true);
3158 if (top != null) {
3159 if (top.frontOfTask) {
3160 // Activity aliases may mean we use different
3161 // intents for the top activity, so make sure
3162 // the task now has the identity of the new
3163 // intent.
3164 top.task.setIntent(r.intent, r.info);
3165 }
3166 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3167 deliverNewIntentLocked(top, r.intent);
3168 } else {
3169 // A special case: we need to
3170 // start the activity because it is not currently
3171 // running, and the caller has asked to clear the
3172 // current task to have this activity at the top.
3173 addingToTask = true;
3174 // Now pretend like this activity is being started
3175 // by the top of its task, so it is put in the
3176 // right place.
3177 sourceRecord = taskTop;
3178 }
3179 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3180 // In this case the top activity on the task is the
3181 // same as the one being launched, so we take that
3182 // as a request to bring the task to the foreground.
3183 // If the top activity in the task is the root
3184 // activity, deliver this new intent to it if it
3185 // desires.
3186 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3187 && taskTop.realActivity.equals(r.realActivity)) {
3188 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3189 if (taskTop.frontOfTask) {
3190 taskTop.task.setIntent(r.intent, r.info);
3191 }
3192 deliverNewIntentLocked(taskTop, r.intent);
3193 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3194 // In this case we are launching the root activity
3195 // of the task, but with a different intent. We
3196 // should start a new instance on top.
3197 addingToTask = true;
3198 sourceRecord = taskTop;
3199 }
3200 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3201 // In this case an activity is being launched in to an
3202 // existing task, without resetting that task. This
3203 // is typically the situation of launching an activity
3204 // from a notification or shortcut. We want to place
3205 // the new activity on top of the current task.
3206 addingToTask = true;
3207 sourceRecord = taskTop;
3208 } else if (!taskTop.task.rootWasReset) {
3209 // In this case we are launching in to an existing task
3210 // that has not yet been started from its front door.
3211 // The current task has been brought to the front.
3212 // Ideally, we'd probably like to place this new task
3213 // at the bottom of its stack, but that's a little hard
3214 // to do with the current organization of the code so
3215 // for now we'll just drop it.
3216 taskTop.task.setIntent(r.intent, r.info);
3217 }
3218 if (!addingToTask) {
3219 // We didn't do anything... but it was needed (a.k.a., client
3220 // don't use that intent!) And for paranoia, make
3221 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003222 if (doResume) {
3223 resumeTopActivityLocked(null);
3224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003225 return START_TASK_TO_FRONT;
3226 }
3227 }
3228 }
3229 }
3230
3231 //String uri = r.intent.toURI();
3232 //Intent intent2 = new Intent(uri);
3233 //Log.i(TAG, "Given intent: " + r.intent);
3234 //Log.i(TAG, "URI is: " + uri);
3235 //Log.i(TAG, "To intent: " + intent2);
3236
3237 if (r.packageName != null) {
3238 // If the activity being launched is the same as the one currently
3239 // at the top, then we need to check if it should only be launched
3240 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003241 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3242 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 if (top.realActivity.equals(r.realActivity)) {
3244 if (top.app != null && top.app.thread != null) {
3245 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3246 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3247 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3248 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3249 // For paranoia, make sure we have correctly
3250 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003251 if (doResume) {
3252 resumeTopActivityLocked(null);
3253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 if (onlyIfNeeded) {
3255 // We don't need to start a new activity, and
3256 // the client said not to do anything if that
3257 // is the case, so this is it!
3258 return START_RETURN_INTENT_TO_CALLER;
3259 }
3260 deliverNewIntentLocked(top, r.intent);
3261 return START_DELIVERED_TO_TOP;
3262 }
3263 }
3264 }
3265 }
3266
3267 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003268 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003270 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003271 Activity.RESULT_CANCELED, null);
3272 }
3273 return START_CLASS_NOT_FOUND;
3274 }
3275
3276 boolean newTask = false;
3277
3278 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003279 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3281 // todo: should do better management of integers.
3282 mCurTask++;
3283 if (mCurTask <= 0) {
3284 mCurTask = 1;
3285 }
3286 r.task = new TaskRecord(mCurTask, r.info, intent,
3287 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3288 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3289 + " in new task " + r.task);
3290 newTask = true;
3291 addRecentTask(r.task);
3292
3293 } else if (sourceRecord != null) {
3294 if (!addingToTask &&
3295 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3296 // In this case, we are adding the activity to an existing
3297 // task, but the caller has asked to clear that task if the
3298 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003299 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 sourceRecord.task.taskId, r, true);
3301 if (top != null) {
3302 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3303 deliverNewIntentLocked(top, r.intent);
3304 // For paranoia, make sure we have correctly
3305 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 if (doResume) {
3307 resumeTopActivityLocked(null);
3308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 return START_DELIVERED_TO_TOP;
3310 }
3311 } else if (!addingToTask &&
3312 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3313 // In this case, we are launching an activity in our own task
3314 // that may already be running somewhere in the history, and
3315 // we want to shuffle it to the front of the stack if so.
3316 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3317 if (where >= 0) {
3318 HistoryRecord top = moveActivityToFrontLocked(where);
3319 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3320 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003321 if (doResume) {
3322 resumeTopActivityLocked(null);
3323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 return START_DELIVERED_TO_TOP;
3325 }
3326 }
3327 // An existing activity is starting this new activity, so we want
3328 // to keep the new one in the same task as the one that is starting
3329 // it.
3330 r.task = sourceRecord.task;
3331 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3332 + " in existing task " + r.task);
3333
3334 } else {
3335 // This not being started from an existing activity, and not part
3336 // of a new task... just put it in the top task, though these days
3337 // this case should never happen.
3338 final int N = mHistory.size();
3339 HistoryRecord prev =
3340 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3341 r.task = prev != null
3342 ? prev.task
3343 : new TaskRecord(mCurTask, r.info, intent,
3344 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3345 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3346 + " in new guessed " + r.task);
3347 }
3348 if (newTask) {
3349 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3350 }
3351 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003352 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003353 return START_SUCCESS;
3354 }
3355
3356 public final int startActivity(IApplicationThread caller,
3357 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3358 int grantedMode, IBinder resultTo,
3359 String resultWho, int requestCode, boolean onlyIfNeeded,
3360 boolean debug) {
3361 // Refuse possible leaked file descriptors
3362 if (intent != null && intent.hasFileDescriptors()) {
3363 throw new IllegalArgumentException("File descriptors passed in Intent");
3364 }
3365
The Android Open Source Project4df24232009-03-05 14:34:35 -08003366 final boolean componentSpecified = intent.getComponent() != null;
3367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 // Don't modify the client's object!
3369 intent = new Intent(intent);
3370
3371 // Collect information about the target of the Intent.
3372 // Must do this before locking, because resolving the intent
3373 // may require launching a process to run its content provider.
3374 ActivityInfo aInfo;
3375 try {
3376 ResolveInfo rInfo =
3377 ActivityThread.getPackageManager().resolveIntent(
3378 intent, resolvedType,
3379 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003380 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381 aInfo = rInfo != null ? rInfo.activityInfo : null;
3382 } catch (RemoteException e) {
3383 aInfo = null;
3384 }
3385
3386 if (aInfo != null) {
3387 // Store the found target back into the intent, because now that
3388 // we have it we never want to do this again. For example, if the
3389 // user navigates back to this point in the history, we should
3390 // always restart the exact same activity.
3391 intent.setComponent(new ComponentName(
3392 aInfo.applicationInfo.packageName, aInfo.name));
3393
3394 // Don't debug things in the system process
3395 if (debug) {
3396 if (!aInfo.processName.equals("system")) {
3397 setDebugApp(aInfo.processName, true, false);
3398 }
3399 }
3400 }
3401
3402 synchronized(this) {
3403 final long origId = Binder.clearCallingIdentity();
3404 int res = startActivityLocked(caller, intent, resolvedType,
3405 grantedUriPermissions, grantedMode, aInfo,
3406 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003407 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 Binder.restoreCallingIdentity(origId);
3409 return res;
3410 }
3411 }
3412
3413 public boolean startNextMatchingActivity(IBinder callingActivity,
3414 Intent intent) {
3415 // Refuse possible leaked file descriptors
3416 if (intent != null && intent.hasFileDescriptors() == true) {
3417 throw new IllegalArgumentException("File descriptors passed in Intent");
3418 }
3419
3420 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003421 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003422 if (index < 0) {
3423 return false;
3424 }
3425 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3426 if (r.app == null || r.app.thread == null) {
3427 // The caller is not running... d'oh!
3428 return false;
3429 }
3430 intent = new Intent(intent);
3431 // The caller is not allowed to change the data.
3432 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3433 // And we are resetting to find the next component...
3434 intent.setComponent(null);
3435
3436 ActivityInfo aInfo = null;
3437 try {
3438 List<ResolveInfo> resolves =
3439 ActivityThread.getPackageManager().queryIntentActivities(
3440 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003441 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003442
3443 // Look for the original activity in the list...
3444 final int N = resolves != null ? resolves.size() : 0;
3445 for (int i=0; i<N; i++) {
3446 ResolveInfo rInfo = resolves.get(i);
3447 if (rInfo.activityInfo.packageName.equals(r.packageName)
3448 && rInfo.activityInfo.name.equals(r.info.name)) {
3449 // We found the current one... the next matching is
3450 // after it.
3451 i++;
3452 if (i<N) {
3453 aInfo = resolves.get(i).activityInfo;
3454 }
3455 break;
3456 }
3457 }
3458 } catch (RemoteException e) {
3459 }
3460
3461 if (aInfo == null) {
3462 // Nobody who is next!
3463 return false;
3464 }
3465
3466 intent.setComponent(new ComponentName(
3467 aInfo.applicationInfo.packageName, aInfo.name));
3468 intent.setFlags(intent.getFlags()&~(
3469 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3470 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3471 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3472 Intent.FLAG_ACTIVITY_NEW_TASK));
3473
3474 // Okay now we need to start the new activity, replacing the
3475 // currently running activity. This is a little tricky because
3476 // we want to start the new one as if the current one is finished,
3477 // but not finish the current one first so that there is no flicker.
3478 // And thus...
3479 final boolean wasFinishing = r.finishing;
3480 r.finishing = true;
3481
3482 // Propagate reply information over to the new activity.
3483 final HistoryRecord resultTo = r.resultTo;
3484 final String resultWho = r.resultWho;
3485 final int requestCode = r.requestCode;
3486 r.resultTo = null;
3487 if (resultTo != null) {
3488 resultTo.removeResultsLocked(r, resultWho, requestCode);
3489 }
3490
3491 final long origId = Binder.clearCallingIdentity();
3492 // XXX we are not dealing with propagating grantedUriPermissions...
3493 // those are not yet exposed to user code, so there is no need.
3494 int res = startActivityLocked(r.app.thread, intent,
3495 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003496 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 Binder.restoreCallingIdentity(origId);
3498
3499 r.finishing = wasFinishing;
3500 if (res != START_SUCCESS) {
3501 return false;
3502 }
3503 return true;
3504 }
3505 }
3506
3507 final int startActivityInPackage(int uid,
3508 Intent intent, String resolvedType, IBinder resultTo,
3509 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003510 final boolean componentSpecified = intent.getComponent() != null;
3511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003512 // Don't modify the client's object!
3513 intent = new Intent(intent);
3514
3515 // Collect information about the target of the Intent.
3516 // Must do this before locking, because resolving the intent
3517 // may require launching a process to run its content provider.
3518 ActivityInfo aInfo;
3519 try {
3520 ResolveInfo rInfo =
3521 ActivityThread.getPackageManager().resolveIntent(
3522 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003523 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003524 aInfo = rInfo != null ? rInfo.activityInfo : null;
3525 } catch (RemoteException e) {
3526 aInfo = null;
3527 }
3528
3529 if (aInfo != null) {
3530 // Store the found target back into the intent, because now that
3531 // we have it we never want to do this again. For example, if the
3532 // user navigates back to this point in the history, we should
3533 // always restart the exact same activity.
3534 intent.setComponent(new ComponentName(
3535 aInfo.applicationInfo.packageName, aInfo.name));
3536 }
3537
3538 synchronized(this) {
3539 return startActivityLocked(null, intent, resolvedType,
3540 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003541 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 }
3543 }
3544
3545 private final void addRecentTask(TaskRecord task) {
3546 // Remove any existing entries that are the same kind of task.
3547 int N = mRecentTasks.size();
3548 for (int i=0; i<N; i++) {
3549 TaskRecord tr = mRecentTasks.get(i);
3550 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3551 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3552 mRecentTasks.remove(i);
3553 i--;
3554 N--;
3555 if (task.intent == null) {
3556 // If the new recent task we are adding is not fully
3557 // specified, then replace it with the existing recent task.
3558 task = tr;
3559 }
3560 }
3561 }
3562 if (N >= MAX_RECENT_TASKS) {
3563 mRecentTasks.remove(N-1);
3564 }
3565 mRecentTasks.add(0, task);
3566 }
3567
3568 public void setRequestedOrientation(IBinder token,
3569 int requestedOrientation) {
3570 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003571 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 if (index < 0) {
3573 return;
3574 }
3575 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3576 final long origId = Binder.clearCallingIdentity();
3577 mWindowManager.setAppOrientation(r, requestedOrientation);
3578 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003579 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 r.mayFreezeScreenLocked(r.app) ? r : null);
3581 if (config != null) {
3582 r.frozenBeforeDestroy = true;
3583 if (!updateConfigurationLocked(config, r)) {
3584 resumeTopActivityLocked(null);
3585 }
3586 }
3587 Binder.restoreCallingIdentity(origId);
3588 }
3589 }
3590
3591 public int getRequestedOrientation(IBinder token) {
3592 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003593 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003594 if (index < 0) {
3595 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3596 }
3597 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3598 return mWindowManager.getAppOrientation(r);
3599 }
3600 }
3601
3602 private final void stopActivityLocked(HistoryRecord r) {
3603 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3604 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3605 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3606 if (!r.finishing) {
3607 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3608 "no-history");
3609 }
3610 } else if (r.app != null && r.app.thread != null) {
3611 if (mFocusedActivity == r) {
3612 setFocusedActivityLocked(topRunningActivityLocked(null));
3613 }
3614 r.resumeKeyDispatchingLocked();
3615 try {
3616 r.stopped = false;
3617 r.state = ActivityState.STOPPING;
3618 if (DEBUG_VISBILITY) Log.v(
3619 TAG, "Stopping visible=" + r.visible + " for " + r);
3620 if (!r.visible) {
3621 mWindowManager.setAppVisibility(r, false);
3622 }
3623 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3624 } catch (Exception e) {
3625 // Maybe just ignore exceptions here... if the process
3626 // has crashed, our death notification will clean things
3627 // up.
3628 Log.w(TAG, "Exception thrown during pause", e);
3629 // Just in case, assume it to be stopped.
3630 r.stopped = true;
3631 r.state = ActivityState.STOPPED;
3632 if (r.configDestroy) {
3633 destroyActivityLocked(r, true);
3634 }
3635 }
3636 }
3637 }
3638
3639 /**
3640 * @return Returns true if the activity is being finished, false if for
3641 * some reason it is being left as-is.
3642 */
3643 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3644 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003645 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 TAG, "Finishing activity: token=" + token
3647 + ", result=" + resultCode + ", data=" + resultData);
3648
Dianne Hackborn75b03852009-06-12 15:43:26 -07003649 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 if (index < 0) {
3651 return false;
3652 }
3653 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3654
3655 // Is this the last activity left?
3656 boolean lastActivity = true;
3657 for (int i=mHistory.size()-1; i>=0; i--) {
3658 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3659 if (!p.finishing && p != r) {
3660 lastActivity = false;
3661 break;
3662 }
3663 }
3664
3665 // If this is the last activity, but it is the home activity, then
3666 // just don't finish it.
3667 if (lastActivity) {
3668 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3669 return false;
3670 }
3671 }
3672
3673 finishActivityLocked(r, index, resultCode, resultData, reason);
3674 return true;
3675 }
3676
3677 /**
3678 * @return Returns true if this activity has been removed from the history
3679 * list, or false if it is still in the list and will be removed later.
3680 */
3681 private final boolean finishActivityLocked(HistoryRecord r, int index,
3682 int resultCode, Intent resultData, String reason) {
3683 if (r.finishing) {
3684 Log.w(TAG, "Duplicate finish request for " + r);
3685 return false;
3686 }
3687
3688 r.finishing = true;
3689 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3690 System.identityHashCode(r),
3691 r.task.taskId, r.shortComponentName, reason);
3692 r.task.numActivities--;
3693 if (r.frontOfTask && index < (mHistory.size()-1)) {
3694 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3695 if (next.task == r.task) {
3696 next.frontOfTask = true;
3697 }
3698 }
3699
3700 r.pauseKeyDispatchingLocked();
3701 if (mFocusedActivity == r) {
3702 setFocusedActivityLocked(topRunningActivityLocked(null));
3703 }
3704
3705 // send the result
3706 HistoryRecord resultTo = r.resultTo;
3707 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003708 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3709 + " who=" + r.resultWho + " req=" + r.requestCode
3710 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 if (r.info.applicationInfo.uid > 0) {
3712 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3713 r.packageName, resultData, r);
3714 }
3715 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3716 resultData);
3717 r.resultTo = null;
3718 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003719 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003720
3721 // Make sure this HistoryRecord is not holding on to other resources,
3722 // because clients have remote IPC references to this object so we
3723 // can't assume that will go away and want to avoid circular IPC refs.
3724 r.results = null;
3725 r.pendingResults = null;
3726 r.newIntents = null;
3727 r.icicle = null;
3728
3729 if (mPendingThumbnails.size() > 0) {
3730 // There are clients waiting to receive thumbnails so, in case
3731 // this is an activity that someone is waiting for, add it
3732 // to the pending list so we can correctly update the clients.
3733 mCancelledThumbnails.add(r);
3734 }
3735
3736 if (mResumedActivity == r) {
3737 boolean endTask = index <= 0
3738 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3739 if (DEBUG_TRANSITION) Log.v(TAG,
3740 "Prepare close transition: finishing " + r);
3741 mWindowManager.prepareAppTransition(endTask
3742 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3743 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3744
3745 // Tell window manager to prepare for this one to be removed.
3746 mWindowManager.setAppVisibility(r, false);
3747
3748 if (mPausingActivity == null) {
3749 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3750 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3751 startPausingLocked(false, false);
3752 }
3753
3754 } else if (r.state != ActivityState.PAUSING) {
3755 // If the activity is PAUSING, we will complete the finish once
3756 // it is done pausing; else we can just directly finish it here.
3757 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3758 return finishCurrentActivityLocked(r, index,
3759 FINISH_AFTER_PAUSE) == null;
3760 } else {
3761 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3762 }
3763
3764 return false;
3765 }
3766
3767 private static final int FINISH_IMMEDIATELY = 0;
3768 private static final int FINISH_AFTER_PAUSE = 1;
3769 private static final int FINISH_AFTER_VISIBLE = 2;
3770
3771 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3772 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003773 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003774 if (index < 0) {
3775 return null;
3776 }
3777
3778 return finishCurrentActivityLocked(r, index, mode);
3779 }
3780
3781 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3782 int index, int mode) {
3783 // First things first: if this activity is currently visible,
3784 // and the resumed activity is not yet visible, then hold off on
3785 // finishing until the resumed one becomes visible.
3786 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3787 if (!mStoppingActivities.contains(r)) {
3788 mStoppingActivities.add(r);
3789 if (mStoppingActivities.size() > 3) {
3790 // If we already have a few activities waiting to stop,
3791 // then give up on things going idle and start clearing
3792 // them out.
3793 Message msg = Message.obtain();
3794 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3795 mHandler.sendMessage(msg);
3796 }
3797 }
3798 r.state = ActivityState.STOPPING;
3799 updateOomAdjLocked();
3800 return r;
3801 }
3802
3803 // make sure the record is cleaned out of other places.
3804 mStoppingActivities.remove(r);
3805 mWaitingVisibleActivities.remove(r);
3806 if (mResumedActivity == r) {
3807 mResumedActivity = null;
3808 }
3809 final ActivityState prevState = r.state;
3810 r.state = ActivityState.FINISHING;
3811
3812 if (mode == FINISH_IMMEDIATELY
3813 || prevState == ActivityState.STOPPED
3814 || prevState == ActivityState.INITIALIZING) {
3815 // If this activity is already stopped, we can just finish
3816 // it right now.
3817 return destroyActivityLocked(r, true) ? null : r;
3818 } else {
3819 // Need to go through the full pause cycle to get this
3820 // activity into the stopped state and then finish it.
3821 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3822 mFinishingActivities.add(r);
3823 resumeTopActivityLocked(null);
3824 }
3825 return r;
3826 }
3827
3828 /**
3829 * This is the internal entry point for handling Activity.finish().
3830 *
3831 * @param token The Binder token referencing the Activity we want to finish.
3832 * @param resultCode Result code, if any, from this Activity.
3833 * @param resultData Result data (Intent), if any, from this Activity.
3834 *
3835 * @result Returns true if the activity successfully finished, or false if it is still running.
3836 */
3837 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3838 // Refuse possible leaked file descriptors
3839 if (resultData != null && resultData.hasFileDescriptors() == true) {
3840 throw new IllegalArgumentException("File descriptors passed in Intent");
3841 }
3842
3843 synchronized(this) {
3844 if (mWatcher != null) {
3845 // Find the first activity that is not finishing.
3846 HistoryRecord next = topRunningActivityLocked(token, 0);
3847 if (next != null) {
3848 // ask watcher if this is allowed
3849 boolean resumeOK = true;
3850 try {
3851 resumeOK = mWatcher.activityResuming(next.packageName);
3852 } catch (RemoteException e) {
3853 mWatcher = null;
3854 }
3855
3856 if (!resumeOK) {
3857 return false;
3858 }
3859 }
3860 }
3861 final long origId = Binder.clearCallingIdentity();
3862 boolean res = requestFinishActivityLocked(token, resultCode,
3863 resultData, "app-request");
3864 Binder.restoreCallingIdentity(origId);
3865 return res;
3866 }
3867 }
3868
3869 void sendActivityResultLocked(int callingUid, HistoryRecord r,
3870 String resultWho, int requestCode, int resultCode, Intent data) {
3871
3872 if (callingUid > 0) {
3873 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3874 data, r);
3875 }
3876
The Android Open Source Project10592532009-03-18 17:39:46 -07003877 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
3878 + " : who=" + resultWho + " req=" + requestCode
3879 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3881 try {
3882 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3883 list.add(new ResultInfo(resultWho, requestCode,
3884 resultCode, data));
3885 r.app.thread.scheduleSendResult(r, list);
3886 return;
3887 } catch (Exception e) {
3888 Log.w(TAG, "Exception thrown sending result to " + r, e);
3889 }
3890 }
3891
3892 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3893 }
3894
3895 public final void finishSubActivity(IBinder token, String resultWho,
3896 int requestCode) {
3897 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003898 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 if (index < 0) {
3900 return;
3901 }
3902 HistoryRecord self = (HistoryRecord)mHistory.get(index);
3903
3904 final long origId = Binder.clearCallingIdentity();
3905
3906 int i;
3907 for (i=mHistory.size()-1; i>=0; i--) {
3908 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3909 if (r.resultTo == self && r.requestCode == requestCode) {
3910 if ((r.resultWho == null && resultWho == null) ||
3911 (r.resultWho != null && r.resultWho.equals(resultWho))) {
3912 finishActivityLocked(r, i,
3913 Activity.RESULT_CANCELED, null, "request-sub");
3914 }
3915 }
3916 }
3917
3918 Binder.restoreCallingIdentity(origId);
3919 }
3920 }
3921
3922 /**
3923 * Perform clean-up of service connections in an activity record.
3924 */
3925 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
3926 // Throw away any services that have been bound by this activity.
3927 if (r.connections != null) {
3928 Iterator<ConnectionRecord> it = r.connections.iterator();
3929 while (it.hasNext()) {
3930 ConnectionRecord c = it.next();
3931 removeConnectionLocked(c, null, r);
3932 }
3933 r.connections = null;
3934 }
3935 }
3936
3937 /**
3938 * Perform the common clean-up of an activity record. This is called both
3939 * as part of destroyActivityLocked() (when destroying the client-side
3940 * representation) and cleaning things up as a result of its hosting
3941 * processing going away, in which case there is no remaining client-side
3942 * state to destroy so only the cleanup here is needed.
3943 */
3944 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
3945 if (mResumedActivity == r) {
3946 mResumedActivity = null;
3947 }
3948 if (mFocusedActivity == r) {
3949 mFocusedActivity = null;
3950 }
3951
3952 r.configDestroy = false;
3953 r.frozenBeforeDestroy = false;
3954
3955 // Make sure this record is no longer in the pending finishes list.
3956 // This could happen, for example, if we are trimming activities
3957 // down to the max limit while they are still waiting to finish.
3958 mFinishingActivities.remove(r);
3959 mWaitingVisibleActivities.remove(r);
3960
3961 // Remove any pending results.
3962 if (r.finishing && r.pendingResults != null) {
3963 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
3964 PendingIntentRecord rec = apr.get();
3965 if (rec != null) {
3966 cancelIntentSenderLocked(rec, false);
3967 }
3968 }
3969 r.pendingResults = null;
3970 }
3971
3972 if (cleanServices) {
3973 cleanUpActivityServicesLocked(r);
3974 }
3975
3976 if (mPendingThumbnails.size() > 0) {
3977 // There are clients waiting to receive thumbnails so, in case
3978 // this is an activity that someone is waiting for, add it
3979 // to the pending list so we can correctly update the clients.
3980 mCancelledThumbnails.add(r);
3981 }
3982
3983 // Get rid of any pending idle timeouts.
3984 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
3985 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
3986 }
3987
3988 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
3989 if (r.state != ActivityState.DESTROYED) {
3990 mHistory.remove(r);
3991 r.inHistory = false;
3992 r.state = ActivityState.DESTROYED;
3993 mWindowManager.removeAppToken(r);
3994 if (VALIDATE_TOKENS) {
3995 mWindowManager.validateAppTokens(mHistory);
3996 }
3997 cleanUpActivityServicesLocked(r);
3998 removeActivityUriPermissionsLocked(r);
3999 }
4000 }
4001
4002 /**
4003 * Destroy the current CLIENT SIDE instance of an activity. This may be
4004 * called both when actually finishing an activity, or when performing
4005 * a configuration switch where we destroy the current client-side object
4006 * but then create a new client-side object for this same HistoryRecord.
4007 */
4008 private final boolean destroyActivityLocked(HistoryRecord r,
4009 boolean removeFromApp) {
4010 if (DEBUG_SWITCH) Log.v(
4011 TAG, "Removing activity: token=" + r
4012 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4013 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4014 System.identityHashCode(r),
4015 r.task.taskId, r.shortComponentName);
4016
4017 boolean removedFromHistory = false;
4018
4019 cleanUpActivityLocked(r, false);
4020
4021 if (r.app != null) {
4022 if (removeFromApp) {
4023 int idx = r.app.activities.indexOf(r);
4024 if (idx >= 0) {
4025 r.app.activities.remove(idx);
4026 }
4027 if (r.persistent) {
4028 decPersistentCountLocked(r.app);
4029 }
4030 }
4031
4032 boolean skipDestroy = false;
4033
4034 try {
4035 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4036 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4037 r.configChangeFlags);
4038 } catch (Exception e) {
4039 // We can just ignore exceptions here... if the process
4040 // has crashed, our death notification will clean things
4041 // up.
4042 //Log.w(TAG, "Exception thrown during finish", e);
4043 if (r.finishing) {
4044 removeActivityFromHistoryLocked(r);
4045 removedFromHistory = true;
4046 skipDestroy = true;
4047 }
4048 }
4049
4050 r.app = null;
4051 r.nowVisible = false;
4052
4053 if (r.finishing && !skipDestroy) {
4054 r.state = ActivityState.DESTROYING;
4055 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4056 msg.obj = r;
4057 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4058 } else {
4059 r.state = ActivityState.DESTROYED;
4060 }
4061 } else {
4062 // remove this record from the history.
4063 if (r.finishing) {
4064 removeActivityFromHistoryLocked(r);
4065 removedFromHistory = true;
4066 } else {
4067 r.state = ActivityState.DESTROYED;
4068 }
4069 }
4070
4071 r.configChangeFlags = 0;
4072
4073 if (!mLRUActivities.remove(r)) {
4074 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4075 }
4076
4077 return removedFromHistory;
4078 }
4079
4080 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4081 ProcessRecord app)
4082 {
4083 int i = list.size();
4084 if (localLOGV) Log.v(
4085 TAG, "Removing app " + app + " from list " + list
4086 + " with " + i + " entries");
4087 while (i > 0) {
4088 i--;
4089 HistoryRecord r = (HistoryRecord)list.get(i);
4090 if (localLOGV) Log.v(
4091 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4092 if (r.app == app) {
4093 if (localLOGV) Log.v(TAG, "Removing this entry!");
4094 list.remove(i);
4095 }
4096 }
4097 }
4098
4099 /**
4100 * Main function for removing an existing process from the activity manager
4101 * as a result of that process going away. Clears out all connections
4102 * to the process.
4103 */
4104 private final void handleAppDiedLocked(ProcessRecord app,
4105 boolean restarting) {
4106 cleanUpApplicationRecordLocked(app, restarting, -1);
4107 if (!restarting) {
4108 mLRUProcesses.remove(app);
4109 }
4110
4111 // Just in case...
4112 if (mPausingActivity != null && mPausingActivity.app == app) {
4113 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4114 mPausingActivity = null;
4115 }
4116 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4117 mLastPausedActivity = null;
4118 }
4119
4120 // Remove this application's activities from active lists.
4121 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4122 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4123 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4124 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4125
4126 boolean atTop = true;
4127 boolean hasVisibleActivities = false;
4128
4129 // Clean out the history list.
4130 int i = mHistory.size();
4131 if (localLOGV) Log.v(
4132 TAG, "Removing app " + app + " from history with " + i + " entries");
4133 while (i > 0) {
4134 i--;
4135 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4136 if (localLOGV) Log.v(
4137 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4138 if (r.app == app) {
4139 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4140 if (localLOGV) Log.v(
4141 TAG, "Removing this entry! frozen=" + r.haveState
4142 + " finishing=" + r.finishing);
4143 mHistory.remove(i);
4144
4145 r.inHistory = false;
4146 mWindowManager.removeAppToken(r);
4147 if (VALIDATE_TOKENS) {
4148 mWindowManager.validateAppTokens(mHistory);
4149 }
4150 removeActivityUriPermissionsLocked(r);
4151
4152 } else {
4153 // We have the current state for this activity, so
4154 // it can be restarted later when needed.
4155 if (localLOGV) Log.v(
4156 TAG, "Keeping entry, setting app to null");
4157 if (r.visible) {
4158 hasVisibleActivities = true;
4159 }
4160 r.app = null;
4161 r.nowVisible = false;
4162 if (!r.haveState) {
4163 r.icicle = null;
4164 }
4165 }
4166
4167 cleanUpActivityLocked(r, true);
4168 r.state = ActivityState.STOPPED;
4169 }
4170 atTop = false;
4171 }
4172
4173 app.activities.clear();
4174
4175 if (app.instrumentationClass != null) {
4176 Log.w(TAG, "Crash of app " + app.processName
4177 + " running instrumentation " + app.instrumentationClass);
4178 Bundle info = new Bundle();
4179 info.putString("shortMsg", "Process crashed.");
4180 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4181 }
4182
4183 if (!restarting) {
4184 if (!resumeTopActivityLocked(null)) {
4185 // If there was nothing to resume, and we are not already
4186 // restarting this process, but there is a visible activity that
4187 // is hosted by the process... then make sure all visible
4188 // activities are running, taking care of restarting this
4189 // process.
4190 if (hasVisibleActivities) {
4191 ensureActivitiesVisibleLocked(null, 0);
4192 }
4193 }
4194 }
4195 }
4196
4197 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4198 IBinder threadBinder = thread.asBinder();
4199
4200 // Find the application record.
4201 int count = mLRUProcesses.size();
4202 int i;
4203 for (i=0; i<count; i++) {
4204 ProcessRecord rec = mLRUProcesses.get(i);
4205 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4206 return i;
4207 }
4208 }
4209 return -1;
4210 }
4211
4212 private final ProcessRecord getRecordForAppLocked(
4213 IApplicationThread thread) {
4214 if (thread == null) {
4215 return null;
4216 }
4217
4218 int appIndex = getLRURecordIndexForAppLocked(thread);
4219 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4220 }
4221
4222 private final void appDiedLocked(ProcessRecord app, int pid,
4223 IApplicationThread thread) {
4224
4225 mProcDeaths[0]++;
4226
4227 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4228 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4229 + ") has died.");
4230 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4231 if (localLOGV) Log.v(
4232 TAG, "Dying app: " + app + ", pid: " + pid
4233 + ", thread: " + thread.asBinder());
4234 boolean doLowMem = app.instrumentationClass == null;
4235 handleAppDiedLocked(app, false);
4236
4237 if (doLowMem) {
4238 // If there are no longer any background processes running,
4239 // and the app that died was not running instrumentation,
4240 // then tell everyone we are now low on memory.
4241 boolean haveBg = false;
4242 int count = mLRUProcesses.size();
4243 int i;
4244 for (i=0; i<count; i++) {
4245 ProcessRecord rec = mLRUProcesses.get(i);
4246 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4247 haveBg = true;
4248 break;
4249 }
4250 }
4251
4252 if (!haveBg) {
4253 Log.i(TAG, "Low Memory: No more background processes.");
4254 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4255 for (i=0; i<count; i++) {
4256 ProcessRecord rec = mLRUProcesses.get(i);
4257 if (rec.thread != null) {
4258 rec.lastRequestedGc = SystemClock.uptimeMillis();
4259 try {
4260 rec.thread.scheduleLowMemory();
4261 } catch (RemoteException e) {
4262 // Don't care if the process is gone.
4263 }
4264 }
4265 }
4266 }
4267 }
4268 } else if (Config.LOGD) {
4269 Log.d(TAG, "Received spurious death notification for thread "
4270 + thread.asBinder());
4271 }
4272 }
4273
4274 final String readFile(String filename) {
4275 try {
4276 FileInputStream fs = new FileInputStream(filename);
4277 byte[] inp = new byte[8192];
4278 int size = fs.read(inp);
4279 fs.close();
4280 return new String(inp, 0, 0, size);
4281 } catch (java.io.IOException e) {
4282 }
4283 return "";
4284 }
4285
4286 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4287 final String annotation) {
4288 if (app.notResponding || app.crashing) {
4289 return;
4290 }
4291
4292 // Log the ANR to the event log.
4293 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4294
4295 // If we are on a secure build and the application is not interesting to the user (it is
4296 // not visible or in the background), just kill it instead of displaying a dialog.
4297 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4298 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4299 Process.killProcess(app.pid);
4300 return;
4301 }
4302
4303 // DeviceMonitor.start();
4304
4305 String processInfo = null;
4306 if (MONITOR_CPU_USAGE) {
4307 updateCpuStatsNow();
4308 synchronized (mProcessStatsThread) {
4309 processInfo = mProcessStats.printCurrentState();
4310 }
4311 }
4312
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004313 StringBuilder info = mStringBuilder;
4314 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004315 info.append("ANR (application not responding) in process: ");
4316 info.append(app.processName);
4317 if (annotation != null) {
4318 info.append("\nAnnotation: ");
4319 info.append(annotation);
4320 }
4321 if (MONITOR_CPU_USAGE) {
4322 info.append("\nCPU usage:\n");
4323 info.append(processInfo);
4324 }
4325 Log.i(TAG, info.toString());
4326
4327 // The application is not responding. Dump as many thread traces as we can.
4328 boolean fileDump = prepareTraceFile(true);
4329 if (!fileDump) {
4330 // Dumping traces to the log, just dump the process that isn't responding so
4331 // we don't overflow the log
4332 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4333 } else {
4334 // Dumping traces to a file so dump all active processes we know about
4335 synchronized (this) {
4336 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4337 ProcessRecord r = mLRUProcesses.get(i);
4338 if (r.thread != null) {
4339 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4340 }
4341 }
4342 }
4343 }
4344
4345 if (mWatcher != null) {
4346 try {
4347 int res = mWatcher.appNotResponding(app.processName,
4348 app.pid, info.toString());
4349 if (res != 0) {
4350 if (res < 0) {
4351 // wait until the SIGQUIT has had a chance to process before killing the
4352 // process.
4353 try {
4354 wait(2000);
4355 } catch (InterruptedException e) {
4356 }
4357
4358 Process.killProcess(app.pid);
4359 return;
4360 }
4361 }
4362 } catch (RemoteException e) {
4363 mWatcher = null;
4364 }
4365 }
4366
4367 makeAppNotRespondingLocked(app,
4368 activity != null ? activity.shortComponentName : null,
4369 annotation != null ? "ANR " + annotation : "ANR",
4370 info.toString(), null);
4371 Message msg = Message.obtain();
4372 HashMap map = new HashMap();
4373 msg.what = SHOW_NOT_RESPONDING_MSG;
4374 msg.obj = map;
4375 map.put("app", app);
4376 if (activity != null) {
4377 map.put("activity", activity);
4378 }
4379
4380 mHandler.sendMessage(msg);
4381 return;
4382 }
4383
4384 /**
4385 * If a stack trace file has been configured, prepare the filesystem
4386 * by creating the directory if it doesn't exist and optionally
4387 * removing the old trace file.
4388 *
4389 * @param removeExisting If set, the existing trace file will be removed.
4390 * @return Returns true if the trace file preparations succeeded
4391 */
4392 public static boolean prepareTraceFile(boolean removeExisting) {
4393 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4394 boolean fileReady = false;
4395 if (!TextUtils.isEmpty(tracesPath)) {
4396 File f = new File(tracesPath);
4397 if (!f.exists()) {
4398 // Ensure the enclosing directory exists
4399 File dir = f.getParentFile();
4400 if (!dir.exists()) {
4401 fileReady = dir.mkdirs();
4402 FileUtils.setPermissions(dir.getAbsolutePath(),
4403 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4404 } else if (dir.isDirectory()) {
4405 fileReady = true;
4406 }
4407 } else if (removeExisting) {
4408 // Remove the previous traces file, so we don't fill the disk.
4409 // The VM will recreate it
4410 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4411 fileReady = f.delete();
4412 }
4413 }
4414
4415 return fileReady;
4416 }
4417
4418
4419 private final void decPersistentCountLocked(ProcessRecord app)
4420 {
4421 app.persistentActivities--;
4422 if (app.persistentActivities > 0) {
4423 // Still more of 'em...
4424 return;
4425 }
4426 if (app.persistent) {
4427 // Ah, but the application itself is persistent. Whatever!
4428 return;
4429 }
4430
4431 // App is no longer persistent... make sure it and the ones
4432 // following it in the LRU list have the correc oom_adj.
4433 updateOomAdjLocked();
4434 }
4435
4436 public void setPersistent(IBinder token, boolean isPersistent) {
4437 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4438 != PackageManager.PERMISSION_GRANTED) {
4439 String msg = "Permission Denial: setPersistent() from pid="
4440 + Binder.getCallingPid()
4441 + ", uid=" + Binder.getCallingUid()
4442 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4443 Log.w(TAG, msg);
4444 throw new SecurityException(msg);
4445 }
4446
4447 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004448 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004449 if (index < 0) {
4450 return;
4451 }
4452 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4453 ProcessRecord app = r.app;
4454
4455 if (localLOGV) Log.v(
4456 TAG, "Setting persistence " + isPersistent + ": " + r);
4457
4458 if (isPersistent) {
4459 if (r.persistent) {
4460 // Okay okay, I heard you already!
4461 if (localLOGV) Log.v(TAG, "Already persistent!");
4462 return;
4463 }
4464 r.persistent = true;
4465 app.persistentActivities++;
4466 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4467 if (app.persistentActivities > 1) {
4468 // We aren't the first...
4469 if (localLOGV) Log.v(TAG, "Not the first!");
4470 return;
4471 }
4472 if (app.persistent) {
4473 // This would be redundant.
4474 if (localLOGV) Log.v(TAG, "App is persistent!");
4475 return;
4476 }
4477
4478 // App is now persistent... make sure it and the ones
4479 // following it now have the correct oom_adj.
4480 final long origId = Binder.clearCallingIdentity();
4481 updateOomAdjLocked();
4482 Binder.restoreCallingIdentity(origId);
4483
4484 } else {
4485 if (!r.persistent) {
4486 // Okay okay, I heard you already!
4487 return;
4488 }
4489 r.persistent = false;
4490 final long origId = Binder.clearCallingIdentity();
4491 decPersistentCountLocked(app);
4492 Binder.restoreCallingIdentity(origId);
4493
4494 }
4495 }
4496 }
4497
4498 public boolean clearApplicationUserData(final String packageName,
4499 final IPackageDataObserver observer) {
4500 int uid = Binder.getCallingUid();
4501 int pid = Binder.getCallingPid();
4502 long callingId = Binder.clearCallingIdentity();
4503 try {
4504 IPackageManager pm = ActivityThread.getPackageManager();
4505 int pkgUid = -1;
4506 synchronized(this) {
4507 try {
4508 pkgUid = pm.getPackageUid(packageName);
4509 } catch (RemoteException e) {
4510 }
4511 if (pkgUid == -1) {
4512 Log.w(TAG, "Invalid packageName:" + packageName);
4513 return false;
4514 }
4515 if (uid == pkgUid || checkComponentPermission(
4516 android.Manifest.permission.CLEAR_APP_USER_DATA,
4517 pid, uid, -1)
4518 == PackageManager.PERMISSION_GRANTED) {
4519 restartPackageLocked(packageName, pkgUid);
4520 } else {
4521 throw new SecurityException(pid+" does not have permission:"+
4522 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4523 "for process:"+packageName);
4524 }
4525 }
4526
4527 try {
4528 //clear application user data
4529 pm.clearApplicationUserData(packageName, observer);
4530 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4531 Uri.fromParts("package", packageName, null));
4532 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4533 broadcastIntentLocked(null, null, intent,
4534 null, null, 0, null, null, null,
4535 false, false, MY_PID, Process.SYSTEM_UID);
4536 } catch (RemoteException e) {
4537 }
4538 } finally {
4539 Binder.restoreCallingIdentity(callingId);
4540 }
4541 return true;
4542 }
4543
4544 public void restartPackage(final String packageName) {
4545 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4546 != PackageManager.PERMISSION_GRANTED) {
4547 String msg = "Permission Denial: restartPackage() from pid="
4548 + Binder.getCallingPid()
4549 + ", uid=" + Binder.getCallingUid()
4550 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4551 Log.w(TAG, msg);
4552 throw new SecurityException(msg);
4553 }
4554
4555 long callingId = Binder.clearCallingIdentity();
4556 try {
4557 IPackageManager pm = ActivityThread.getPackageManager();
4558 int pkgUid = -1;
4559 synchronized(this) {
4560 try {
4561 pkgUid = pm.getPackageUid(packageName);
4562 } catch (RemoteException e) {
4563 }
4564 if (pkgUid == -1) {
4565 Log.w(TAG, "Invalid packageName: " + packageName);
4566 return;
4567 }
4568 restartPackageLocked(packageName, pkgUid);
4569 }
4570 } finally {
4571 Binder.restoreCallingIdentity(callingId);
4572 }
4573 }
4574
4575 private void restartPackageLocked(final String packageName, int uid) {
4576 uninstallPackageLocked(packageName, uid, false);
4577 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4578 Uri.fromParts("package", packageName, null));
4579 intent.putExtra(Intent.EXTRA_UID, uid);
4580 broadcastIntentLocked(null, null, intent,
4581 null, null, 0, null, null, null,
4582 false, false, MY_PID, Process.SYSTEM_UID);
4583 }
4584
4585 private final void uninstallPackageLocked(String name, int uid,
4586 boolean callerWillRestart) {
4587 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4588
4589 int i, N;
4590
4591 final String procNamePrefix = name + ":";
4592 if (uid < 0) {
4593 try {
4594 uid = ActivityThread.getPackageManager().getPackageUid(name);
4595 } catch (RemoteException e) {
4596 }
4597 }
4598
4599 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4600 while (badApps.hasNext()) {
4601 SparseArray<Long> ba = badApps.next();
4602 if (ba.get(uid) != null) {
4603 badApps.remove();
4604 }
4605 }
4606
4607 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4608
4609 // Remove all processes this package may have touched: all with the
4610 // same UID (except for the system or root user), and all whose name
4611 // matches the package name.
4612 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4613 final int NA = apps.size();
4614 for (int ia=0; ia<NA; ia++) {
4615 ProcessRecord app = apps.valueAt(ia);
4616 if (app.removed) {
4617 procs.add(app);
4618 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4619 || app.processName.equals(name)
4620 || app.processName.startsWith(procNamePrefix)) {
4621 app.removed = true;
4622 procs.add(app);
4623 }
4624 }
4625 }
4626
4627 N = procs.size();
4628 for (i=0; i<N; i++) {
4629 removeProcessLocked(procs.get(i), callerWillRestart);
4630 }
4631
4632 for (i=mHistory.size()-1; i>=0; i--) {
4633 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4634 if (r.packageName.equals(name)) {
4635 if (Config.LOGD) Log.d(
4636 TAG, " Force finishing activity "
4637 + r.intent.getComponent().flattenToShortString());
4638 if (r.app != null) {
4639 r.app.removed = true;
4640 }
4641 r.app = null;
4642 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4643 }
4644 }
4645
4646 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4647 for (ServiceRecord service : mServices.values()) {
4648 if (service.packageName.equals(name)) {
4649 if (service.app != null) {
4650 service.app.removed = true;
4651 }
4652 service.app = null;
4653 services.add(service);
4654 }
4655 }
4656
4657 N = services.size();
4658 for (i=0; i<N; i++) {
4659 bringDownServiceLocked(services.get(i), true);
4660 }
4661
4662 resumeTopActivityLocked(null);
4663 }
4664
4665 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4666 final String name = app.processName;
4667 final int uid = app.info.uid;
4668 if (Config.LOGD) Log.d(
4669 TAG, "Force removing process " + app + " (" + name
4670 + "/" + uid + ")");
4671
4672 mProcessNames.remove(name, uid);
4673 boolean needRestart = false;
4674 if (app.pid > 0 && app.pid != MY_PID) {
4675 int pid = app.pid;
4676 synchronized (mPidsSelfLocked) {
4677 mPidsSelfLocked.remove(pid);
4678 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4679 }
4680 handleAppDiedLocked(app, true);
4681 mLRUProcesses.remove(app);
4682 Process.killProcess(pid);
4683
4684 if (app.persistent) {
4685 if (!callerWillRestart) {
4686 addAppLocked(app.info);
4687 } else {
4688 needRestart = true;
4689 }
4690 }
4691 } else {
4692 mRemovedProcesses.add(app);
4693 }
4694
4695 return needRestart;
4696 }
4697
4698 private final void processStartTimedOutLocked(ProcessRecord app) {
4699 final int pid = app.pid;
4700 boolean gone = false;
4701 synchronized (mPidsSelfLocked) {
4702 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4703 if (knownApp != null && knownApp.thread == null) {
4704 mPidsSelfLocked.remove(pid);
4705 gone = true;
4706 }
4707 }
4708
4709 if (gone) {
4710 Log.w(TAG, "Process " + app + " failed to attach");
4711 mProcessNames.remove(app.processName, app.info.uid);
4712 Process.killProcess(pid);
4713 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4714 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4715 mPendingBroadcast = null;
4716 scheduleBroadcastsLocked();
4717 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004718 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4719 Log.w(TAG, "Unattached app died before backup, skipping");
4720 try {
4721 IBackupManager bm = IBackupManager.Stub.asInterface(
4722 ServiceManager.getService(Context.BACKUP_SERVICE));
4723 bm.agentDisconnected(app.info.packageName);
4724 } catch (RemoteException e) {
4725 // Can't happen; the backup manager is local
4726 }
4727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004728 } else {
4729 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4730 }
4731 }
4732
4733 private final boolean attachApplicationLocked(IApplicationThread thread,
4734 int pid) {
4735
4736 // Find the application record that is being attached... either via
4737 // the pid if we are running in multiple processes, or just pull the
4738 // next app record if we are emulating process with anonymous threads.
4739 ProcessRecord app;
4740 if (pid != MY_PID && pid >= 0) {
4741 synchronized (mPidsSelfLocked) {
4742 app = mPidsSelfLocked.get(pid);
4743 }
4744 } else if (mStartingProcesses.size() > 0) {
4745 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004746 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004747 } else {
4748 app = null;
4749 }
4750
4751 if (app == null) {
4752 Log.w(TAG, "No pending application record for pid " + pid
4753 + " (IApplicationThread " + thread + "); dropping process");
4754 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4755 if (pid > 0 && pid != MY_PID) {
4756 Process.killProcess(pid);
4757 } else {
4758 try {
4759 thread.scheduleExit();
4760 } catch (Exception e) {
4761 // Ignore exceptions.
4762 }
4763 }
4764 return false;
4765 }
4766
4767 // If this application record is still attached to a previous
4768 // process, clean it up now.
4769 if (app.thread != null) {
4770 handleAppDiedLocked(app, true);
4771 }
4772
4773 // Tell the process all about itself.
4774
4775 if (localLOGV) Log.v(
4776 TAG, "Binding process pid " + pid + " to record " + app);
4777
4778 String processName = app.processName;
4779 try {
4780 thread.asBinder().linkToDeath(new AppDeathRecipient(
4781 app, pid, thread), 0);
4782 } catch (RemoteException e) {
4783 app.resetPackageList();
4784 startProcessLocked(app, "link fail", processName);
4785 return false;
4786 }
4787
4788 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4789
4790 app.thread = thread;
4791 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004792 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 app.forcingToForeground = null;
4794 app.foregroundServices = false;
4795 app.debugging = false;
4796
4797 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4798
4799 List providers = generateApplicationProvidersLocked(app);
4800
4801 if (localLOGV) Log.v(
4802 TAG, "New app record " + app
4803 + " thread=" + thread.asBinder() + " pid=" + pid);
4804 try {
4805 int testMode = IApplicationThread.DEBUG_OFF;
4806 if (mDebugApp != null && mDebugApp.equals(processName)) {
4807 testMode = mWaitForDebugger
4808 ? IApplicationThread.DEBUG_WAIT
4809 : IApplicationThread.DEBUG_ON;
4810 app.debugging = true;
4811 if (mDebugTransient) {
4812 mDebugApp = mOrigDebugApp;
4813 mWaitForDebugger = mOrigWaitForDebugger;
4814 }
4815 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004816 // If the app is being launched for restore or full backup, set it up specially
4817 boolean isRestrictedBackupMode = false;
4818 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4819 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4820 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4821 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004822 thread.bindApplication(processName, app.instrumentationInfo != null
4823 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004824 app.instrumentationClass, app.instrumentationProfileFile,
4825 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004826 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004827 updateLRUListLocked(app, false);
4828 app.lastRequestedGc = SystemClock.uptimeMillis();
4829 } catch (Exception e) {
4830 // todo: Yikes! What should we do? For now we will try to
4831 // start another process, but that could easily get us in
4832 // an infinite loop of restarting processes...
4833 Log.w(TAG, "Exception thrown during bind!", e);
4834
4835 app.resetPackageList();
4836 startProcessLocked(app, "bind fail", processName);
4837 return false;
4838 }
4839
4840 // Remove this record from the list of starting applications.
4841 mPersistentStartingProcesses.remove(app);
4842 mProcessesOnHold.remove(app);
4843
4844 boolean badApp = false;
4845 boolean didSomething = false;
4846
4847 // See if the top visible activity is waiting to run in this process...
4848 HistoryRecord hr = topRunningActivityLocked(null);
4849 if (hr != null) {
4850 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
4851 && processName.equals(hr.processName)) {
4852 try {
4853 if (realStartActivityLocked(hr, app, true, true)) {
4854 didSomething = true;
4855 }
4856 } catch (Exception e) {
4857 Log.w(TAG, "Exception in new application when starting activity "
4858 + hr.intent.getComponent().flattenToShortString(), e);
4859 badApp = true;
4860 }
4861 } else {
4862 ensureActivitiesVisibleLocked(hr, null, processName, 0);
4863 }
4864 }
4865
4866 // Find any services that should be running in this process...
4867 if (!badApp && mPendingServices.size() > 0) {
4868 ServiceRecord sr = null;
4869 try {
4870 for (int i=0; i<mPendingServices.size(); i++) {
4871 sr = mPendingServices.get(i);
4872 if (app.info.uid != sr.appInfo.uid
4873 || !processName.equals(sr.processName)) {
4874 continue;
4875 }
4876
4877 mPendingServices.remove(i);
4878 i--;
4879 realStartServiceLocked(sr, app);
4880 didSomething = true;
4881 }
4882 } catch (Exception e) {
4883 Log.w(TAG, "Exception in new application when starting service "
4884 + sr.shortName, e);
4885 badApp = true;
4886 }
4887 }
4888
4889 // Check if the next broadcast receiver is in this process...
4890 BroadcastRecord br = mPendingBroadcast;
4891 if (!badApp && br != null && br.curApp == app) {
4892 try {
4893 mPendingBroadcast = null;
4894 processCurBroadcastLocked(br, app);
4895 didSomething = true;
4896 } catch (Exception e) {
4897 Log.w(TAG, "Exception in new application when starting receiver "
4898 + br.curComponent.flattenToShortString(), e);
4899 badApp = true;
4900 logBroadcastReceiverDiscard(br);
4901 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
4902 br.resultExtras, br.resultAbort, true);
4903 scheduleBroadcastsLocked();
4904 }
4905 }
4906
Christopher Tate181fafa2009-05-14 11:12:14 -07004907 // Check whether the next backup agent is in this process...
4908 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
4909 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
4910 try {
4911 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
4912 } catch (Exception e) {
4913 Log.w(TAG, "Exception scheduling backup agent creation: ");
4914 e.printStackTrace();
4915 }
4916 }
4917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004918 if (badApp) {
4919 // todo: Also need to kill application to deal with all
4920 // kinds of exceptions.
4921 handleAppDiedLocked(app, false);
4922 return false;
4923 }
4924
4925 if (!didSomething) {
4926 updateOomAdjLocked();
4927 }
4928
4929 return true;
4930 }
4931
4932 public final void attachApplication(IApplicationThread thread) {
4933 synchronized (this) {
4934 int callingPid = Binder.getCallingPid();
4935 final long origId = Binder.clearCallingIdentity();
4936 attachApplicationLocked(thread, callingPid);
4937 Binder.restoreCallingIdentity(origId);
4938 }
4939 }
4940
4941 public final void activityIdle(IBinder token) {
4942 final long origId = Binder.clearCallingIdentity();
4943 activityIdleInternal(token, false);
4944 Binder.restoreCallingIdentity(origId);
4945 }
4946
4947 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
4948 boolean remove) {
4949 int N = mStoppingActivities.size();
4950 if (N <= 0) return null;
4951
4952 ArrayList<HistoryRecord> stops = null;
4953
4954 final boolean nowVisible = mResumedActivity != null
4955 && mResumedActivity.nowVisible
4956 && !mResumedActivity.waitingVisible;
4957 for (int i=0; i<N; i++) {
4958 HistoryRecord s = mStoppingActivities.get(i);
4959 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
4960 + nowVisible + " waitingVisible=" + s.waitingVisible
4961 + " finishing=" + s.finishing);
4962 if (s.waitingVisible && nowVisible) {
4963 mWaitingVisibleActivities.remove(s);
4964 s.waitingVisible = false;
4965 if (s.finishing) {
4966 // If this activity is finishing, it is sitting on top of
4967 // everyone else but we now know it is no longer needed...
4968 // so get rid of it. Otherwise, we need to go through the
4969 // normal flow and hide it once we determine that it is
4970 // hidden by the activities in front of it.
4971 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
4972 mWindowManager.setAppVisibility(s, false);
4973 }
4974 }
4975 if (!s.waitingVisible && remove) {
4976 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
4977 if (stops == null) {
4978 stops = new ArrayList<HistoryRecord>();
4979 }
4980 stops.add(s);
4981 mStoppingActivities.remove(i);
4982 N--;
4983 i--;
4984 }
4985 }
4986
4987 return stops;
4988 }
4989
4990 void enableScreenAfterBoot() {
4991 mWindowManager.enableScreenAfterBoot();
4992 }
4993
4994 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
4995 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
4996
4997 ArrayList<HistoryRecord> stops = null;
4998 ArrayList<HistoryRecord> finishes = null;
4999 ArrayList<HistoryRecord> thumbnails = null;
5000 int NS = 0;
5001 int NF = 0;
5002 int NT = 0;
5003 IApplicationThread sendThumbnail = null;
5004 boolean booting = false;
5005 boolean enableScreen = false;
5006
5007 synchronized (this) {
5008 if (token != null) {
5009 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5010 }
5011
5012 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005013 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005014 if (index >= 0) {
5015 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5016
5017 // No longer need to keep the device awake.
5018 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5019 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5020 mLaunchingActivity.release();
5021 }
5022
5023 // We are now idle. If someone is waiting for a thumbnail from
5024 // us, we can now deliver.
5025 r.idle = true;
5026 scheduleAppGcsLocked();
5027 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5028 sendThumbnail = r.app.thread;
5029 r.thumbnailNeeded = false;
5030 }
5031
5032 // If this activity is fullscreen, set up to hide those under it.
5033
5034 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5035 ensureActivitiesVisibleLocked(null, 0);
5036
5037 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5038 if (!mBooted && !fromTimeout) {
5039 mBooted = true;
5040 enableScreen = true;
5041 }
5042 }
5043
5044 // Atomically retrieve all of the other things to do.
5045 stops = processStoppingActivitiesLocked(true);
5046 NS = stops != null ? stops.size() : 0;
5047 if ((NF=mFinishingActivities.size()) > 0) {
5048 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5049 mFinishingActivities.clear();
5050 }
5051 if ((NT=mCancelledThumbnails.size()) > 0) {
5052 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5053 mCancelledThumbnails.clear();
5054 }
5055
5056 booting = mBooting;
5057 mBooting = false;
5058 }
5059
5060 int i;
5061
5062 // Send thumbnail if requested.
5063 if (sendThumbnail != null) {
5064 try {
5065 sendThumbnail.requestThumbnail(token);
5066 } catch (Exception e) {
5067 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5068 sendPendingThumbnail(null, token, null, null, true);
5069 }
5070 }
5071
5072 // Stop any activities that are scheduled to do so but have been
5073 // waiting for the next one to start.
5074 for (i=0; i<NS; i++) {
5075 HistoryRecord r = (HistoryRecord)stops.get(i);
5076 synchronized (this) {
5077 if (r.finishing) {
5078 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5079 } else {
5080 stopActivityLocked(r);
5081 }
5082 }
5083 }
5084
5085 // Finish any activities that are scheduled to do so but have been
5086 // waiting for the next one to start.
5087 for (i=0; i<NF; i++) {
5088 HistoryRecord r = (HistoryRecord)finishes.get(i);
5089 synchronized (this) {
5090 destroyActivityLocked(r, true);
5091 }
5092 }
5093
5094 // Report back to any thumbnail receivers.
5095 for (i=0; i<NT; i++) {
5096 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5097 sendPendingThumbnail(r, null, null, null, true);
5098 }
5099
5100 if (booting) {
5101 // Ensure that any processes we had put on hold are now started
5102 // up.
5103 final int NP = mProcessesOnHold.size();
5104 if (NP > 0) {
5105 ArrayList<ProcessRecord> procs =
5106 new ArrayList<ProcessRecord>(mProcessesOnHold);
5107 for (int ip=0; ip<NP; ip++) {
5108 this.startProcessLocked(procs.get(ip), "on-hold", null);
5109 }
5110 }
5111 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5112 // Tell anyone interested that we are done booting!
5113 synchronized (this) {
5114 broadcastIntentLocked(null, null,
5115 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5116 null, null, 0, null, null,
5117 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5118 false, false, MY_PID, Process.SYSTEM_UID);
5119 }
5120 }
5121 }
5122
5123 trimApplications();
5124 //dump();
5125 //mWindowManager.dump();
5126
5127 if (enableScreen) {
5128 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5129 SystemClock.uptimeMillis());
5130 enableScreenAfterBoot();
5131 }
5132 }
5133
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005134 final void ensureScreenEnabled() {
5135 boolean enableScreen;
5136 synchronized (this) {
5137 enableScreen = !mBooted;
5138 mBooted = true;
5139 }
5140
5141 if (enableScreen) {
5142 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5143 SystemClock.uptimeMillis());
5144 enableScreenAfterBoot();
5145 }
5146 }
5147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005148 public final void activityPaused(IBinder token, Bundle icicle) {
5149 // Refuse possible leaked file descriptors
5150 if (icicle != null && icicle.hasFileDescriptors()) {
5151 throw new IllegalArgumentException("File descriptors passed in Bundle");
5152 }
5153
5154 final long origId = Binder.clearCallingIdentity();
5155 activityPaused(token, icicle, false);
5156 Binder.restoreCallingIdentity(origId);
5157 }
5158
5159 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5160 if (DEBUG_PAUSE) Log.v(
5161 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5162 + ", timeout=" + timeout);
5163
5164 HistoryRecord r = null;
5165
5166 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005167 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005168 if (index >= 0) {
5169 r = (HistoryRecord)mHistory.get(index);
5170 if (!timeout) {
5171 r.icicle = icicle;
5172 r.haveState = true;
5173 }
5174 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5175 if (mPausingActivity == r) {
5176 r.state = ActivityState.PAUSED;
5177 completePauseLocked();
5178 } else {
5179 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5180 System.identityHashCode(r), r.shortComponentName,
5181 mPausingActivity != null
5182 ? mPausingActivity.shortComponentName : "(none)");
5183 }
5184 }
5185 }
5186 }
5187
5188 public final void activityStopped(IBinder token, Bitmap thumbnail,
5189 CharSequence description) {
5190 if (localLOGV) Log.v(
5191 TAG, "Activity stopped: token=" + token);
5192
5193 HistoryRecord r = null;
5194
5195 final long origId = Binder.clearCallingIdentity();
5196
5197 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005198 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 if (index >= 0) {
5200 r = (HistoryRecord)mHistory.get(index);
5201 r.thumbnail = thumbnail;
5202 r.description = description;
5203 r.stopped = true;
5204 r.state = ActivityState.STOPPED;
5205 if (!r.finishing) {
5206 if (r.configDestroy) {
5207 destroyActivityLocked(r, true);
5208 resumeTopActivityLocked(null);
5209 }
5210 }
5211 }
5212 }
5213
5214 if (r != null) {
5215 sendPendingThumbnail(r, null, null, null, false);
5216 }
5217
5218 trimApplications();
5219
5220 Binder.restoreCallingIdentity(origId);
5221 }
5222
5223 public final void activityDestroyed(IBinder token) {
5224 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5225 synchronized (this) {
5226 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5227
Dianne Hackborn75b03852009-06-12 15:43:26 -07005228 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005229 if (index >= 0) {
5230 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5231 if (r.state == ActivityState.DESTROYING) {
5232 final long origId = Binder.clearCallingIdentity();
5233 removeActivityFromHistoryLocked(r);
5234 Binder.restoreCallingIdentity(origId);
5235 }
5236 }
5237 }
5238 }
5239
5240 public String getCallingPackage(IBinder token) {
5241 synchronized (this) {
5242 HistoryRecord r = getCallingRecordLocked(token);
5243 return r != null && r.app != null ? r.app.processName : null;
5244 }
5245 }
5246
5247 public ComponentName getCallingActivity(IBinder token) {
5248 synchronized (this) {
5249 HistoryRecord r = getCallingRecordLocked(token);
5250 return r != null ? r.intent.getComponent() : null;
5251 }
5252 }
5253
5254 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005255 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005256 if (index >= 0) {
5257 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5258 if (r != null) {
5259 return r.resultTo;
5260 }
5261 }
5262 return null;
5263 }
5264
5265 public ComponentName getActivityClassForToken(IBinder token) {
5266 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005267 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005268 if (index >= 0) {
5269 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5270 return r.intent.getComponent();
5271 }
5272 return null;
5273 }
5274 }
5275
5276 public String getPackageForToken(IBinder token) {
5277 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005278 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005279 if (index >= 0) {
5280 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5281 return r.packageName;
5282 }
5283 return null;
5284 }
5285 }
5286
5287 public IIntentSender getIntentSender(int type,
5288 String packageName, IBinder token, String resultWho,
5289 int requestCode, Intent intent, String resolvedType, int flags) {
5290 // Refuse possible leaked file descriptors
5291 if (intent != null && intent.hasFileDescriptors() == true) {
5292 throw new IllegalArgumentException("File descriptors passed in Intent");
5293 }
5294
5295 synchronized(this) {
5296 int callingUid = Binder.getCallingUid();
5297 try {
5298 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5299 Process.supportsProcesses()) {
5300 int uid = ActivityThread.getPackageManager()
5301 .getPackageUid(packageName);
5302 if (uid != Binder.getCallingUid()) {
5303 String msg = "Permission Denial: getIntentSender() from pid="
5304 + Binder.getCallingPid()
5305 + ", uid=" + Binder.getCallingUid()
5306 + ", (need uid=" + uid + ")"
5307 + " is not allowed to send as package " + packageName;
5308 Log.w(TAG, msg);
5309 throw new SecurityException(msg);
5310 }
5311 }
5312 } catch (RemoteException e) {
5313 throw new SecurityException(e);
5314 }
5315 HistoryRecord activity = null;
5316 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005317 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005318 if (index < 0) {
5319 return null;
5320 }
5321 activity = (HistoryRecord)mHistory.get(index);
5322 if (activity.finishing) {
5323 return null;
5324 }
5325 }
5326
5327 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5328 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5329 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5330 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5331 |PendingIntent.FLAG_UPDATE_CURRENT);
5332
5333 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5334 type, packageName, activity, resultWho,
5335 requestCode, intent, resolvedType, flags);
5336 WeakReference<PendingIntentRecord> ref;
5337 ref = mIntentSenderRecords.get(key);
5338 PendingIntentRecord rec = ref != null ? ref.get() : null;
5339 if (rec != null) {
5340 if (!cancelCurrent) {
5341 if (updateCurrent) {
5342 rec.key.requestIntent.replaceExtras(intent);
5343 }
5344 return rec;
5345 }
5346 rec.canceled = true;
5347 mIntentSenderRecords.remove(key);
5348 }
5349 if (noCreate) {
5350 return rec;
5351 }
5352 rec = new PendingIntentRecord(this, key, callingUid);
5353 mIntentSenderRecords.put(key, rec.ref);
5354 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5355 if (activity.pendingResults == null) {
5356 activity.pendingResults
5357 = new HashSet<WeakReference<PendingIntentRecord>>();
5358 }
5359 activity.pendingResults.add(rec.ref);
5360 }
5361 return rec;
5362 }
5363 }
5364
5365 public void cancelIntentSender(IIntentSender sender) {
5366 if (!(sender instanceof PendingIntentRecord)) {
5367 return;
5368 }
5369 synchronized(this) {
5370 PendingIntentRecord rec = (PendingIntentRecord)sender;
5371 try {
5372 int uid = ActivityThread.getPackageManager()
5373 .getPackageUid(rec.key.packageName);
5374 if (uid != Binder.getCallingUid()) {
5375 String msg = "Permission Denial: cancelIntentSender() from pid="
5376 + Binder.getCallingPid()
5377 + ", uid=" + Binder.getCallingUid()
5378 + " is not allowed to cancel packges "
5379 + rec.key.packageName;
5380 Log.w(TAG, msg);
5381 throw new SecurityException(msg);
5382 }
5383 } catch (RemoteException e) {
5384 throw new SecurityException(e);
5385 }
5386 cancelIntentSenderLocked(rec, true);
5387 }
5388 }
5389
5390 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5391 rec.canceled = true;
5392 mIntentSenderRecords.remove(rec.key);
5393 if (cleanActivity && rec.key.activity != null) {
5394 rec.key.activity.pendingResults.remove(rec.ref);
5395 }
5396 }
5397
5398 public String getPackageForIntentSender(IIntentSender pendingResult) {
5399 if (!(pendingResult instanceof PendingIntentRecord)) {
5400 return null;
5401 }
5402 synchronized(this) {
5403 try {
5404 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5405 return res.key.packageName;
5406 } catch (ClassCastException e) {
5407 }
5408 }
5409 return null;
5410 }
5411
5412 public void setProcessLimit(int max) {
5413 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5414 "setProcessLimit()");
5415 mProcessLimit = max;
5416 }
5417
5418 public int getProcessLimit() {
5419 return mProcessLimit;
5420 }
5421
5422 void foregroundTokenDied(ForegroundToken token) {
5423 synchronized (ActivityManagerService.this) {
5424 synchronized (mPidsSelfLocked) {
5425 ForegroundToken cur
5426 = mForegroundProcesses.get(token.pid);
5427 if (cur != token) {
5428 return;
5429 }
5430 mForegroundProcesses.remove(token.pid);
5431 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5432 if (pr == null) {
5433 return;
5434 }
5435 pr.forcingToForeground = null;
5436 pr.foregroundServices = false;
5437 }
5438 updateOomAdjLocked();
5439 }
5440 }
5441
5442 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5443 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5444 "setProcessForeground()");
5445 synchronized(this) {
5446 boolean changed = false;
5447
5448 synchronized (mPidsSelfLocked) {
5449 ProcessRecord pr = mPidsSelfLocked.get(pid);
5450 if (pr == null) {
5451 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5452 return;
5453 }
5454 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5455 if (oldToken != null) {
5456 oldToken.token.unlinkToDeath(oldToken, 0);
5457 mForegroundProcesses.remove(pid);
5458 pr.forcingToForeground = null;
5459 changed = true;
5460 }
5461 if (isForeground && token != null) {
5462 ForegroundToken newToken = new ForegroundToken() {
5463 public void binderDied() {
5464 foregroundTokenDied(this);
5465 }
5466 };
5467 newToken.pid = pid;
5468 newToken.token = token;
5469 try {
5470 token.linkToDeath(newToken, 0);
5471 mForegroundProcesses.put(pid, newToken);
5472 pr.forcingToForeground = token;
5473 changed = true;
5474 } catch (RemoteException e) {
5475 // If the process died while doing this, we will later
5476 // do the cleanup with the process death link.
5477 }
5478 }
5479 }
5480
5481 if (changed) {
5482 updateOomAdjLocked();
5483 }
5484 }
5485 }
5486
5487 // =========================================================
5488 // PERMISSIONS
5489 // =========================================================
5490
5491 static class PermissionController extends IPermissionController.Stub {
5492 ActivityManagerService mActivityManagerService;
5493 PermissionController(ActivityManagerService activityManagerService) {
5494 mActivityManagerService = activityManagerService;
5495 }
5496
5497 public boolean checkPermission(String permission, int pid, int uid) {
5498 return mActivityManagerService.checkPermission(permission, pid,
5499 uid) == PackageManager.PERMISSION_GRANTED;
5500 }
5501 }
5502
5503 /**
5504 * This can be called with or without the global lock held.
5505 */
5506 int checkComponentPermission(String permission, int pid, int uid,
5507 int reqUid) {
5508 // We might be performing an operation on behalf of an indirect binder
5509 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5510 // client identity accordingly before proceeding.
5511 Identity tlsIdentity = sCallerIdentity.get();
5512 if (tlsIdentity != null) {
5513 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5514 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5515 uid = tlsIdentity.uid;
5516 pid = tlsIdentity.pid;
5517 }
5518
5519 // Root, system server and our own process get to do everything.
5520 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5521 !Process.supportsProcesses()) {
5522 return PackageManager.PERMISSION_GRANTED;
5523 }
5524 // If the target requires a specific UID, always fail for others.
5525 if (reqUid >= 0 && uid != reqUid) {
5526 return PackageManager.PERMISSION_DENIED;
5527 }
5528 if (permission == null) {
5529 return PackageManager.PERMISSION_GRANTED;
5530 }
5531 try {
5532 return ActivityThread.getPackageManager()
5533 .checkUidPermission(permission, uid);
5534 } catch (RemoteException e) {
5535 // Should never happen, but if it does... deny!
5536 Log.e(TAG, "PackageManager is dead?!?", e);
5537 }
5538 return PackageManager.PERMISSION_DENIED;
5539 }
5540
5541 /**
5542 * As the only public entry point for permissions checking, this method
5543 * can enforce the semantic that requesting a check on a null global
5544 * permission is automatically denied. (Internally a null permission
5545 * string is used when calling {@link #checkComponentPermission} in cases
5546 * when only uid-based security is needed.)
5547 *
5548 * This can be called with or without the global lock held.
5549 */
5550 public int checkPermission(String permission, int pid, int uid) {
5551 if (permission == null) {
5552 return PackageManager.PERMISSION_DENIED;
5553 }
5554 return checkComponentPermission(permission, pid, uid, -1);
5555 }
5556
5557 /**
5558 * Binder IPC calls go through the public entry point.
5559 * This can be called with or without the global lock held.
5560 */
5561 int checkCallingPermission(String permission) {
5562 return checkPermission(permission,
5563 Binder.getCallingPid(),
5564 Binder.getCallingUid());
5565 }
5566
5567 /**
5568 * This can be called with or without the global lock held.
5569 */
5570 void enforceCallingPermission(String permission, String func) {
5571 if (checkCallingPermission(permission)
5572 == PackageManager.PERMISSION_GRANTED) {
5573 return;
5574 }
5575
5576 String msg = "Permission Denial: " + func + " from pid="
5577 + Binder.getCallingPid()
5578 + ", uid=" + Binder.getCallingUid()
5579 + " requires " + permission;
5580 Log.w(TAG, msg);
5581 throw new SecurityException(msg);
5582 }
5583
5584 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5585 ProviderInfo pi, int uid, int modeFlags) {
5586 try {
5587 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5588 if ((pi.readPermission != null) &&
5589 (pm.checkUidPermission(pi.readPermission, uid)
5590 != PackageManager.PERMISSION_GRANTED)) {
5591 return false;
5592 }
5593 }
5594 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5595 if ((pi.writePermission != null) &&
5596 (pm.checkUidPermission(pi.writePermission, uid)
5597 != PackageManager.PERMISSION_GRANTED)) {
5598 return false;
5599 }
5600 }
5601 return true;
5602 } catch (RemoteException e) {
5603 return false;
5604 }
5605 }
5606
5607 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5608 int modeFlags) {
5609 // Root gets to do everything.
5610 if (uid == 0 || !Process.supportsProcesses()) {
5611 return true;
5612 }
5613 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5614 if (perms == null) return false;
5615 UriPermission perm = perms.get(uri);
5616 if (perm == null) return false;
5617 return (modeFlags&perm.modeFlags) == modeFlags;
5618 }
5619
5620 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5621 // Another redirected-binder-call permissions check as in
5622 // {@link checkComponentPermission}.
5623 Identity tlsIdentity = sCallerIdentity.get();
5624 if (tlsIdentity != null) {
5625 uid = tlsIdentity.uid;
5626 pid = tlsIdentity.pid;
5627 }
5628
5629 // Our own process gets to do everything.
5630 if (pid == MY_PID) {
5631 return PackageManager.PERMISSION_GRANTED;
5632 }
5633 synchronized(this) {
5634 return checkUriPermissionLocked(uri, uid, modeFlags)
5635 ? PackageManager.PERMISSION_GRANTED
5636 : PackageManager.PERMISSION_DENIED;
5637 }
5638 }
5639
5640 private void grantUriPermissionLocked(int callingUid,
5641 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5642 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5643 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5644 if (modeFlags == 0) {
5645 return;
5646 }
5647
5648 final IPackageManager pm = ActivityThread.getPackageManager();
5649
5650 // If this is not a content: uri, we can't do anything with it.
5651 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5652 return;
5653 }
5654
5655 String name = uri.getAuthority();
5656 ProviderInfo pi = null;
5657 ContentProviderRecord cpr
5658 = (ContentProviderRecord)mProvidersByName.get(name);
5659 if (cpr != null) {
5660 pi = cpr.info;
5661 } else {
5662 try {
5663 pi = pm.resolveContentProvider(name,
5664 PackageManager.GET_URI_PERMISSION_PATTERNS);
5665 } catch (RemoteException ex) {
5666 }
5667 }
5668 if (pi == null) {
5669 Log.w(TAG, "No content provider found for: " + name);
5670 return;
5671 }
5672
5673 int targetUid;
5674 try {
5675 targetUid = pm.getPackageUid(targetPkg);
5676 if (targetUid < 0) {
5677 return;
5678 }
5679 } catch (RemoteException ex) {
5680 return;
5681 }
5682
5683 // First... does the target actually need this permission?
5684 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5685 // No need to grant the target this permission.
5686 return;
5687 }
5688
5689 // Second... maybe someone else has already granted the
5690 // permission?
5691 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5692 // No need to grant the target this permission.
5693 return;
5694 }
5695
5696 // Third... is the provider allowing granting of URI permissions?
5697 if (!pi.grantUriPermissions) {
5698 throw new SecurityException("Provider " + pi.packageName
5699 + "/" + pi.name
5700 + " does not allow granting of Uri permissions (uri "
5701 + uri + ")");
5702 }
5703 if (pi.uriPermissionPatterns != null) {
5704 final int N = pi.uriPermissionPatterns.length;
5705 boolean allowed = false;
5706 for (int i=0; i<N; i++) {
5707 if (pi.uriPermissionPatterns[i] != null
5708 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5709 allowed = true;
5710 break;
5711 }
5712 }
5713 if (!allowed) {
5714 throw new SecurityException("Provider " + pi.packageName
5715 + "/" + pi.name
5716 + " does not allow granting of permission to path of Uri "
5717 + uri);
5718 }
5719 }
5720
5721 // Fourth... does the caller itself have permission to access
5722 // this uri?
5723 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5724 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5725 throw new SecurityException("Uid " + callingUid
5726 + " does not have permission to uri " + uri);
5727 }
5728 }
5729
5730 // Okay! So here we are: the caller has the assumed permission
5731 // to the uri, and the target doesn't. Let's now give this to
5732 // the target.
5733
5734 HashMap<Uri, UriPermission> targetUris
5735 = mGrantedUriPermissions.get(targetUid);
5736 if (targetUris == null) {
5737 targetUris = new HashMap<Uri, UriPermission>();
5738 mGrantedUriPermissions.put(targetUid, targetUris);
5739 }
5740
5741 UriPermission perm = targetUris.get(uri);
5742 if (perm == null) {
5743 perm = new UriPermission(targetUid, uri);
5744 targetUris.put(uri, perm);
5745
5746 }
5747 perm.modeFlags |= modeFlags;
5748 if (activity == null) {
5749 perm.globalModeFlags |= modeFlags;
5750 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5751 perm.readActivities.add(activity);
5752 if (activity.readUriPermissions == null) {
5753 activity.readUriPermissions = new HashSet<UriPermission>();
5754 }
5755 activity.readUriPermissions.add(perm);
5756 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5757 perm.writeActivities.add(activity);
5758 if (activity.writeUriPermissions == null) {
5759 activity.writeUriPermissions = new HashSet<UriPermission>();
5760 }
5761 activity.writeUriPermissions.add(perm);
5762 }
5763 }
5764
5765 private void grantUriPermissionFromIntentLocked(int callingUid,
5766 String targetPkg, Intent intent, HistoryRecord activity) {
5767 if (intent == null) {
5768 return;
5769 }
5770 Uri data = intent.getData();
5771 if (data == null) {
5772 return;
5773 }
5774 grantUriPermissionLocked(callingUid, targetPkg, data,
5775 intent.getFlags(), activity);
5776 }
5777
5778 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5779 Uri uri, int modeFlags) {
5780 synchronized(this) {
5781 final ProcessRecord r = getRecordForAppLocked(caller);
5782 if (r == null) {
5783 throw new SecurityException("Unable to find app for caller "
5784 + caller
5785 + " when granting permission to uri " + uri);
5786 }
5787 if (targetPkg == null) {
5788 Log.w(TAG, "grantUriPermission: null target");
5789 return;
5790 }
5791 if (uri == null) {
5792 Log.w(TAG, "grantUriPermission: null uri");
5793 return;
5794 }
5795
5796 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5797 null);
5798 }
5799 }
5800
5801 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5802 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5803 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5804 HashMap<Uri, UriPermission> perms
5805 = mGrantedUriPermissions.get(perm.uid);
5806 if (perms != null) {
5807 perms.remove(perm.uri);
5808 if (perms.size() == 0) {
5809 mGrantedUriPermissions.remove(perm.uid);
5810 }
5811 }
5812 }
5813 }
5814
5815 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5816 if (activity.readUriPermissions != null) {
5817 for (UriPermission perm : activity.readUriPermissions) {
5818 perm.readActivities.remove(activity);
5819 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5820 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5821 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5822 removeUriPermissionIfNeededLocked(perm);
5823 }
5824 }
5825 }
5826 if (activity.writeUriPermissions != null) {
5827 for (UriPermission perm : activity.writeUriPermissions) {
5828 perm.writeActivities.remove(activity);
5829 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5830 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5831 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5832 removeUriPermissionIfNeededLocked(perm);
5833 }
5834 }
5835 }
5836 }
5837
5838 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5839 int modeFlags) {
5840 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5841 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5842 if (modeFlags == 0) {
5843 return;
5844 }
5845
5846 final IPackageManager pm = ActivityThread.getPackageManager();
5847
5848 final String authority = uri.getAuthority();
5849 ProviderInfo pi = null;
5850 ContentProviderRecord cpr
5851 = (ContentProviderRecord)mProvidersByName.get(authority);
5852 if (cpr != null) {
5853 pi = cpr.info;
5854 } else {
5855 try {
5856 pi = pm.resolveContentProvider(authority,
5857 PackageManager.GET_URI_PERMISSION_PATTERNS);
5858 } catch (RemoteException ex) {
5859 }
5860 }
5861 if (pi == null) {
5862 Log.w(TAG, "No content provider found for: " + authority);
5863 return;
5864 }
5865
5866 // Does the caller have this permission on the URI?
5867 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5868 // Right now, if you are not the original owner of the permission,
5869 // you are not allowed to revoke it.
5870 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5871 throw new SecurityException("Uid " + callingUid
5872 + " does not have permission to uri " + uri);
5873 //}
5874 }
5875
5876 // Go through all of the permissions and remove any that match.
5877 final List<String> SEGMENTS = uri.getPathSegments();
5878 if (SEGMENTS != null) {
5879 final int NS = SEGMENTS.size();
5880 int N = mGrantedUriPermissions.size();
5881 for (int i=0; i<N; i++) {
5882 HashMap<Uri, UriPermission> perms
5883 = mGrantedUriPermissions.valueAt(i);
5884 Iterator<UriPermission> it = perms.values().iterator();
5885 toploop:
5886 while (it.hasNext()) {
5887 UriPermission perm = it.next();
5888 Uri targetUri = perm.uri;
5889 if (!authority.equals(targetUri.getAuthority())) {
5890 continue;
5891 }
5892 List<String> targetSegments = targetUri.getPathSegments();
5893 if (targetSegments == null) {
5894 continue;
5895 }
5896 if (targetSegments.size() < NS) {
5897 continue;
5898 }
5899 for (int j=0; j<NS; j++) {
5900 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
5901 continue toploop;
5902 }
5903 }
5904 perm.clearModes(modeFlags);
5905 if (perm.modeFlags == 0) {
5906 it.remove();
5907 }
5908 }
5909 if (perms.size() == 0) {
5910 mGrantedUriPermissions.remove(
5911 mGrantedUriPermissions.keyAt(i));
5912 N--;
5913 i--;
5914 }
5915 }
5916 }
5917 }
5918
5919 public void revokeUriPermission(IApplicationThread caller, Uri uri,
5920 int modeFlags) {
5921 synchronized(this) {
5922 final ProcessRecord r = getRecordForAppLocked(caller);
5923 if (r == null) {
5924 throw new SecurityException("Unable to find app for caller "
5925 + caller
5926 + " when revoking permission to uri " + uri);
5927 }
5928 if (uri == null) {
5929 Log.w(TAG, "revokeUriPermission: null uri");
5930 return;
5931 }
5932
5933 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5934 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5935 if (modeFlags == 0) {
5936 return;
5937 }
5938
5939 final IPackageManager pm = ActivityThread.getPackageManager();
5940
5941 final String authority = uri.getAuthority();
5942 ProviderInfo pi = null;
5943 ContentProviderRecord cpr
5944 = (ContentProviderRecord)mProvidersByName.get(authority);
5945 if (cpr != null) {
5946 pi = cpr.info;
5947 } else {
5948 try {
5949 pi = pm.resolveContentProvider(authority,
5950 PackageManager.GET_URI_PERMISSION_PATTERNS);
5951 } catch (RemoteException ex) {
5952 }
5953 }
5954 if (pi == null) {
5955 Log.w(TAG, "No content provider found for: " + authority);
5956 return;
5957 }
5958
5959 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
5960 }
5961 }
5962
5963 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
5964 synchronized (this) {
5965 ProcessRecord app =
5966 who != null ? getRecordForAppLocked(who) : null;
5967 if (app == null) return;
5968
5969 Message msg = Message.obtain();
5970 msg.what = WAIT_FOR_DEBUGGER_MSG;
5971 msg.obj = app;
5972 msg.arg1 = waiting ? 1 : 0;
5973 mHandler.sendMessage(msg);
5974 }
5975 }
5976
5977 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
5978 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08005979 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005980 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08005981 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005982 }
5983
5984 // =========================================================
5985 // TASK MANAGEMENT
5986 // =========================================================
5987
5988 public List getTasks(int maxNum, int flags,
5989 IThumbnailReceiver receiver) {
5990 ArrayList list = new ArrayList();
5991
5992 PendingThumbnailsRecord pending = null;
5993 IApplicationThread topThumbnail = null;
5994 HistoryRecord topRecord = null;
5995
5996 synchronized(this) {
5997 if (localLOGV) Log.v(
5998 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
5999 + ", receiver=" + receiver);
6000
6001 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6002 != PackageManager.PERMISSION_GRANTED) {
6003 if (receiver != null) {
6004 // If the caller wants to wait for pending thumbnails,
6005 // it ain't gonna get them.
6006 try {
6007 receiver.finished();
6008 } catch (RemoteException ex) {
6009 }
6010 }
6011 String msg = "Permission Denial: getTasks() from pid="
6012 + Binder.getCallingPid()
6013 + ", uid=" + Binder.getCallingUid()
6014 + " requires " + android.Manifest.permission.GET_TASKS;
6015 Log.w(TAG, msg);
6016 throw new SecurityException(msg);
6017 }
6018
6019 int pos = mHistory.size()-1;
6020 HistoryRecord next =
6021 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6022 HistoryRecord top = null;
6023 CharSequence topDescription = null;
6024 TaskRecord curTask = null;
6025 int numActivities = 0;
6026 int numRunning = 0;
6027 while (pos >= 0 && maxNum > 0) {
6028 final HistoryRecord r = next;
6029 pos--;
6030 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6031
6032 // Initialize state for next task if needed.
6033 if (top == null ||
6034 (top.state == ActivityState.INITIALIZING
6035 && top.task == r.task)) {
6036 top = r;
6037 topDescription = r.description;
6038 curTask = r.task;
6039 numActivities = numRunning = 0;
6040 }
6041
6042 // Add 'r' into the current task.
6043 numActivities++;
6044 if (r.app != null && r.app.thread != null) {
6045 numRunning++;
6046 }
6047 if (topDescription == null) {
6048 topDescription = r.description;
6049 }
6050
6051 if (localLOGV) Log.v(
6052 TAG, r.intent.getComponent().flattenToShortString()
6053 + ": task=" + r.task);
6054
6055 // If the next one is a different task, generate a new
6056 // TaskInfo entry for what we have.
6057 if (next == null || next.task != curTask) {
6058 ActivityManager.RunningTaskInfo ci
6059 = new ActivityManager.RunningTaskInfo();
6060 ci.id = curTask.taskId;
6061 ci.baseActivity = r.intent.getComponent();
6062 ci.topActivity = top.intent.getComponent();
6063 ci.thumbnail = top.thumbnail;
6064 ci.description = topDescription;
6065 ci.numActivities = numActivities;
6066 ci.numRunning = numRunning;
6067 //System.out.println(
6068 // "#" + maxNum + ": " + " descr=" + ci.description);
6069 if (ci.thumbnail == null && receiver != null) {
6070 if (localLOGV) Log.v(
6071 TAG, "State=" + top.state + "Idle=" + top.idle
6072 + " app=" + top.app
6073 + " thr=" + (top.app != null ? top.app.thread : null));
6074 if (top.state == ActivityState.RESUMED
6075 || top.state == ActivityState.PAUSING) {
6076 if (top.idle && top.app != null
6077 && top.app.thread != null) {
6078 topRecord = top;
6079 topThumbnail = top.app.thread;
6080 } else {
6081 top.thumbnailNeeded = true;
6082 }
6083 }
6084 if (pending == null) {
6085 pending = new PendingThumbnailsRecord(receiver);
6086 }
6087 pending.pendingRecords.add(top);
6088 }
6089 list.add(ci);
6090 maxNum--;
6091 top = null;
6092 }
6093 }
6094
6095 if (pending != null) {
6096 mPendingThumbnails.add(pending);
6097 }
6098 }
6099
6100 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6101
6102 if (topThumbnail != null) {
6103 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6104 try {
6105 topThumbnail.requestThumbnail(topRecord);
6106 } catch (Exception e) {
6107 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6108 sendPendingThumbnail(null, topRecord, null, null, true);
6109 }
6110 }
6111
6112 if (pending == null && receiver != null) {
6113 // In this case all thumbnails were available and the client
6114 // is being asked to be told when the remaining ones come in...
6115 // which is unusually, since the top-most currently running
6116 // activity should never have a canned thumbnail! Oh well.
6117 try {
6118 receiver.finished();
6119 } catch (RemoteException ex) {
6120 }
6121 }
6122
6123 return list;
6124 }
6125
6126 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6127 int flags) {
6128 synchronized (this) {
6129 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6130 "getRecentTasks()");
6131
6132 final int N = mRecentTasks.size();
6133 ArrayList<ActivityManager.RecentTaskInfo> res
6134 = new ArrayList<ActivityManager.RecentTaskInfo>(
6135 maxNum < N ? maxNum : N);
6136 for (int i=0; i<N && maxNum > 0; i++) {
6137 TaskRecord tr = mRecentTasks.get(i);
6138 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6139 || (tr.intent == null)
6140 || ((tr.intent.getFlags()
6141 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6142 ActivityManager.RecentTaskInfo rti
6143 = new ActivityManager.RecentTaskInfo();
6144 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6145 rti.baseIntent = new Intent(
6146 tr.intent != null ? tr.intent : tr.affinityIntent);
6147 rti.origActivity = tr.origActivity;
6148 res.add(rti);
6149 maxNum--;
6150 }
6151 }
6152 return res;
6153 }
6154 }
6155
6156 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6157 int j;
6158 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6159 TaskRecord jt = startTask;
6160
6161 // First look backwards
6162 for (j=startIndex-1; j>=0; j--) {
6163 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6164 if (r.task != jt) {
6165 jt = r.task;
6166 if (affinity.equals(jt.affinity)) {
6167 return j;
6168 }
6169 }
6170 }
6171
6172 // Now look forwards
6173 final int N = mHistory.size();
6174 jt = startTask;
6175 for (j=startIndex+1; j<N; j++) {
6176 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6177 if (r.task != jt) {
6178 if (affinity.equals(jt.affinity)) {
6179 return j;
6180 }
6181 jt = r.task;
6182 }
6183 }
6184
6185 // Might it be at the top?
6186 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6187 return N-1;
6188 }
6189
6190 return -1;
6191 }
6192
6193 /**
6194 * Perform a reset of the given task, if needed as part of launching it.
6195 * Returns the new HistoryRecord at the top of the task.
6196 */
6197 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6198 HistoryRecord newActivity) {
6199 boolean forceReset = (newActivity.info.flags
6200 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6201 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6202 if ((newActivity.info.flags
6203 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6204 forceReset = true;
6205 }
6206 }
6207
6208 final TaskRecord task = taskTop.task;
6209
6210 // We are going to move through the history list so that we can look
6211 // at each activity 'target' with 'below' either the interesting
6212 // activity immediately below it in the stack or null.
6213 HistoryRecord target = null;
6214 int targetI = 0;
6215 int taskTopI = -1;
6216 int replyChainEnd = -1;
6217 int lastReparentPos = -1;
6218 for (int i=mHistory.size()-1; i>=-1; i--) {
6219 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6220
6221 if (below != null && below.finishing) {
6222 continue;
6223 }
6224 if (target == null) {
6225 target = below;
6226 targetI = i;
6227 // If we were in the middle of a reply chain before this
6228 // task, it doesn't appear like the root of the chain wants
6229 // anything interesting, so drop it.
6230 replyChainEnd = -1;
6231 continue;
6232 }
6233
6234 final int flags = target.info.flags;
6235
6236 final boolean finishOnTaskLaunch =
6237 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6238 final boolean allowTaskReparenting =
6239 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6240
6241 if (target.task == task) {
6242 // We are inside of the task being reset... we'll either
6243 // finish this activity, push it out for another task,
6244 // or leave it as-is. We only do this
6245 // for activities that are not the root of the task (since
6246 // if we finish the root, we may no longer have the task!).
6247 if (taskTopI < 0) {
6248 taskTopI = targetI;
6249 }
6250 if (below != null && below.task == task) {
6251 final boolean clearWhenTaskReset =
6252 (target.intent.getFlags()
6253 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006254 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006255 // If this activity is sending a reply to a previous
6256 // activity, we can't do anything with it now until
6257 // we reach the start of the reply chain.
6258 // XXX note that we are assuming the result is always
6259 // to the previous activity, which is almost always
6260 // the case but we really shouldn't count on.
6261 if (replyChainEnd < 0) {
6262 replyChainEnd = targetI;
6263 }
Ed Heyl73798232009-03-24 21:32:21 -07006264 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006265 && target.taskAffinity != null
6266 && !target.taskAffinity.equals(task.affinity)) {
6267 // If this activity has an affinity for another
6268 // task, then we need to move it out of here. We will
6269 // move it as far out of the way as possible, to the
6270 // bottom of the activity stack. This also keeps it
6271 // correctly ordered with any activities we previously
6272 // moved.
6273 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6274 if (target.taskAffinity != null
6275 && target.taskAffinity.equals(p.task.affinity)) {
6276 // If the activity currently at the bottom has the
6277 // same task affinity as the one we are moving,
6278 // then merge it into the same task.
6279 target.task = p.task;
6280 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6281 + " out to bottom task " + p.task);
6282 } else {
6283 mCurTask++;
6284 if (mCurTask <= 0) {
6285 mCurTask = 1;
6286 }
6287 target.task = new TaskRecord(mCurTask, target.info, null,
6288 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6289 target.task.affinityIntent = target.intent;
6290 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6291 + " out to new task " + target.task);
6292 }
6293 mWindowManager.setAppGroupId(target, task.taskId);
6294 if (replyChainEnd < 0) {
6295 replyChainEnd = targetI;
6296 }
6297 int dstPos = 0;
6298 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6299 p = (HistoryRecord)mHistory.get(srcPos);
6300 if (p.finishing) {
6301 continue;
6302 }
6303 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6304 + " out to target's task " + target.task);
6305 task.numActivities--;
6306 p.task = target.task;
6307 target.task.numActivities++;
6308 mHistory.remove(srcPos);
6309 mHistory.add(dstPos, p);
6310 mWindowManager.moveAppToken(dstPos, p);
6311 mWindowManager.setAppGroupId(p, p.task.taskId);
6312 dstPos++;
6313 if (VALIDATE_TOKENS) {
6314 mWindowManager.validateAppTokens(mHistory);
6315 }
6316 i++;
6317 }
6318 if (taskTop == p) {
6319 taskTop = below;
6320 }
6321 if (taskTopI == replyChainEnd) {
6322 taskTopI = -1;
6323 }
6324 replyChainEnd = -1;
6325 addRecentTask(target.task);
6326 } else if (forceReset || finishOnTaskLaunch
6327 || clearWhenTaskReset) {
6328 // If the activity should just be removed -- either
6329 // because it asks for it, or the task should be
6330 // cleared -- then finish it and anything that is
6331 // part of its reply chain.
6332 if (clearWhenTaskReset) {
6333 // In this case, we want to finish this activity
6334 // and everything above it, so be sneaky and pretend
6335 // like these are all in the reply chain.
6336 replyChainEnd = targetI+1;
6337 while (replyChainEnd < mHistory.size() &&
6338 ((HistoryRecord)mHistory.get(
6339 replyChainEnd)).task == task) {
6340 replyChainEnd++;
6341 }
6342 replyChainEnd--;
6343 } else if (replyChainEnd < 0) {
6344 replyChainEnd = targetI;
6345 }
6346 HistoryRecord p = null;
6347 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6348 p = (HistoryRecord)mHistory.get(srcPos);
6349 if (p.finishing) {
6350 continue;
6351 }
6352 if (finishActivityLocked(p, srcPos,
6353 Activity.RESULT_CANCELED, null, "reset")) {
6354 replyChainEnd--;
6355 srcPos--;
6356 }
6357 }
6358 if (taskTop == p) {
6359 taskTop = below;
6360 }
6361 if (taskTopI == replyChainEnd) {
6362 taskTopI = -1;
6363 }
6364 replyChainEnd = -1;
6365 } else {
6366 // If we were in the middle of a chain, well the
6367 // activity that started it all doesn't want anything
6368 // special, so leave it all as-is.
6369 replyChainEnd = -1;
6370 }
6371 } else {
6372 // Reached the bottom of the task -- any reply chain
6373 // should be left as-is.
6374 replyChainEnd = -1;
6375 }
6376
6377 } else if (target.resultTo != null) {
6378 // If this activity is sending a reply to a previous
6379 // activity, we can't do anything with it now until
6380 // we reach the start of the reply chain.
6381 // XXX note that we are assuming the result is always
6382 // to the previous activity, which is almost always
6383 // the case but we really shouldn't count on.
6384 if (replyChainEnd < 0) {
6385 replyChainEnd = targetI;
6386 }
6387
6388 } else if (taskTopI >= 0 && allowTaskReparenting
6389 && task.affinity != null
6390 && task.affinity.equals(target.taskAffinity)) {
6391 // We are inside of another task... if this activity has
6392 // an affinity for our task, then either remove it if we are
6393 // clearing or move it over to our task. Note that
6394 // we currently punt on the case where we are resetting a
6395 // task that is not at the top but who has activities above
6396 // with an affinity to it... this is really not a normal
6397 // case, and we will need to later pull that task to the front
6398 // and usually at that point we will do the reset and pick
6399 // up those remaining activities. (This only happens if
6400 // someone starts an activity in a new task from an activity
6401 // in a task that is not currently on top.)
6402 if (forceReset || finishOnTaskLaunch) {
6403 if (replyChainEnd < 0) {
6404 replyChainEnd = targetI;
6405 }
6406 HistoryRecord p = null;
6407 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6408 p = (HistoryRecord)mHistory.get(srcPos);
6409 if (p.finishing) {
6410 continue;
6411 }
6412 if (finishActivityLocked(p, srcPos,
6413 Activity.RESULT_CANCELED, null, "reset")) {
6414 taskTopI--;
6415 lastReparentPos--;
6416 replyChainEnd--;
6417 srcPos--;
6418 }
6419 }
6420 replyChainEnd = -1;
6421 } else {
6422 if (replyChainEnd < 0) {
6423 replyChainEnd = targetI;
6424 }
6425 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6426 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6427 if (p.finishing) {
6428 continue;
6429 }
6430 if (lastReparentPos < 0) {
6431 lastReparentPos = taskTopI;
6432 taskTop = p;
6433 } else {
6434 lastReparentPos--;
6435 }
6436 mHistory.remove(srcPos);
6437 p.task.numActivities--;
6438 p.task = task;
6439 mHistory.add(lastReparentPos, p);
6440 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6441 + " in to resetting task " + task);
6442 task.numActivities++;
6443 mWindowManager.moveAppToken(lastReparentPos, p);
6444 mWindowManager.setAppGroupId(p, p.task.taskId);
6445 if (VALIDATE_TOKENS) {
6446 mWindowManager.validateAppTokens(mHistory);
6447 }
6448 }
6449 replyChainEnd = -1;
6450
6451 // Now we've moved it in to place... but what if this is
6452 // a singleTop activity and we have put it on top of another
6453 // instance of the same activity? Then we drop the instance
6454 // below so it remains singleTop.
6455 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6456 for (int j=lastReparentPos-1; j>=0; j--) {
6457 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6458 if (p.finishing) {
6459 continue;
6460 }
6461 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6462 if (finishActivityLocked(p, j,
6463 Activity.RESULT_CANCELED, null, "replace")) {
6464 taskTopI--;
6465 lastReparentPos--;
6466 }
6467 }
6468 }
6469 }
6470 }
6471 }
6472
6473 target = below;
6474 targetI = i;
6475 }
6476
6477 return taskTop;
6478 }
6479
6480 /**
6481 * TODO: Add mWatcher hook
6482 */
6483 public void moveTaskToFront(int task) {
6484 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6485 "moveTaskToFront()");
6486
6487 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006488 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6489 Binder.getCallingUid(), "Task to front")) {
6490 return;
6491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006492 final long origId = Binder.clearCallingIdentity();
6493 try {
6494 int N = mRecentTasks.size();
6495 for (int i=0; i<N; i++) {
6496 TaskRecord tr = mRecentTasks.get(i);
6497 if (tr.taskId == task) {
6498 moveTaskToFrontLocked(tr);
6499 return;
6500 }
6501 }
6502 for (int i=mHistory.size()-1; i>=0; i--) {
6503 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6504 if (hr.task.taskId == task) {
6505 moveTaskToFrontLocked(hr.task);
6506 return;
6507 }
6508 }
6509 } finally {
6510 Binder.restoreCallingIdentity(origId);
6511 }
6512 }
6513 }
6514
6515 private final void moveTaskToFrontLocked(TaskRecord tr) {
6516 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6517
6518 final int task = tr.taskId;
6519 int top = mHistory.size()-1;
6520
6521 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6522 // nothing to do!
6523 return;
6524 }
6525
6526 if (DEBUG_TRANSITION) Log.v(TAG,
6527 "Prepare to front transition: task=" + tr);
6528 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6529
6530 ArrayList moved = new ArrayList();
6531
6532 // Applying the affinities may have removed entries from the history,
6533 // so get the size again.
6534 top = mHistory.size()-1;
6535 int pos = top;
6536
6537 // Shift all activities with this task up to the top
6538 // of the stack, keeping them in the same internal order.
6539 while (pos >= 0) {
6540 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6541 if (localLOGV) Log.v(
6542 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6543 boolean first = true;
6544 if (r.task.taskId == task) {
6545 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6546 mHistory.remove(pos);
6547 mHistory.add(top, r);
6548 moved.add(0, r);
6549 top--;
6550 if (first) {
6551 addRecentTask(r.task);
6552 first = false;
6553 }
6554 }
6555 pos--;
6556 }
6557
6558 mWindowManager.moveAppTokensToTop(moved);
6559 if (VALIDATE_TOKENS) {
6560 mWindowManager.validateAppTokens(mHistory);
6561 }
6562
6563 finishTaskMove(task);
6564 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6565 }
6566
6567 private final void finishTaskMove(int task) {
6568 resumeTopActivityLocked(null);
6569 }
6570
6571 public void moveTaskToBack(int task) {
6572 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6573 "moveTaskToBack()");
6574
6575 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006576 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6577 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6578 Binder.getCallingUid(), "Task to back")) {
6579 return;
6580 }
6581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006582 final long origId = Binder.clearCallingIdentity();
6583 moveTaskToBackLocked(task);
6584 Binder.restoreCallingIdentity(origId);
6585 }
6586 }
6587
6588 /**
6589 * Moves an activity, and all of the other activities within the same task, to the bottom
6590 * of the history stack. The activity's order within the task is unchanged.
6591 *
6592 * @param token A reference to the activity we wish to move
6593 * @param nonRoot If false then this only works if the activity is the root
6594 * of a task; if true it will work for any activity in a task.
6595 * @return Returns true if the move completed, false if not.
6596 */
6597 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6598 synchronized(this) {
6599 final long origId = Binder.clearCallingIdentity();
6600 int taskId = getTaskForActivityLocked(token, !nonRoot);
6601 if (taskId >= 0) {
6602 return moveTaskToBackLocked(taskId);
6603 }
6604 Binder.restoreCallingIdentity(origId);
6605 }
6606 return false;
6607 }
6608
6609 /**
6610 * Worker method for rearranging history stack. Implements the function of moving all
6611 * activities for a specific task (gathering them if disjoint) into a single group at the
6612 * bottom of the stack.
6613 *
6614 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6615 * to premeptively cancel the move.
6616 *
6617 * @param task The taskId to collect and move to the bottom.
6618 * @return Returns true if the move completed, false if not.
6619 */
6620 private final boolean moveTaskToBackLocked(int task) {
6621 Log.i(TAG, "moveTaskToBack: " + task);
6622
6623 // If we have a watcher, preflight the move before committing to it. First check
6624 // for *other* available tasks, but if none are available, then try again allowing the
6625 // current task to be selected.
6626 if (mWatcher != null) {
6627 HistoryRecord next = topRunningActivityLocked(null, task);
6628 if (next == null) {
6629 next = topRunningActivityLocked(null, 0);
6630 }
6631 if (next != null) {
6632 // ask watcher if this is allowed
6633 boolean moveOK = true;
6634 try {
6635 moveOK = mWatcher.activityResuming(next.packageName);
6636 } catch (RemoteException e) {
6637 mWatcher = null;
6638 }
6639 if (!moveOK) {
6640 return false;
6641 }
6642 }
6643 }
6644
6645 ArrayList moved = new ArrayList();
6646
6647 if (DEBUG_TRANSITION) Log.v(TAG,
6648 "Prepare to back transition: task=" + task);
6649 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6650
6651 final int N = mHistory.size();
6652 int bottom = 0;
6653 int pos = 0;
6654
6655 // Shift all activities with this task down to the bottom
6656 // of the stack, keeping them in the same internal order.
6657 while (pos < N) {
6658 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6659 if (localLOGV) Log.v(
6660 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6661 if (r.task.taskId == task) {
6662 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6663 mHistory.remove(pos);
6664 mHistory.add(bottom, r);
6665 moved.add(r);
6666 bottom++;
6667 }
6668 pos++;
6669 }
6670
6671 mWindowManager.moveAppTokensToBottom(moved);
6672 if (VALIDATE_TOKENS) {
6673 mWindowManager.validateAppTokens(mHistory);
6674 }
6675
6676 finishTaskMove(task);
6677 return true;
6678 }
6679
6680 public void moveTaskBackwards(int task) {
6681 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6682 "moveTaskBackwards()");
6683
6684 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006685 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6686 Binder.getCallingUid(), "Task backwards")) {
6687 return;
6688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006689 final long origId = Binder.clearCallingIdentity();
6690 moveTaskBackwardsLocked(task);
6691 Binder.restoreCallingIdentity(origId);
6692 }
6693 }
6694
6695 private final void moveTaskBackwardsLocked(int task) {
6696 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6697 }
6698
6699 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6700 synchronized(this) {
6701 return getTaskForActivityLocked(token, onlyRoot);
6702 }
6703 }
6704
6705 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6706 final int N = mHistory.size();
6707 TaskRecord lastTask = null;
6708 for (int i=0; i<N; i++) {
6709 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6710 if (r == token) {
6711 if (!onlyRoot || lastTask != r.task) {
6712 return r.task.taskId;
6713 }
6714 return -1;
6715 }
6716 lastTask = r.task;
6717 }
6718
6719 return -1;
6720 }
6721
6722 /**
6723 * Returns the top activity in any existing task matching the given
6724 * Intent. Returns null if no such task is found.
6725 */
6726 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6727 ComponentName cls = intent.getComponent();
6728 if (info.targetActivity != null) {
6729 cls = new ComponentName(info.packageName, info.targetActivity);
6730 }
6731
6732 TaskRecord cp = null;
6733
6734 final int N = mHistory.size();
6735 for (int i=(N-1); i>=0; i--) {
6736 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6737 if (!r.finishing && r.task != cp
6738 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6739 cp = r.task;
6740 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6741 // + "/aff=" + r.task.affinity + " to new cls="
6742 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6743 if (r.task.affinity != null) {
6744 if (r.task.affinity.equals(info.taskAffinity)) {
6745 //Log.i(TAG, "Found matching affinity!");
6746 return r;
6747 }
6748 } else if (r.task.intent != null
6749 && r.task.intent.getComponent().equals(cls)) {
6750 //Log.i(TAG, "Found matching class!");
6751 //dump();
6752 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6753 return r;
6754 } else if (r.task.affinityIntent != null
6755 && r.task.affinityIntent.getComponent().equals(cls)) {
6756 //Log.i(TAG, "Found matching class!");
6757 //dump();
6758 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6759 return r;
6760 }
6761 }
6762 }
6763
6764 return null;
6765 }
6766
6767 /**
6768 * Returns the first activity (starting from the top of the stack) that
6769 * is the same as the given activity. Returns null if no such activity
6770 * is found.
6771 */
6772 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6773 ComponentName cls = intent.getComponent();
6774 if (info.targetActivity != null) {
6775 cls = new ComponentName(info.packageName, info.targetActivity);
6776 }
6777
6778 final int N = mHistory.size();
6779 for (int i=(N-1); i>=0; i--) {
6780 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6781 if (!r.finishing) {
6782 if (r.intent.getComponent().equals(cls)) {
6783 //Log.i(TAG, "Found matching class!");
6784 //dump();
6785 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6786 return r;
6787 }
6788 }
6789 }
6790
6791 return null;
6792 }
6793
6794 public void finishOtherInstances(IBinder token, ComponentName className) {
6795 synchronized(this) {
6796 final long origId = Binder.clearCallingIdentity();
6797
6798 int N = mHistory.size();
6799 TaskRecord lastTask = null;
6800 for (int i=0; i<N; i++) {
6801 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6802 if (r.realActivity.equals(className)
6803 && r != token && lastTask != r.task) {
6804 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6805 null, "others")) {
6806 i--;
6807 N--;
6808 }
6809 }
6810 lastTask = r.task;
6811 }
6812
6813 Binder.restoreCallingIdentity(origId);
6814 }
6815 }
6816
6817 // =========================================================
6818 // THUMBNAILS
6819 // =========================================================
6820
6821 public void reportThumbnail(IBinder token,
6822 Bitmap thumbnail, CharSequence description) {
6823 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6824 final long origId = Binder.clearCallingIdentity();
6825 sendPendingThumbnail(null, token, thumbnail, description, true);
6826 Binder.restoreCallingIdentity(origId);
6827 }
6828
6829 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6830 Bitmap thumbnail, CharSequence description, boolean always) {
6831 TaskRecord task = null;
6832 ArrayList receivers = null;
6833
6834 //System.out.println("Send pending thumbnail: " + r);
6835
6836 synchronized(this) {
6837 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006838 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006839 if (index < 0) {
6840 return;
6841 }
6842 r = (HistoryRecord)mHistory.get(index);
6843 }
6844 if (thumbnail == null) {
6845 thumbnail = r.thumbnail;
6846 description = r.description;
6847 }
6848 if (thumbnail == null && !always) {
6849 // If there is no thumbnail, and this entry is not actually
6850 // going away, then abort for now and pick up the next
6851 // thumbnail we get.
6852 return;
6853 }
6854 task = r.task;
6855
6856 int N = mPendingThumbnails.size();
6857 int i=0;
6858 while (i<N) {
6859 PendingThumbnailsRecord pr =
6860 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
6861 //System.out.println("Looking in " + pr.pendingRecords);
6862 if (pr.pendingRecords.remove(r)) {
6863 if (receivers == null) {
6864 receivers = new ArrayList();
6865 }
6866 receivers.add(pr);
6867 if (pr.pendingRecords.size() == 0) {
6868 pr.finished = true;
6869 mPendingThumbnails.remove(i);
6870 N--;
6871 continue;
6872 }
6873 }
6874 i++;
6875 }
6876 }
6877
6878 if (receivers != null) {
6879 final int N = receivers.size();
6880 for (int i=0; i<N; i++) {
6881 try {
6882 PendingThumbnailsRecord pr =
6883 (PendingThumbnailsRecord)receivers.get(i);
6884 pr.receiver.newThumbnail(
6885 task != null ? task.taskId : -1, thumbnail, description);
6886 if (pr.finished) {
6887 pr.receiver.finished();
6888 }
6889 } catch (Exception e) {
6890 Log.w(TAG, "Exception thrown when sending thumbnail", e);
6891 }
6892 }
6893 }
6894 }
6895
6896 // =========================================================
6897 // CONTENT PROVIDERS
6898 // =========================================================
6899
6900 private final List generateApplicationProvidersLocked(ProcessRecord app) {
6901 List providers = null;
6902 try {
6903 providers = ActivityThread.getPackageManager().
6904 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07006905 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006906 } catch (RemoteException ex) {
6907 }
6908 if (providers != null) {
6909 final int N = providers.size();
6910 for (int i=0; i<N; i++) {
6911 ProviderInfo cpi =
6912 (ProviderInfo)providers.get(i);
6913 ContentProviderRecord cpr =
6914 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
6915 if (cpr == null) {
6916 cpr = new ContentProviderRecord(cpi, app.info);
6917 mProvidersByClass.put(cpi.name, cpr);
6918 }
6919 app.pubProviders.put(cpi.name, cpr);
6920 app.addPackage(cpi.applicationInfo.packageName);
6921 }
6922 }
6923 return providers;
6924 }
6925
6926 private final String checkContentProviderPermissionLocked(
6927 ProviderInfo cpi, ProcessRecord r, int mode) {
6928 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
6929 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
6930 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
6931 cpi.exported ? -1 : cpi.applicationInfo.uid)
6932 == PackageManager.PERMISSION_GRANTED
6933 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
6934 return null;
6935 }
6936 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
6937 cpi.exported ? -1 : cpi.applicationInfo.uid)
6938 == PackageManager.PERMISSION_GRANTED) {
6939 return null;
6940 }
6941 String msg = "Permission Denial: opening provider " + cpi.name
6942 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
6943 + ", uid=" + callingUid + ") requires "
6944 + cpi.readPermission + " or " + cpi.writePermission;
6945 Log.w(TAG, msg);
6946 return msg;
6947 }
6948
6949 private final ContentProviderHolder getContentProviderImpl(
6950 IApplicationThread caller, String name) {
6951 ContentProviderRecord cpr;
6952 ProviderInfo cpi = null;
6953
6954 synchronized(this) {
6955 ProcessRecord r = null;
6956 if (caller != null) {
6957 r = getRecordForAppLocked(caller);
6958 if (r == null) {
6959 throw new SecurityException(
6960 "Unable to find app for caller " + caller
6961 + " (pid=" + Binder.getCallingPid()
6962 + ") when getting content provider " + name);
6963 }
6964 }
6965
6966 // First check if this content provider has been published...
6967 cpr = (ContentProviderRecord)mProvidersByName.get(name);
6968 if (cpr != null) {
6969 cpi = cpr.info;
6970 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
6971 return new ContentProviderHolder(cpi,
6972 cpi.readPermission != null
6973 ? cpi.readPermission : cpi.writePermission);
6974 }
6975
6976 if (r != null && cpr.canRunHere(r)) {
6977 // This provider has been published or is in the process
6978 // of being published... but it is also allowed to run
6979 // in the caller's process, so don't make a connection
6980 // and just let the caller instantiate its own instance.
6981 if (cpr.provider != null) {
6982 // don't give caller the provider object, it needs
6983 // to make its own.
6984 cpr = new ContentProviderRecord(cpr);
6985 }
6986 return cpr;
6987 }
6988
6989 final long origId = Binder.clearCallingIdentity();
6990
6991 // In this case the provider is a single instance, so we can
6992 // return it right away.
6993 if (r != null) {
6994 r.conProviders.add(cpr);
6995 cpr.clients.add(r);
6996 } else {
6997 cpr.externals++;
6998 }
6999
7000 if (cpr.app != null) {
7001 updateOomAdjLocked(cpr.app);
7002 }
7003
7004 Binder.restoreCallingIdentity(origId);
7005
7006 } else {
7007 try {
7008 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007009 resolveContentProvider(name,
7010 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007011 } catch (RemoteException ex) {
7012 }
7013 if (cpi == null) {
7014 return null;
7015 }
7016
7017 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7018 return new ContentProviderHolder(cpi,
7019 cpi.readPermission != null
7020 ? cpi.readPermission : cpi.writePermission);
7021 }
7022
7023 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7024 final boolean firstClass = cpr == null;
7025 if (firstClass) {
7026 try {
7027 ApplicationInfo ai =
7028 ActivityThread.getPackageManager().
7029 getApplicationInfo(
7030 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007031 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007032 if (ai == null) {
7033 Log.w(TAG, "No package info for content provider "
7034 + cpi.name);
7035 return null;
7036 }
7037 cpr = new ContentProviderRecord(cpi, ai);
7038 } catch (RemoteException ex) {
7039 // pm is in same process, this will never happen.
7040 }
7041 }
7042
7043 if (r != null && cpr.canRunHere(r)) {
7044 // If this is a multiprocess provider, then just return its
7045 // info and allow the caller to instantiate it. Only do
7046 // this if the provider is the same user as the caller's
7047 // process, or can run as root (so can be in any process).
7048 return cpr;
7049 }
7050
7051 if (false) {
7052 RuntimeException e = new RuntimeException("foo");
7053 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7054 // + " pruid " + ai.uid + "): " + cpi.className, e);
7055 }
7056
7057 // This is single process, and our app is now connecting to it.
7058 // See if we are already in the process of launching this
7059 // provider.
7060 final int N = mLaunchingProviders.size();
7061 int i;
7062 for (i=0; i<N; i++) {
7063 if (mLaunchingProviders.get(i) == cpr) {
7064 break;
7065 }
7066 if (false) {
7067 final ContentProviderRecord rec =
7068 (ContentProviderRecord)mLaunchingProviders.get(i);
7069 if (rec.info.name.equals(cpr.info.name)) {
7070 cpr = rec;
7071 break;
7072 }
7073 }
7074 }
7075
7076 // If the provider is not already being launched, then get it
7077 // started.
7078 if (i >= N) {
7079 final long origId = Binder.clearCallingIdentity();
7080 ProcessRecord proc = startProcessLocked(cpi.processName,
7081 cpr.appInfo, false, 0, "content provider",
7082 new ComponentName(cpi.applicationInfo.packageName,
7083 cpi.name));
7084 if (proc == null) {
7085 Log.w(TAG, "Unable to launch app "
7086 + cpi.applicationInfo.packageName + "/"
7087 + cpi.applicationInfo.uid + " for provider "
7088 + name + ": process is bad");
7089 return null;
7090 }
7091 cpr.launchingApp = proc;
7092 mLaunchingProviders.add(cpr);
7093 Binder.restoreCallingIdentity(origId);
7094 }
7095
7096 // Make sure the provider is published (the same provider class
7097 // may be published under multiple names).
7098 if (firstClass) {
7099 mProvidersByClass.put(cpi.name, cpr);
7100 }
7101 mProvidersByName.put(name, cpr);
7102
7103 if (r != null) {
7104 r.conProviders.add(cpr);
7105 cpr.clients.add(r);
7106 } else {
7107 cpr.externals++;
7108 }
7109 }
7110 }
7111
7112 // Wait for the provider to be published...
7113 synchronized (cpr) {
7114 while (cpr.provider == null) {
7115 if (cpr.launchingApp == null) {
7116 Log.w(TAG, "Unable to launch app "
7117 + cpi.applicationInfo.packageName + "/"
7118 + cpi.applicationInfo.uid + " for provider "
7119 + name + ": launching app became null");
7120 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7121 cpi.applicationInfo.packageName,
7122 cpi.applicationInfo.uid, name);
7123 return null;
7124 }
7125 try {
7126 cpr.wait();
7127 } catch (InterruptedException ex) {
7128 }
7129 }
7130 }
7131 return cpr;
7132 }
7133
7134 public final ContentProviderHolder getContentProvider(
7135 IApplicationThread caller, String name) {
7136 if (caller == null) {
7137 String msg = "null IApplicationThread when getting content provider "
7138 + name;
7139 Log.w(TAG, msg);
7140 throw new SecurityException(msg);
7141 }
7142
7143 return getContentProviderImpl(caller, name);
7144 }
7145
7146 private ContentProviderHolder getContentProviderExternal(String name) {
7147 return getContentProviderImpl(null, name);
7148 }
7149
7150 /**
7151 * Drop a content provider from a ProcessRecord's bookkeeping
7152 * @param cpr
7153 */
7154 public void removeContentProvider(IApplicationThread caller, String name) {
7155 synchronized (this) {
7156 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7157 if(cpr == null) {
7158 //remove from mProvidersByClass
7159 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7160 return;
7161 }
7162 final ProcessRecord r = getRecordForAppLocked(caller);
7163 if (r == null) {
7164 throw new SecurityException(
7165 "Unable to find app for caller " + caller +
7166 " when removing content provider " + name);
7167 }
7168 //update content provider record entry info
7169 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7170 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7171 r.info.processName+" from process "+localCpr.appInfo.processName);
7172 if(localCpr.appInfo.processName == r.info.processName) {
7173 //should not happen. taken care of as a local provider
7174 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7175 return;
7176 } else {
7177 localCpr.clients.remove(r);
7178 r.conProviders.remove(localCpr);
7179 }
7180 updateOomAdjLocked();
7181 }
7182 }
7183
7184 private void removeContentProviderExternal(String name) {
7185 synchronized (this) {
7186 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7187 if(cpr == null) {
7188 //remove from mProvidersByClass
7189 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7190 return;
7191 }
7192
7193 //update content provider record entry info
7194 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7195 localCpr.externals--;
7196 if (localCpr.externals < 0) {
7197 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7198 }
7199 updateOomAdjLocked();
7200 }
7201 }
7202
7203 public final void publishContentProviders(IApplicationThread caller,
7204 List<ContentProviderHolder> providers) {
7205 if (providers == null) {
7206 return;
7207 }
7208
7209 synchronized(this) {
7210 final ProcessRecord r = getRecordForAppLocked(caller);
7211 if (r == null) {
7212 throw new SecurityException(
7213 "Unable to find app for caller " + caller
7214 + " (pid=" + Binder.getCallingPid()
7215 + ") when publishing content providers");
7216 }
7217
7218 final long origId = Binder.clearCallingIdentity();
7219
7220 final int N = providers.size();
7221 for (int i=0; i<N; i++) {
7222 ContentProviderHolder src = providers.get(i);
7223 if (src == null || src.info == null || src.provider == null) {
7224 continue;
7225 }
7226 ContentProviderRecord dst =
7227 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7228 if (dst != null) {
7229 mProvidersByClass.put(dst.info.name, dst);
7230 String names[] = dst.info.authority.split(";");
7231 for (int j = 0; j < names.length; j++) {
7232 mProvidersByName.put(names[j], dst);
7233 }
7234
7235 int NL = mLaunchingProviders.size();
7236 int j;
7237 for (j=0; j<NL; j++) {
7238 if (mLaunchingProviders.get(j) == dst) {
7239 mLaunchingProviders.remove(j);
7240 j--;
7241 NL--;
7242 }
7243 }
7244 synchronized (dst) {
7245 dst.provider = src.provider;
7246 dst.app = r;
7247 dst.notifyAll();
7248 }
7249 updateOomAdjLocked(r);
7250 }
7251 }
7252
7253 Binder.restoreCallingIdentity(origId);
7254 }
7255 }
7256
7257 public static final void installSystemProviders() {
7258 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7259 List providers = mSelf.generateApplicationProvidersLocked(app);
7260 mSystemThread.installSystemProviders(providers);
7261 }
7262
7263 // =========================================================
7264 // GLOBAL MANAGEMENT
7265 // =========================================================
7266
7267 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7268 ApplicationInfo info, String customProcess) {
7269 String proc = customProcess != null ? customProcess : info.processName;
7270 BatteryStatsImpl.Uid.Proc ps = null;
7271 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7272 synchronized (stats) {
7273 ps = stats.getProcessStatsLocked(info.uid, proc);
7274 }
7275 return new ProcessRecord(ps, thread, info, proc);
7276 }
7277
7278 final ProcessRecord addAppLocked(ApplicationInfo info) {
7279 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7280
7281 if (app == null) {
7282 app = newProcessRecordLocked(null, info, null);
7283 mProcessNames.put(info.processName, info.uid, app);
7284 updateLRUListLocked(app, true);
7285 }
7286
7287 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7288 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7289 app.persistent = true;
7290 app.maxAdj = CORE_SERVER_ADJ;
7291 }
7292 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7293 mPersistentStartingProcesses.add(app);
7294 startProcessLocked(app, "added application", app.processName);
7295 }
7296
7297 return app;
7298 }
7299
7300 public void unhandledBack() {
7301 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7302 "unhandledBack()");
7303
7304 synchronized(this) {
7305 int count = mHistory.size();
7306 if (Config.LOGD) Log.d(
7307 TAG, "Performing unhandledBack(): stack size = " + count);
7308 if (count > 1) {
7309 final long origId = Binder.clearCallingIdentity();
7310 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7311 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7312 Binder.restoreCallingIdentity(origId);
7313 }
7314 }
7315 }
7316
7317 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7318 String name = uri.getAuthority();
7319 ContentProviderHolder cph = getContentProviderExternal(name);
7320 ParcelFileDescriptor pfd = null;
7321 if (cph != null) {
7322 // We record the binder invoker's uid in thread-local storage before
7323 // going to the content provider to open the file. Later, in the code
7324 // that handles all permissions checks, we look for this uid and use
7325 // that rather than the Activity Manager's own uid. The effect is that
7326 // we do the check against the caller's permissions even though it looks
7327 // to the content provider like the Activity Manager itself is making
7328 // the request.
7329 sCallerIdentity.set(new Identity(
7330 Binder.getCallingPid(), Binder.getCallingUid()));
7331 try {
7332 pfd = cph.provider.openFile(uri, "r");
7333 } catch (FileNotFoundException e) {
7334 // do nothing; pfd will be returned null
7335 } finally {
7336 // Ensure that whatever happens, we clean up the identity state
7337 sCallerIdentity.remove();
7338 }
7339
7340 // We've got the fd now, so we're done with the provider.
7341 removeContentProviderExternal(name);
7342 } else {
7343 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7344 }
7345 return pfd;
7346 }
7347
7348 public void goingToSleep() {
7349 synchronized(this) {
7350 mSleeping = true;
7351 mWindowManager.setEventDispatching(false);
7352
7353 if (mResumedActivity != null) {
7354 pauseIfSleepingLocked();
7355 } else {
7356 Log.w(TAG, "goingToSleep with no resumed activity!");
7357 }
7358 }
7359 }
7360
Dianne Hackborn55280a92009-05-07 15:53:46 -07007361 public boolean shutdown(int timeout) {
7362 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7363 != PackageManager.PERMISSION_GRANTED) {
7364 throw new SecurityException("Requires permission "
7365 + android.Manifest.permission.SHUTDOWN);
7366 }
7367
7368 boolean timedout = false;
7369
7370 synchronized(this) {
7371 mShuttingDown = true;
7372 mWindowManager.setEventDispatching(false);
7373
7374 if (mResumedActivity != null) {
7375 pauseIfSleepingLocked();
7376 final long endTime = System.currentTimeMillis() + timeout;
7377 while (mResumedActivity != null || mPausingActivity != null) {
7378 long delay = endTime - System.currentTimeMillis();
7379 if (delay <= 0) {
7380 Log.w(TAG, "Activity manager shutdown timed out");
7381 timedout = true;
7382 break;
7383 }
7384 try {
7385 this.wait();
7386 } catch (InterruptedException e) {
7387 }
7388 }
7389 }
7390 }
7391
7392 mUsageStatsService.shutdown();
7393 mBatteryStatsService.shutdown();
7394
7395 return timedout;
7396 }
7397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007398 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007399 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007400 if (!mGoingToSleep.isHeld()) {
7401 mGoingToSleep.acquire();
7402 if (mLaunchingActivity.isHeld()) {
7403 mLaunchingActivity.release();
7404 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7405 }
7406 }
7407
7408 // If we are not currently pausing an activity, get the current
7409 // one to pause. If we are pausing one, we will just let that stuff
7410 // run and release the wake lock when all done.
7411 if (mPausingActivity == null) {
7412 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7413 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7414 startPausingLocked(false, true);
7415 }
7416 }
7417 }
7418
7419 public void wakingUp() {
7420 synchronized(this) {
7421 if (mGoingToSleep.isHeld()) {
7422 mGoingToSleep.release();
7423 }
7424 mWindowManager.setEventDispatching(true);
7425 mSleeping = false;
7426 resumeTopActivityLocked(null);
7427 }
7428 }
7429
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007430 public void stopAppSwitches() {
7431 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7432 != PackageManager.PERMISSION_GRANTED) {
7433 throw new SecurityException("Requires permission "
7434 + android.Manifest.permission.STOP_APP_SWITCHES);
7435 }
7436
7437 synchronized(this) {
7438 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7439 + APP_SWITCH_DELAY_TIME;
7440 mDidAppSwitch = false;
7441 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7442 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7443 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7444 }
7445 }
7446
7447 public void resumeAppSwitches() {
7448 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7449 != PackageManager.PERMISSION_GRANTED) {
7450 throw new SecurityException("Requires permission "
7451 + android.Manifest.permission.STOP_APP_SWITCHES);
7452 }
7453
7454 synchronized(this) {
7455 // Note that we don't execute any pending app switches... we will
7456 // let those wait until either the timeout, or the next start
7457 // activity request.
7458 mAppSwitchesAllowedTime = 0;
7459 }
7460 }
7461
7462 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7463 String name) {
7464 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7465 return true;
7466 }
7467
7468 final int perm = checkComponentPermission(
7469 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7470 callingUid, -1);
7471 if (perm == PackageManager.PERMISSION_GRANTED) {
7472 return true;
7473 }
7474
7475 Log.w(TAG, name + " request from " + callingUid + " stopped");
7476 return false;
7477 }
7478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007479 public void setDebugApp(String packageName, boolean waitForDebugger,
7480 boolean persistent) {
7481 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7482 "setDebugApp()");
7483
7484 // Note that this is not really thread safe if there are multiple
7485 // callers into it at the same time, but that's not a situation we
7486 // care about.
7487 if (persistent) {
7488 final ContentResolver resolver = mContext.getContentResolver();
7489 Settings.System.putString(
7490 resolver, Settings.System.DEBUG_APP,
7491 packageName);
7492 Settings.System.putInt(
7493 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7494 waitForDebugger ? 1 : 0);
7495 }
7496
7497 synchronized (this) {
7498 if (!persistent) {
7499 mOrigDebugApp = mDebugApp;
7500 mOrigWaitForDebugger = mWaitForDebugger;
7501 }
7502 mDebugApp = packageName;
7503 mWaitForDebugger = waitForDebugger;
7504 mDebugTransient = !persistent;
7505 if (packageName != null) {
7506 final long origId = Binder.clearCallingIdentity();
7507 uninstallPackageLocked(packageName, -1, false);
7508 Binder.restoreCallingIdentity(origId);
7509 }
7510 }
7511 }
7512
7513 public void setAlwaysFinish(boolean enabled) {
7514 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7515 "setAlwaysFinish()");
7516
7517 Settings.System.putInt(
7518 mContext.getContentResolver(),
7519 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7520
7521 synchronized (this) {
7522 mAlwaysFinishActivities = enabled;
7523 }
7524 }
7525
7526 public void setActivityWatcher(IActivityWatcher watcher) {
7527 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
7528 "setActivityWatcher()");
7529 synchronized (this) {
7530 mWatcher = watcher;
7531 }
7532 }
7533
7534 public final void enterSafeMode() {
7535 synchronized(this) {
7536 // It only makes sense to do this before the system is ready
7537 // and started launching other packages.
7538 if (!mSystemReady) {
7539 try {
7540 ActivityThread.getPackageManager().enterSafeMode();
7541 } catch (RemoteException e) {
7542 }
7543
7544 View v = LayoutInflater.from(mContext).inflate(
7545 com.android.internal.R.layout.safe_mode, null);
7546 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7547 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7548 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7549 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7550 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7551 lp.format = v.getBackground().getOpacity();
7552 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7553 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7554 ((WindowManager)mContext.getSystemService(
7555 Context.WINDOW_SERVICE)).addView(v, lp);
7556 }
7557 }
7558 }
7559
7560 public void noteWakeupAlarm(IIntentSender sender) {
7561 if (!(sender instanceof PendingIntentRecord)) {
7562 return;
7563 }
7564 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7565 synchronized (stats) {
7566 if (mBatteryStatsService.isOnBattery()) {
7567 mBatteryStatsService.enforceCallingPermission();
7568 PendingIntentRecord rec = (PendingIntentRecord)sender;
7569 int MY_UID = Binder.getCallingUid();
7570 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7571 BatteryStatsImpl.Uid.Pkg pkg =
7572 stats.getPackageStatsLocked(uid, rec.key.packageName);
7573 pkg.incWakeupsLocked();
7574 }
7575 }
7576 }
7577
7578 public boolean killPidsForMemory(int[] pids) {
7579 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7580 throw new SecurityException("killPidsForMemory only available to the system");
7581 }
7582
7583 // XXX Note: don't acquire main activity lock here, because the window
7584 // manager calls in with its locks held.
7585
7586 boolean killed = false;
7587 synchronized (mPidsSelfLocked) {
7588 int[] types = new int[pids.length];
7589 int worstType = 0;
7590 for (int i=0; i<pids.length; i++) {
7591 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7592 if (proc != null) {
7593 int type = proc.setAdj;
7594 types[i] = type;
7595 if (type > worstType) {
7596 worstType = type;
7597 }
7598 }
7599 }
7600
7601 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7602 // then constrain it so we will kill all hidden procs.
7603 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7604 worstType = HIDDEN_APP_MIN_ADJ;
7605 }
7606 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7607 for (int i=0; i<pids.length; i++) {
7608 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7609 if (proc == null) {
7610 continue;
7611 }
7612 int adj = proc.setAdj;
7613 if (adj >= worstType) {
7614 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7615 + adj + ")");
7616 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7617 proc.processName, adj);
7618 killed = true;
7619 Process.killProcess(pids[i]);
7620 }
7621 }
7622 }
7623 return killed;
7624 }
7625
7626 public void reportPss(IApplicationThread caller, int pss) {
7627 Watchdog.PssRequestor req;
7628 String name;
7629 ProcessRecord callerApp;
7630 synchronized (this) {
7631 if (caller == null) {
7632 return;
7633 }
7634 callerApp = getRecordForAppLocked(caller);
7635 if (callerApp == null) {
7636 return;
7637 }
7638 callerApp.lastPss = pss;
7639 req = callerApp;
7640 name = callerApp.processName;
7641 }
7642 Watchdog.getInstance().reportPss(req, name, pss);
7643 if (!callerApp.persistent) {
7644 removeRequestedPss(callerApp);
7645 }
7646 }
7647
7648 public void requestPss(Runnable completeCallback) {
7649 ArrayList<ProcessRecord> procs;
7650 synchronized (this) {
7651 mRequestPssCallback = completeCallback;
7652 mRequestPssList.clear();
7653 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7654 ProcessRecord proc = mLRUProcesses.get(i);
7655 if (!proc.persistent) {
7656 mRequestPssList.add(proc);
7657 }
7658 }
7659 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7660 }
7661
7662 int oldPri = Process.getThreadPriority(Process.myTid());
7663 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7664 for (int i=procs.size()-1; i>=0; i--) {
7665 ProcessRecord proc = procs.get(i);
7666 proc.lastPss = 0;
7667 proc.requestPss();
7668 }
7669 Process.setThreadPriority(oldPri);
7670 }
7671
7672 void removeRequestedPss(ProcessRecord proc) {
7673 Runnable callback = null;
7674 synchronized (this) {
7675 if (mRequestPssList.remove(proc)) {
7676 if (mRequestPssList.size() == 0) {
7677 callback = mRequestPssCallback;
7678 mRequestPssCallback = null;
7679 }
7680 }
7681 }
7682
7683 if (callback != null) {
7684 callback.run();
7685 }
7686 }
7687
7688 public void collectPss(Watchdog.PssStats stats) {
7689 stats.mEmptyPss = 0;
7690 stats.mEmptyCount = 0;
7691 stats.mBackgroundPss = 0;
7692 stats.mBackgroundCount = 0;
7693 stats.mServicePss = 0;
7694 stats.mServiceCount = 0;
7695 stats.mVisiblePss = 0;
7696 stats.mVisibleCount = 0;
7697 stats.mForegroundPss = 0;
7698 stats.mForegroundCount = 0;
7699 stats.mNoPssCount = 0;
7700 synchronized (this) {
7701 int i;
7702 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7703 ? mProcDeaths.length : stats.mProcDeaths.length;
7704 int aggr = 0;
7705 for (i=0; i<NPD; i++) {
7706 aggr += mProcDeaths[i];
7707 stats.mProcDeaths[i] = aggr;
7708 }
7709 while (i<stats.mProcDeaths.length) {
7710 stats.mProcDeaths[i] = 0;
7711 i++;
7712 }
7713
7714 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7715 ProcessRecord proc = mLRUProcesses.get(i);
7716 if (proc.persistent) {
7717 continue;
7718 }
7719 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7720 if (proc.lastPss == 0) {
7721 stats.mNoPssCount++;
7722 continue;
7723 }
7724 if (proc.setAdj == EMPTY_APP_ADJ) {
7725 stats.mEmptyPss += proc.lastPss;
7726 stats.mEmptyCount++;
7727 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7728 stats.mEmptyPss += proc.lastPss;
7729 stats.mEmptyCount++;
7730 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7731 stats.mBackgroundPss += proc.lastPss;
7732 stats.mBackgroundCount++;
7733 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7734 stats.mVisiblePss += proc.lastPss;
7735 stats.mVisibleCount++;
7736 } else {
7737 stats.mForegroundPss += proc.lastPss;
7738 stats.mForegroundCount++;
7739 }
7740 }
7741 }
7742 }
7743
7744 public final void startRunning(String pkg, String cls, String action,
7745 String data) {
7746 synchronized(this) {
7747 if (mStartRunning) {
7748 return;
7749 }
7750 mStartRunning = true;
7751 mTopComponent = pkg != null && cls != null
7752 ? new ComponentName(pkg, cls) : null;
7753 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7754 mTopData = data;
7755 if (!mSystemReady) {
7756 return;
7757 }
7758 }
7759
7760 systemReady();
7761 }
7762
7763 private void retrieveSettings() {
7764 final ContentResolver resolver = mContext.getContentResolver();
7765 String debugApp = Settings.System.getString(
7766 resolver, Settings.System.DEBUG_APP);
7767 boolean waitForDebugger = Settings.System.getInt(
7768 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7769 boolean alwaysFinishActivities = Settings.System.getInt(
7770 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7771
7772 Configuration configuration = new Configuration();
7773 Settings.System.getConfiguration(resolver, configuration);
7774
7775 synchronized (this) {
7776 mDebugApp = mOrigDebugApp = debugApp;
7777 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7778 mAlwaysFinishActivities = alwaysFinishActivities;
7779 // This happens before any activities are started, so we can
7780 // change mConfiguration in-place.
7781 mConfiguration.updateFrom(configuration);
7782 }
7783 }
7784
7785 public boolean testIsSystemReady() {
7786 // no need to synchronize(this) just to read & return the value
7787 return mSystemReady;
7788 }
7789
7790 public void systemReady() {
7791 // In the simulator, startRunning will never have been called, which
7792 // normally sets a few crucial variables. Do it here instead.
7793 if (!Process.supportsProcesses()) {
7794 mStartRunning = true;
7795 mTopAction = Intent.ACTION_MAIN;
7796 }
7797
7798 synchronized(this) {
7799 if (mSystemReady) {
7800 return;
7801 }
7802 mSystemReady = true;
7803 if (!mStartRunning) {
7804 return;
7805 }
7806 }
7807
7808 if (Config.LOGD) Log.d(TAG, "Start running!");
7809 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
7810 SystemClock.uptimeMillis());
7811
7812 synchronized(this) {
7813 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
7814 ResolveInfo ri = mContext.getPackageManager()
7815 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07007816 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007817 CharSequence errorMsg = null;
7818 if (ri != null) {
7819 ActivityInfo ai = ri.activityInfo;
7820 ApplicationInfo app = ai.applicationInfo;
7821 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
7822 mTopAction = Intent.ACTION_FACTORY_TEST;
7823 mTopData = null;
7824 mTopComponent = new ComponentName(app.packageName,
7825 ai.name);
7826 } else {
7827 errorMsg = mContext.getResources().getText(
7828 com.android.internal.R.string.factorytest_not_system);
7829 }
7830 } else {
7831 errorMsg = mContext.getResources().getText(
7832 com.android.internal.R.string.factorytest_no_action);
7833 }
7834 if (errorMsg != null) {
7835 mTopAction = null;
7836 mTopData = null;
7837 mTopComponent = null;
7838 Message msg = Message.obtain();
7839 msg.what = SHOW_FACTORY_ERROR_MSG;
7840 msg.getData().putCharSequence("msg", errorMsg);
7841 mHandler.sendMessage(msg);
7842 }
7843 }
7844 }
7845
7846 retrieveSettings();
7847
7848 synchronized (this) {
7849 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
7850 try {
7851 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007852 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007853 if (apps != null) {
7854 int N = apps.size();
7855 int i;
7856 for (i=0; i<N; i++) {
7857 ApplicationInfo info
7858 = (ApplicationInfo)apps.get(i);
7859 if (info != null &&
7860 !info.packageName.equals("android")) {
7861 addAppLocked(info);
7862 }
7863 }
7864 }
7865 } catch (RemoteException ex) {
7866 // pm is in same process, this will never happen.
7867 }
7868 }
7869
7870 try {
7871 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
7872 Message msg = Message.obtain();
7873 msg.what = SHOW_UID_ERROR_MSG;
7874 mHandler.sendMessage(msg);
7875 }
7876 } catch (RemoteException e) {
7877 }
7878
7879 // Start up initial activity.
7880 mBooting = true;
7881 resumeTopActivityLocked(null);
7882 }
7883 }
7884
7885 boolean makeAppCrashingLocked(ProcessRecord app,
7886 String tag, String shortMsg, String longMsg, byte[] crashData) {
7887 app.crashing = true;
7888 app.crashingReport = generateProcessError(app,
7889 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
7890 startAppProblemLocked(app);
7891 app.stopFreezingAllLocked();
7892 return handleAppCrashLocked(app);
7893 }
7894
Jacek Surazskif5b9c722009-05-18 12:09:59 +02007895 private ComponentName getErrorReportReceiver(ProcessRecord app) {
7896 IPackageManager pm = ActivityThread.getPackageManager();
7897 try {
7898 // was an installer package name specified when this app was
7899 // installed?
7900 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
7901 if (installerPackageName == null) {
7902 return null;
7903 }
7904
7905 // is there an Activity in this package that handles ACTION_APP_ERROR?
7906 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
7907 ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName);
7908 if (info == null || info.activityInfo == null) {
7909 return null;
7910 }
7911
7912 return new ComponentName(installerPackageName, info.activityInfo.name);
7913 } catch (RemoteException e) {
7914 // will return null and no error report will be delivered
7915 }
7916 return null;
7917 }
7918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007919 void makeAppNotRespondingLocked(ProcessRecord app,
7920 String tag, String shortMsg, String longMsg, byte[] crashData) {
7921 app.notResponding = true;
7922 app.notRespondingReport = generateProcessError(app,
7923 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
7924 crashData);
7925 startAppProblemLocked(app);
7926 app.stopFreezingAllLocked();
7927 }
7928
7929 /**
7930 * Generate a process error record, suitable for attachment to a ProcessRecord.
7931 *
7932 * @param app The ProcessRecord in which the error occurred.
7933 * @param condition Crashing, Application Not Responding, etc. Values are defined in
7934 * ActivityManager.AppErrorStateInfo
7935 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
7936 * @param shortMsg Short message describing the crash.
7937 * @param longMsg Long message describing the crash.
7938 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
7939 *
7940 * @return Returns a fully-formed AppErrorStateInfo record.
7941 */
7942 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
7943 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
7944 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
7945
7946 report.condition = condition;
7947 report.processName = app.processName;
7948 report.pid = app.pid;
7949 report.uid = app.info.uid;
7950 report.tag = tag;
7951 report.shortMsg = shortMsg;
7952 report.longMsg = longMsg;
7953 report.crashData = crashData;
7954
7955 return report;
7956 }
7957
7958 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
7959 boolean crashed) {
7960 synchronized (this) {
7961 app.crashing = false;
7962 app.crashingReport = null;
7963 app.notResponding = false;
7964 app.notRespondingReport = null;
7965 if (app.anrDialog == fromDialog) {
7966 app.anrDialog = null;
7967 }
7968 if (app.waitDialog == fromDialog) {
7969 app.waitDialog = null;
7970 }
7971 if (app.pid > 0 && app.pid != MY_PID) {
7972 if (crashed) {
7973 handleAppCrashLocked(app);
7974 }
7975 Log.i(ActivityManagerService.TAG, "Killing process "
7976 + app.processName
7977 + " (pid=" + app.pid + ") at user's request");
7978 Process.killProcess(app.pid);
7979 }
7980
7981 }
7982 }
7983
7984 boolean handleAppCrashLocked(ProcessRecord app) {
7985 long now = SystemClock.uptimeMillis();
7986
7987 Long crashTime = mProcessCrashTimes.get(app.info.processName,
7988 app.info.uid);
7989 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
7990 // This process loses!
7991 Log.w(TAG, "Process " + app.info.processName
7992 + " has crashed too many times: killing!");
7993 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
7994 app.info.processName, app.info.uid);
7995 killServicesLocked(app, false);
7996 for (int i=mHistory.size()-1; i>=0; i--) {
7997 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7998 if (r.app == app) {
7999 if (Config.LOGD) Log.d(
8000 TAG, " Force finishing activity "
8001 + r.intent.getComponent().flattenToShortString());
8002 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8003 }
8004 }
8005 if (!app.persistent) {
8006 // We don't want to start this process again until the user
8007 // explicitly does so... but for persistent process, we really
8008 // need to keep it running. If a persistent process is actually
8009 // repeatedly crashing, then badness for everyone.
8010 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8011 app.info.processName);
8012 mBadProcesses.put(app.info.processName, app.info.uid, now);
8013 app.bad = true;
8014 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8015 app.removed = true;
8016 removeProcessLocked(app, false);
8017 return false;
8018 }
8019 }
8020
8021 // Bump up the crash count of any services currently running in the proc.
8022 if (app.services.size() != 0) {
8023 // Any services running in the application need to be placed
8024 // back in the pending list.
8025 Iterator it = app.services.iterator();
8026 while (it.hasNext()) {
8027 ServiceRecord sr = (ServiceRecord)it.next();
8028 sr.crashCount++;
8029 }
8030 }
8031
8032 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8033 return true;
8034 }
8035
8036 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008037 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008038 skipCurrentReceiverLocked(app);
8039 }
8040
8041 void skipCurrentReceiverLocked(ProcessRecord app) {
8042 boolean reschedule = false;
8043 BroadcastRecord r = app.curReceiver;
8044 if (r != null) {
8045 // The current broadcast is waiting for this app's receiver
8046 // to be finished. Looks like that's not going to happen, so
8047 // let the broadcast continue.
8048 logBroadcastReceiverDiscard(r);
8049 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8050 r.resultExtras, r.resultAbort, true);
8051 reschedule = true;
8052 }
8053 r = mPendingBroadcast;
8054 if (r != null && r.curApp == app) {
8055 if (DEBUG_BROADCAST) Log.v(TAG,
8056 "skip & discard pending app " + r);
8057 logBroadcastReceiverDiscard(r);
8058 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8059 r.resultExtras, r.resultAbort, true);
8060 reschedule = true;
8061 }
8062 if (reschedule) {
8063 scheduleBroadcastsLocked();
8064 }
8065 }
8066
8067 public int handleApplicationError(IBinder app, int flags,
8068 String tag, String shortMsg, String longMsg, byte[] crashData) {
8069 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008070 ProcessRecord r = null;
8071 synchronized (this) {
8072 if (app != null) {
8073 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8074 final int NA = apps.size();
8075 for (int ia=0; ia<NA; ia++) {
8076 ProcessRecord p = apps.valueAt(ia);
8077 if (p.thread != null && p.thread.asBinder() == app) {
8078 r = p;
8079 break;
8080 }
8081 }
8082 }
8083 }
8084
8085 if (r != null) {
8086 // The application has crashed. Send the SIGQUIT to the process so
8087 // that it can dump its state.
8088 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8089 //Log.i(TAG, "Current system threads:");
8090 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8091 }
8092
8093 if (mWatcher != null) {
8094 try {
8095 String name = r != null ? r.processName : null;
8096 int pid = r != null ? r.pid : Binder.getCallingPid();
8097 if (!mWatcher.appCrashed(name, pid,
8098 shortMsg, longMsg, crashData)) {
8099 Log.w(TAG, "Force-killing crashed app " + name
8100 + " at watcher's request");
8101 Process.killProcess(pid);
8102 return 0;
8103 }
8104 } catch (RemoteException e) {
8105 mWatcher = null;
8106 }
8107 }
8108
8109 final long origId = Binder.clearCallingIdentity();
8110
8111 // If this process is running instrumentation, finish it.
8112 if (r != null && r.instrumentationClass != null) {
8113 Log.w(TAG, "Error in app " + r.processName
8114 + " running instrumentation " + r.instrumentationClass + ":");
8115 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8116 if (longMsg != null) Log.w(TAG, " " + longMsg);
8117 Bundle info = new Bundle();
8118 info.putString("shortMsg", shortMsg);
8119 info.putString("longMsg", longMsg);
8120 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8121 Binder.restoreCallingIdentity(origId);
8122 return 0;
8123 }
8124
8125 if (r != null) {
8126 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8127 return 0;
8128 }
8129 } else {
8130 Log.w(TAG, "Some application object " + app + " tag " + tag
8131 + " has crashed, but I don't know who it is.");
8132 Log.w(TAG, "ShortMsg:" + shortMsg);
8133 Log.w(TAG, "LongMsg:" + longMsg);
8134 Binder.restoreCallingIdentity(origId);
8135 return 0;
8136 }
8137
8138 Message msg = Message.obtain();
8139 msg.what = SHOW_ERROR_MSG;
8140 HashMap data = new HashMap();
8141 data.put("result", result);
8142 data.put("app", r);
8143 data.put("flags", flags);
8144 data.put("shortMsg", shortMsg);
8145 data.put("longMsg", longMsg);
8146 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8147 // For system processes, submit crash data to the server.
8148 data.put("crashData", crashData);
8149 }
8150 msg.obj = data;
8151 mHandler.sendMessage(msg);
8152
8153 Binder.restoreCallingIdentity(origId);
8154 }
8155
8156 int res = result.get();
8157
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008158 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008159 synchronized (this) {
8160 if (r != null) {
8161 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8162 SystemClock.uptimeMillis());
8163 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008164 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8165 appErrorIntent = createAppErrorIntentLocked(r);
8166 res = AppErrorDialog.FORCE_QUIT;
8167 }
8168 }
8169
8170 if (appErrorIntent != null) {
8171 try {
8172 mContext.startActivity(appErrorIntent);
8173 } catch (ActivityNotFoundException e) {
8174 Log.w(TAG, "bug report receiver dissappeared", e);
8175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008176 }
8177
8178 return res;
8179 }
8180
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008181 Intent createAppErrorIntentLocked(ProcessRecord r) {
8182 ApplicationErrorReport report = createAppErrorReportLocked(r);
8183 if (report == null) {
8184 return null;
8185 }
8186 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8187 result.setComponent(r.errorReportReceiver);
8188 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8189 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8190 return result;
8191 }
8192
8193 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8194 if (r.errorReportReceiver == null) {
8195 return null;
8196 }
8197
8198 if (!r.crashing && !r.notResponding) {
8199 return null;
8200 }
8201
8202 try {
8203 ApplicationErrorReport report = new ApplicationErrorReport();
8204 report.packageName = r.info.packageName;
8205 report.installerPackageName = r.errorReportReceiver.getPackageName();
8206 report.processName = r.processName;
8207
8208 if (r.crashing) {
8209 report.type = ApplicationErrorReport.TYPE_CRASH;
8210 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8211
8212 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8213 r.crashingReport.crashData);
8214 DataInputStream dataStream = new DataInputStream(byteStream);
8215 CrashData crashData = new CrashData(dataStream);
8216 ThrowableData throwData = crashData.getThrowableData();
8217
8218 report.time = crashData.getTime();
8219 report.crashInfo.stackTrace = throwData.toString();
8220
8221 // extract the source of the exception, useful for report
8222 // clustering
8223 while (throwData.getCause() != null) {
8224 throwData = throwData.getCause();
8225 }
8226 StackTraceElementData trace = throwData.getStackTrace()[0];
8227 report.crashInfo.exceptionClassName = throwData.getType();
8228 report.crashInfo.throwFileName = trace.getFileName();
8229 report.crashInfo.throwClassName = trace.getClassName();
8230 report.crashInfo.throwMethodName = trace.getMethodName();
8231 } else if (r.notResponding) {
8232 report.type = ApplicationErrorReport.TYPE_ANR;
8233 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8234
8235 report.anrInfo.activity = r.notRespondingReport.tag;
8236 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8237 report.anrInfo.info = r.notRespondingReport.longMsg;
8238 }
8239
8240 return report;
8241 } catch (IOException e) {
8242 // we don't send it
8243 }
8244
8245 return null;
8246 }
8247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008248 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8249 // assume our apps are happy - lazy create the list
8250 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8251
8252 synchronized (this) {
8253
8254 // iterate across all processes
8255 final int N = mLRUProcesses.size();
8256 for (int i = 0; i < N; i++) {
8257 ProcessRecord app = mLRUProcesses.get(i);
8258 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8259 // This one's in trouble, so we'll generate a report for it
8260 // crashes are higher priority (in case there's a crash *and* an anr)
8261 ActivityManager.ProcessErrorStateInfo report = null;
8262 if (app.crashing) {
8263 report = app.crashingReport;
8264 } else if (app.notResponding) {
8265 report = app.notRespondingReport;
8266 }
8267
8268 if (report != null) {
8269 if (errList == null) {
8270 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8271 }
8272 errList.add(report);
8273 } else {
8274 Log.w(TAG, "Missing app error report, app = " + app.processName +
8275 " crashing = " + app.crashing +
8276 " notResponding = " + app.notResponding);
8277 }
8278 }
8279 }
8280 }
8281
8282 return errList;
8283 }
8284
8285 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8286 // Lazy instantiation of list
8287 List<ActivityManager.RunningAppProcessInfo> runList = null;
8288 synchronized (this) {
8289 // Iterate across all processes
8290 final int N = mLRUProcesses.size();
8291 for (int i = 0; i < N; i++) {
8292 ProcessRecord app = mLRUProcesses.get(i);
8293 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8294 // Generate process state info for running application
8295 ActivityManager.RunningAppProcessInfo currApp =
8296 new ActivityManager.RunningAppProcessInfo(app.processName,
8297 app.pid, app.getPackageList());
8298 int adj = app.curAdj;
8299 if (adj >= CONTENT_PROVIDER_ADJ) {
8300 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8301 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8302 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008303 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8304 } else if (adj >= HOME_APP_ADJ) {
8305 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8306 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008307 } else if (adj >= SECONDARY_SERVER_ADJ) {
8308 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8309 } else if (adj >= VISIBLE_APP_ADJ) {
8310 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8311 } else {
8312 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8313 }
8314 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8315 // + " lru=" + currApp.lru);
8316 if (runList == null) {
8317 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8318 }
8319 runList.add(currApp);
8320 }
8321 }
8322 }
8323 return runList;
8324 }
8325
8326 @Override
8327 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8328 synchronized (this) {
8329 if (checkCallingPermission(android.Manifest.permission.DUMP)
8330 != PackageManager.PERMISSION_GRANTED) {
8331 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8332 + Binder.getCallingPid()
8333 + ", uid=" + Binder.getCallingUid()
8334 + " without permission "
8335 + android.Manifest.permission.DUMP);
8336 return;
8337 }
8338 if (args.length != 0 && "service".equals(args[0])) {
8339 dumpService(fd, pw, args);
8340 return;
8341 }
8342 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008343 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008344 pw.println(" ");
8345 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008346 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008347 if (mWaitingVisibleActivities.size() > 0) {
8348 pw.println(" ");
8349 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008350 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008351 }
8352 if (mStoppingActivities.size() > 0) {
8353 pw.println(" ");
8354 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008355 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008356 }
8357 if (mFinishingActivities.size() > 0) {
8358 pw.println(" ");
8359 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008360 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008361 }
8362
8363 pw.println(" ");
8364 pw.println(" mPausingActivity: " + mPausingActivity);
8365 pw.println(" mResumedActivity: " + mResumedActivity);
8366 pw.println(" mFocusedActivity: " + mFocusedActivity);
8367 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8368
8369 if (mRecentTasks.size() > 0) {
8370 pw.println(" ");
8371 pw.println("Recent tasks in Current Activity Manager State:");
8372
8373 final int N = mRecentTasks.size();
8374 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008375 TaskRecord tr = mRecentTasks.get(i);
8376 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8377 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008378 mRecentTasks.get(i).dump(pw, " ");
8379 }
8380 }
8381
8382 pw.println(" ");
8383 pw.println(" mCurTask: " + mCurTask);
8384
8385 pw.println(" ");
8386 pw.println("Processes in Current Activity Manager State:");
8387
8388 boolean needSep = false;
8389 int numPers = 0;
8390
8391 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8392 final int NA = procs.size();
8393 for (int ia=0; ia<NA; ia++) {
8394 if (!needSep) {
8395 pw.println(" All known processes:");
8396 needSep = true;
8397 }
8398 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008399 pw.print(r.persistent ? " *PERS*" : " *APP*");
8400 pw.print(" UID "); pw.print(procs.keyAt(ia));
8401 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008402 r.dump(pw, " ");
8403 if (r.persistent) {
8404 numPers++;
8405 }
8406 }
8407 }
8408
8409 if (mLRUProcesses.size() > 0) {
8410 if (needSep) pw.println(" ");
8411 needSep = true;
8412 pw.println(" Running processes (most recent first):");
8413 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008414 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008415 needSep = true;
8416 }
8417
8418 synchronized (mPidsSelfLocked) {
8419 if (mPidsSelfLocked.size() > 0) {
8420 if (needSep) pw.println(" ");
8421 needSep = true;
8422 pw.println(" PID mappings:");
8423 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008424 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8425 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008426 }
8427 }
8428 }
8429
8430 if (mForegroundProcesses.size() > 0) {
8431 if (needSep) pw.println(" ");
8432 needSep = true;
8433 pw.println(" Foreground Processes:");
8434 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008435 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8436 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008437 }
8438 }
8439
8440 if (mPersistentStartingProcesses.size() > 0) {
8441 if (needSep) pw.println(" ");
8442 needSep = true;
8443 pw.println(" Persisent processes that are starting:");
8444 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008445 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008446 }
8447
8448 if (mStartingProcesses.size() > 0) {
8449 if (needSep) pw.println(" ");
8450 needSep = true;
8451 pw.println(" Processes that are starting:");
8452 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008453 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008454 }
8455
8456 if (mRemovedProcesses.size() > 0) {
8457 if (needSep) pw.println(" ");
8458 needSep = true;
8459 pw.println(" Processes that are being removed:");
8460 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008461 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008462 }
8463
8464 if (mProcessesOnHold.size() > 0) {
8465 if (needSep) pw.println(" ");
8466 needSep = true;
8467 pw.println(" Processes that are on old until the system is ready:");
8468 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008469 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008470 }
8471
8472 if (mProcessCrashTimes.getMap().size() > 0) {
8473 if (needSep) pw.println(" ");
8474 needSep = true;
8475 pw.println(" Time since processes crashed:");
8476 long now = SystemClock.uptimeMillis();
8477 for (Map.Entry<String, SparseArray<Long>> procs
8478 : mProcessCrashTimes.getMap().entrySet()) {
8479 SparseArray<Long> uids = procs.getValue();
8480 final int N = uids.size();
8481 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008482 pw.print(" Process "); pw.print(procs.getKey());
8483 pw.print(" uid "); pw.print(uids.keyAt(i));
8484 pw.print(": last crashed ");
8485 pw.print((now-uids.valueAt(i)));
8486 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008487 }
8488 }
8489 }
8490
8491 if (mBadProcesses.getMap().size() > 0) {
8492 if (needSep) pw.println(" ");
8493 needSep = true;
8494 pw.println(" Bad processes:");
8495 for (Map.Entry<String, SparseArray<Long>> procs
8496 : mBadProcesses.getMap().entrySet()) {
8497 SparseArray<Long> uids = procs.getValue();
8498 final int N = uids.size();
8499 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008500 pw.print(" Bad process "); pw.print(procs.getKey());
8501 pw.print(" uid "); pw.print(uids.keyAt(i));
8502 pw.print(": crashed at time ");
8503 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008504 }
8505 }
8506 }
8507
8508 pw.println(" ");
8509 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008510 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 pw.println(" mConfiguration: " + mConfiguration);
8512 pw.println(" mStartRunning=" + mStartRunning
8513 + " mSystemReady=" + mSystemReady
8514 + " mBooting=" + mBooting
8515 + " mBooted=" + mBooted
8516 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008517 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008518 pw.println(" mGoingToSleep=" + mGoingToSleep);
8519 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8520 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8521 + " mDebugTransient=" + mDebugTransient
8522 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8523 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
8524 + " mWatcher=" + mWatcher);
8525 }
8526 }
8527
8528 /**
8529 * There are three ways to call this:
8530 * - no service specified: dump all the services
8531 * - a flattened component name that matched an existing service was specified as the
8532 * first arg: dump that one service
8533 * - the first arg isn't the flattened component name of an existing service:
8534 * dump all services whose component contains the first arg as a substring
8535 */
8536 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8537 String[] newArgs;
8538 String componentNameString;
8539 ServiceRecord r;
8540 if (args.length == 1) {
8541 componentNameString = null;
8542 newArgs = EMPTY_STRING_ARRAY;
8543 r = null;
8544 } else {
8545 componentNameString = args[1];
8546 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8547 r = componentName != null ? mServices.get(componentName) : null;
8548 newArgs = new String[args.length - 2];
8549 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8550 }
8551
8552 if (r != null) {
8553 dumpService(fd, pw, r, newArgs);
8554 } else {
8555 for (ServiceRecord r1 : mServices.values()) {
8556 if (componentNameString == null
8557 || r1.name.flattenToString().contains(componentNameString)) {
8558 dumpService(fd, pw, r1, newArgs);
8559 }
8560 }
8561 }
8562 }
8563
8564 /**
8565 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8566 * there is a thread associated with the service.
8567 */
8568 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8569 pw.println(" Service " + r.name.flattenToString());
8570 if (r.app != null && r.app.thread != null) {
8571 try {
8572 // flush anything that is already in the PrintWriter since the thread is going
8573 // to write to the file descriptor directly
8574 pw.flush();
8575 r.app.thread.dumpService(fd, r, args);
8576 pw.print("\n");
8577 } catch (RemoteException e) {
8578 pw.println("got a RemoteException while dumping the service");
8579 }
8580 }
8581 }
8582
8583 void dumpBroadcasts(PrintWriter pw) {
8584 synchronized (this) {
8585 if (checkCallingPermission(android.Manifest.permission.DUMP)
8586 != PackageManager.PERMISSION_GRANTED) {
8587 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8588 + Binder.getCallingPid()
8589 + ", uid=" + Binder.getCallingUid()
8590 + " without permission "
8591 + android.Manifest.permission.DUMP);
8592 return;
8593 }
8594 pw.println("Broadcasts in Current Activity Manager State:");
8595
8596 if (mRegisteredReceivers.size() > 0) {
8597 pw.println(" ");
8598 pw.println(" Registered Receivers:");
8599 Iterator it = mRegisteredReceivers.values().iterator();
8600 while (it.hasNext()) {
8601 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008602 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008603 r.dump(pw, " ");
8604 }
8605 }
8606
8607 pw.println(" ");
8608 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008609 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008610
8611 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8612 || mPendingBroadcast != null) {
8613 if (mParallelBroadcasts.size() > 0) {
8614 pw.println(" ");
8615 pw.println(" Active broadcasts:");
8616 }
8617 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8618 pw.println(" Broadcast #" + i + ":");
8619 mParallelBroadcasts.get(i).dump(pw, " ");
8620 }
8621 if (mOrderedBroadcasts.size() > 0) {
8622 pw.println(" ");
8623 pw.println(" Active serialized broadcasts:");
8624 }
8625 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8626 pw.println(" Serialized Broadcast #" + i + ":");
8627 mOrderedBroadcasts.get(i).dump(pw, " ");
8628 }
8629 pw.println(" ");
8630 pw.println(" Pending broadcast:");
8631 if (mPendingBroadcast != null) {
8632 mPendingBroadcast.dump(pw, " ");
8633 } else {
8634 pw.println(" (null)");
8635 }
8636 }
8637
8638 pw.println(" ");
8639 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8640 if (mStickyBroadcasts != null) {
8641 pw.println(" ");
8642 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008643 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008644 for (Map.Entry<String, ArrayList<Intent>> ent
8645 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008646 pw.print(" * Sticky action "); pw.print(ent.getKey());
8647 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008648 ArrayList<Intent> intents = ent.getValue();
8649 final int N = intents.size();
8650 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008651 sb.setLength(0);
8652 sb.append(" Intent: ");
8653 intents.get(i).toShortString(sb, true, false);
8654 pw.println(sb.toString());
8655 Bundle bundle = intents.get(i).getExtras();
8656 if (bundle != null) {
8657 pw.print(" ");
8658 pw.println(bundle.toString());
8659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008660 }
8661 }
8662 }
8663
8664 pw.println(" ");
8665 pw.println(" mHandler:");
8666 mHandler.dump(new PrintWriterPrinter(pw), " ");
8667 }
8668 }
8669
8670 void dumpServices(PrintWriter pw) {
8671 synchronized (this) {
8672 if (checkCallingPermission(android.Manifest.permission.DUMP)
8673 != PackageManager.PERMISSION_GRANTED) {
8674 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8675 + Binder.getCallingPid()
8676 + ", uid=" + Binder.getCallingUid()
8677 + " without permission "
8678 + android.Manifest.permission.DUMP);
8679 return;
8680 }
8681 pw.println("Services in Current Activity Manager State:");
8682
8683 boolean needSep = false;
8684
8685 if (mServices.size() > 0) {
8686 pw.println(" Active services:");
8687 Iterator<ServiceRecord> it = mServices.values().iterator();
8688 while (it.hasNext()) {
8689 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008690 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008691 r.dump(pw, " ");
8692 }
8693 needSep = true;
8694 }
8695
8696 if (mPendingServices.size() > 0) {
8697 if (needSep) pw.println(" ");
8698 pw.println(" Pending services:");
8699 for (int i=0; i<mPendingServices.size(); i++) {
8700 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008701 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008702 r.dump(pw, " ");
8703 }
8704 needSep = true;
8705 }
8706
8707 if (mRestartingServices.size() > 0) {
8708 if (needSep) pw.println(" ");
8709 pw.println(" Restarting services:");
8710 for (int i=0; i<mRestartingServices.size(); i++) {
8711 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008712 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008713 r.dump(pw, " ");
8714 }
8715 needSep = true;
8716 }
8717
8718 if (mStoppingServices.size() > 0) {
8719 if (needSep) pw.println(" ");
8720 pw.println(" Stopping services:");
8721 for (int i=0; i<mStoppingServices.size(); i++) {
8722 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008723 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008724 r.dump(pw, " ");
8725 }
8726 needSep = true;
8727 }
8728
8729 if (mServiceConnections.size() > 0) {
8730 if (needSep) pw.println(" ");
8731 pw.println(" Connection bindings to services:");
8732 Iterator<ConnectionRecord> it
8733 = mServiceConnections.values().iterator();
8734 while (it.hasNext()) {
8735 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008736 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008737 r.dump(pw, " ");
8738 }
8739 }
8740 }
8741 }
8742
8743 void dumpProviders(PrintWriter pw) {
8744 synchronized (this) {
8745 if (checkCallingPermission(android.Manifest.permission.DUMP)
8746 != PackageManager.PERMISSION_GRANTED) {
8747 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8748 + Binder.getCallingPid()
8749 + ", uid=" + Binder.getCallingUid()
8750 + " without permission "
8751 + android.Manifest.permission.DUMP);
8752 return;
8753 }
8754
8755 pw.println("Content Providers in Current Activity Manager State:");
8756
8757 boolean needSep = false;
8758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008759 if (mProvidersByClass.size() > 0) {
8760 if (needSep) pw.println(" ");
8761 pw.println(" Published content providers (by class):");
8762 Iterator it = mProvidersByClass.entrySet().iterator();
8763 while (it.hasNext()) {
8764 Map.Entry e = (Map.Entry)it.next();
8765 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008766 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008767 r.dump(pw, " ");
8768 }
8769 needSep = true;
8770 }
8771
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008772 if (mProvidersByName.size() > 0) {
8773 pw.println(" ");
8774 pw.println(" Authority to provider mappings:");
8775 Iterator it = mProvidersByName.entrySet().iterator();
8776 while (it.hasNext()) {
8777 Map.Entry e = (Map.Entry)it.next();
8778 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8779 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8780 pw.println(r);
8781 }
8782 needSep = true;
8783 }
8784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008785 if (mLaunchingProviders.size() > 0) {
8786 if (needSep) pw.println(" ");
8787 pw.println(" Launching content providers:");
8788 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008789 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8790 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008791 }
8792 needSep = true;
8793 }
8794
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008795 if (mGrantedUriPermissions.size() > 0) {
8796 pw.println();
8797 pw.println("Granted Uri Permissions:");
8798 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8799 int uid = mGrantedUriPermissions.keyAt(i);
8800 HashMap<Uri, UriPermission> perms
8801 = mGrantedUriPermissions.valueAt(i);
8802 pw.print(" * UID "); pw.print(uid);
8803 pw.println(" holds:");
8804 for (UriPermission perm : perms.values()) {
8805 pw.print(" "); pw.println(perm);
8806 perm.dump(pw, " ");
8807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808 }
8809 }
8810 }
8811 }
8812
8813 void dumpSenders(PrintWriter pw) {
8814 synchronized (this) {
8815 if (checkCallingPermission(android.Manifest.permission.DUMP)
8816 != PackageManager.PERMISSION_GRANTED) {
8817 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8818 + Binder.getCallingPid()
8819 + ", uid=" + Binder.getCallingUid()
8820 + " without permission "
8821 + android.Manifest.permission.DUMP);
8822 return;
8823 }
8824
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008825 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008826
8827 if (this.mIntentSenderRecords.size() > 0) {
8828 Iterator<WeakReference<PendingIntentRecord>> it
8829 = mIntentSenderRecords.values().iterator();
8830 while (it.hasNext()) {
8831 WeakReference<PendingIntentRecord> ref = it.next();
8832 PendingIntentRecord rec = ref != null ? ref.get(): null;
8833 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008834 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008835 rec.dump(pw, " ");
8836 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008837 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008838 }
8839 }
8840 }
8841 }
8842 }
8843
8844 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008845 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008846 TaskRecord lastTask = null;
8847 for (int i=list.size()-1; i>=0; i--) {
8848 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008849 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008850 if (lastTask != r.task) {
8851 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008852 pw.print(prefix);
8853 pw.print(full ? "* " : " ");
8854 pw.println(lastTask);
8855 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008856 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008858 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008859 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
8860 pw.print(" #"); pw.print(i); pw.print(": ");
8861 pw.println(r);
8862 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008863 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07008864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008865 }
8866 }
8867
8868 private static final int dumpProcessList(PrintWriter pw, List list,
8869 String prefix, String normalLabel, String persistentLabel,
8870 boolean inclOomAdj) {
8871 int numPers = 0;
8872 for (int i=list.size()-1; i>=0; i--) {
8873 ProcessRecord r = (ProcessRecord)list.get(i);
8874 if (false) {
8875 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
8876 + " #" + i + ":");
8877 r.dump(pw, prefix + " ");
8878 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008879 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008880 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07008881 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008882 } else {
8883 pw.println(String.format("%s%s #%2d: %s",
8884 prefix, (r.persistent ? persistentLabel : normalLabel),
8885 i, r.toString()));
8886 }
8887 if (r.persistent) {
8888 numPers++;
8889 }
8890 }
8891 return numPers;
8892 }
8893
8894 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
8895 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07008896 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008897 long uptime = SystemClock.uptimeMillis();
8898 long realtime = SystemClock.elapsedRealtime();
8899
8900 if (isCheckinRequest) {
8901 // short checkin version
8902 pw.println(uptime + "," + realtime);
8903 pw.flush();
8904 } else {
8905 pw.println("Applications Memory Usage (kB):");
8906 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
8907 }
8908 for (int i = list.size() - 1 ; i >= 0 ; i--) {
8909 ProcessRecord r = (ProcessRecord)list.get(i);
8910 if (r.thread != null) {
8911 if (!isCheckinRequest) {
8912 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
8913 pw.flush();
8914 }
8915 try {
8916 r.thread.asBinder().dump(fd, args);
8917 } catch (RemoteException e) {
8918 if (!isCheckinRequest) {
8919 pw.println("Got RemoteException!");
8920 pw.flush();
8921 }
8922 }
8923 }
8924 }
8925 }
8926
8927 /**
8928 * Searches array of arguments for the specified string
8929 * @param args array of argument strings
8930 * @param value value to search for
8931 * @return true if the value is contained in the array
8932 */
8933 private static boolean scanArgs(String[] args, String value) {
8934 if (args != null) {
8935 for (String arg : args) {
8936 if (value.equals(arg)) {
8937 return true;
8938 }
8939 }
8940 }
8941 return false;
8942 }
8943
Dianne Hackborn75b03852009-06-12 15:43:26 -07008944 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008945 int count = mHistory.size();
8946
8947 // convert the token to an entry in the history.
8948 HistoryRecord r = null;
8949 int index = -1;
8950 for (int i=count-1; i>=0; i--) {
8951 Object o = mHistory.get(i);
8952 if (o == token) {
8953 r = (HistoryRecord)o;
8954 index = i;
8955 break;
8956 }
8957 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008958
8959 return index;
8960 }
8961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008962 private final void killServicesLocked(ProcessRecord app,
8963 boolean allowRestart) {
8964 // Report disconnected services.
8965 if (false) {
8966 // XXX we are letting the client link to the service for
8967 // death notifications.
8968 if (app.services.size() > 0) {
8969 Iterator it = app.services.iterator();
8970 while (it.hasNext()) {
8971 ServiceRecord r = (ServiceRecord)it.next();
8972 if (r.connections.size() > 0) {
8973 Iterator<ConnectionRecord> jt
8974 = r.connections.values().iterator();
8975 while (jt.hasNext()) {
8976 ConnectionRecord c = jt.next();
8977 if (c.binding.client != app) {
8978 try {
8979 //c.conn.connected(r.className, null);
8980 } catch (Exception e) {
8981 // todo: this should be asynchronous!
8982 Log.w(TAG, "Exception thrown disconnected servce "
8983 + r.shortName
8984 + " from app " + app.processName, e);
8985 }
8986 }
8987 }
8988 }
8989 }
8990 }
8991 }
8992
8993 // Clean up any connections this application has to other services.
8994 if (app.connections.size() > 0) {
8995 Iterator<ConnectionRecord> it = app.connections.iterator();
8996 while (it.hasNext()) {
8997 ConnectionRecord r = it.next();
8998 removeConnectionLocked(r, app, null);
8999 }
9000 }
9001 app.connections.clear();
9002
9003 if (app.services.size() != 0) {
9004 // Any services running in the application need to be placed
9005 // back in the pending list.
9006 Iterator it = app.services.iterator();
9007 while (it.hasNext()) {
9008 ServiceRecord sr = (ServiceRecord)it.next();
9009 synchronized (sr.stats.getBatteryStats()) {
9010 sr.stats.stopLaunchedLocked();
9011 }
9012 sr.app = null;
9013 sr.executeNesting = 0;
9014 mStoppingServices.remove(sr);
9015 if (sr.bindings.size() > 0) {
9016 Iterator<IntentBindRecord> bindings
9017 = sr.bindings.values().iterator();
9018 while (bindings.hasNext()) {
9019 IntentBindRecord b = bindings.next();
9020 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9021 + ": shouldUnbind=" + b.hasBound);
9022 b.binder = null;
9023 b.requested = b.received = b.hasBound = false;
9024 }
9025 }
9026
9027 if (sr.crashCount >= 2) {
9028 Log.w(TAG, "Service crashed " + sr.crashCount
9029 + " times, stopping: " + sr);
9030 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9031 sr.crashCount, sr.shortName, app.pid);
9032 bringDownServiceLocked(sr, true);
9033 } else if (!allowRestart) {
9034 bringDownServiceLocked(sr, true);
9035 } else {
9036 scheduleServiceRestartLocked(sr);
9037 }
9038 }
9039
9040 if (!allowRestart) {
9041 app.services.clear();
9042 }
9043 }
9044
9045 app.executingServices.clear();
9046 }
9047
9048 private final void removeDyingProviderLocked(ProcessRecord proc,
9049 ContentProviderRecord cpr) {
9050 synchronized (cpr) {
9051 cpr.launchingApp = null;
9052 cpr.notifyAll();
9053 }
9054
9055 mProvidersByClass.remove(cpr.info.name);
9056 String names[] = cpr.info.authority.split(";");
9057 for (int j = 0; j < names.length; j++) {
9058 mProvidersByName.remove(names[j]);
9059 }
9060
9061 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9062 while (cit.hasNext()) {
9063 ProcessRecord capp = cit.next();
9064 if (!capp.persistent && capp.thread != null
9065 && capp.pid != 0
9066 && capp.pid != MY_PID) {
9067 Log.i(TAG, "Killing app " + capp.processName
9068 + " (pid " + capp.pid
9069 + ") because provider " + cpr.info.name
9070 + " is in dying process " + proc.processName);
9071 Process.killProcess(capp.pid);
9072 }
9073 }
9074
9075 mLaunchingProviders.remove(cpr);
9076 }
9077
9078 /**
9079 * Main code for cleaning up a process when it has gone away. This is
9080 * called both as a result of the process dying, or directly when stopping
9081 * a process when running in single process mode.
9082 */
9083 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9084 boolean restarting, int index) {
9085 if (index >= 0) {
9086 mLRUProcesses.remove(index);
9087 }
9088
9089 // Dismiss any open dialogs.
9090 if (app.crashDialog != null) {
9091 app.crashDialog.dismiss();
9092 app.crashDialog = null;
9093 }
9094 if (app.anrDialog != null) {
9095 app.anrDialog.dismiss();
9096 app.anrDialog = null;
9097 }
9098 if (app.waitDialog != null) {
9099 app.waitDialog.dismiss();
9100 app.waitDialog = null;
9101 }
9102
9103 app.crashing = false;
9104 app.notResponding = false;
9105
9106 app.resetPackageList();
9107 app.thread = null;
9108 app.forcingToForeground = null;
9109 app.foregroundServices = false;
9110
9111 killServicesLocked(app, true);
9112
9113 boolean restart = false;
9114
9115 int NL = mLaunchingProviders.size();
9116
9117 // Remove published content providers.
9118 if (!app.pubProviders.isEmpty()) {
9119 Iterator it = app.pubProviders.values().iterator();
9120 while (it.hasNext()) {
9121 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9122 cpr.provider = null;
9123 cpr.app = null;
9124
9125 // See if someone is waiting for this provider... in which
9126 // case we don't remove it, but just let it restart.
9127 int i = 0;
9128 if (!app.bad) {
9129 for (; i<NL; i++) {
9130 if (mLaunchingProviders.get(i) == cpr) {
9131 restart = true;
9132 break;
9133 }
9134 }
9135 } else {
9136 i = NL;
9137 }
9138
9139 if (i >= NL) {
9140 removeDyingProviderLocked(app, cpr);
9141 NL = mLaunchingProviders.size();
9142 }
9143 }
9144 app.pubProviders.clear();
9145 }
9146
9147 // Look through the content providers we are waiting to have launched,
9148 // and if any run in this process then either schedule a restart of
9149 // the process or kill the client waiting for it if this process has
9150 // gone bad.
9151 for (int i=0; i<NL; i++) {
9152 ContentProviderRecord cpr = (ContentProviderRecord)
9153 mLaunchingProviders.get(i);
9154 if (cpr.launchingApp == app) {
9155 if (!app.bad) {
9156 restart = true;
9157 } else {
9158 removeDyingProviderLocked(app, cpr);
9159 NL = mLaunchingProviders.size();
9160 }
9161 }
9162 }
9163
9164 // Unregister from connected content providers.
9165 if (!app.conProviders.isEmpty()) {
9166 Iterator it = app.conProviders.iterator();
9167 while (it.hasNext()) {
9168 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9169 cpr.clients.remove(app);
9170 }
9171 app.conProviders.clear();
9172 }
9173
9174 skipCurrentReceiverLocked(app);
9175
9176 // Unregister any receivers.
9177 if (app.receivers.size() > 0) {
9178 Iterator<ReceiverList> it = app.receivers.iterator();
9179 while (it.hasNext()) {
9180 removeReceiverLocked(it.next());
9181 }
9182 app.receivers.clear();
9183 }
9184
Christopher Tate181fafa2009-05-14 11:12:14 -07009185 // If the app is undergoing backup, tell the backup manager about it
9186 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9187 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9188 try {
9189 IBackupManager bm = IBackupManager.Stub.asInterface(
9190 ServiceManager.getService(Context.BACKUP_SERVICE));
9191 bm.agentDisconnected(app.info.packageName);
9192 } catch (RemoteException e) {
9193 // can't happen; backup manager is local
9194 }
9195 }
9196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009197 // If the caller is restarting this app, then leave it in its
9198 // current lists and let the caller take care of it.
9199 if (restarting) {
9200 return;
9201 }
9202
9203 if (!app.persistent) {
9204 if (DEBUG_PROCESSES) Log.v(TAG,
9205 "Removing non-persistent process during cleanup: " + app);
9206 mProcessNames.remove(app.processName, app.info.uid);
9207 } else if (!app.removed) {
9208 // This app is persistent, so we need to keep its record around.
9209 // If it is not already on the pending app list, add it there
9210 // and start a new process for it.
9211 app.thread = null;
9212 app.forcingToForeground = null;
9213 app.foregroundServices = false;
9214 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9215 mPersistentStartingProcesses.add(app);
9216 restart = true;
9217 }
9218 }
9219 mProcessesOnHold.remove(app);
9220
The Android Open Source Project4df24232009-03-05 14:34:35 -08009221 if (app == mHomeProcess) {
9222 mHomeProcess = null;
9223 }
9224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009225 if (restart) {
9226 // We have components that still need to be running in the
9227 // process, so re-launch it.
9228 mProcessNames.put(app.processName, app.info.uid, app);
9229 startProcessLocked(app, "restart", app.processName);
9230 } else if (app.pid > 0 && app.pid != MY_PID) {
9231 // Goodbye!
9232 synchronized (mPidsSelfLocked) {
9233 mPidsSelfLocked.remove(app.pid);
9234 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9235 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009236 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009237 }
9238 }
9239
9240 // =========================================================
9241 // SERVICES
9242 // =========================================================
9243
9244 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9245 ActivityManager.RunningServiceInfo info =
9246 new ActivityManager.RunningServiceInfo();
9247 info.service = r.name;
9248 if (r.app != null) {
9249 info.pid = r.app.pid;
9250 }
9251 info.process = r.processName;
9252 info.foreground = r.isForeground;
9253 info.activeSince = r.createTime;
9254 info.started = r.startRequested;
9255 info.clientCount = r.connections.size();
9256 info.crashCount = r.crashCount;
9257 info.lastActivityTime = r.lastActivity;
9258 return info;
9259 }
9260
9261 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9262 int flags) {
9263 synchronized (this) {
9264 ArrayList<ActivityManager.RunningServiceInfo> res
9265 = new ArrayList<ActivityManager.RunningServiceInfo>();
9266
9267 if (mServices.size() > 0) {
9268 Iterator<ServiceRecord> it = mServices.values().iterator();
9269 while (it.hasNext() && res.size() < maxNum) {
9270 res.add(makeRunningServiceInfoLocked(it.next()));
9271 }
9272 }
9273
9274 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9275 ServiceRecord r = mRestartingServices.get(i);
9276 ActivityManager.RunningServiceInfo info =
9277 makeRunningServiceInfoLocked(r);
9278 info.restarting = r.nextRestartTime;
9279 res.add(info);
9280 }
9281
9282 return res;
9283 }
9284 }
9285
9286 private final ServiceRecord findServiceLocked(ComponentName name,
9287 IBinder token) {
9288 ServiceRecord r = mServices.get(name);
9289 return r == token ? r : null;
9290 }
9291
9292 private final class ServiceLookupResult {
9293 final ServiceRecord record;
9294 final String permission;
9295
9296 ServiceLookupResult(ServiceRecord _record, String _permission) {
9297 record = _record;
9298 permission = _permission;
9299 }
9300 };
9301
9302 private ServiceLookupResult findServiceLocked(Intent service,
9303 String resolvedType) {
9304 ServiceRecord r = null;
9305 if (service.getComponent() != null) {
9306 r = mServices.get(service.getComponent());
9307 }
9308 if (r == null) {
9309 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9310 r = mServicesByIntent.get(filter);
9311 }
9312
9313 if (r == null) {
9314 try {
9315 ResolveInfo rInfo =
9316 ActivityThread.getPackageManager().resolveService(
9317 service, resolvedType, 0);
9318 ServiceInfo sInfo =
9319 rInfo != null ? rInfo.serviceInfo : null;
9320 if (sInfo == null) {
9321 return null;
9322 }
9323
9324 ComponentName name = new ComponentName(
9325 sInfo.applicationInfo.packageName, sInfo.name);
9326 r = mServices.get(name);
9327 } catch (RemoteException ex) {
9328 // pm is in same process, this will never happen.
9329 }
9330 }
9331 if (r != null) {
9332 int callingPid = Binder.getCallingPid();
9333 int callingUid = Binder.getCallingUid();
9334 if (checkComponentPermission(r.permission,
9335 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9336 != PackageManager.PERMISSION_GRANTED) {
9337 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9338 + " from pid=" + callingPid
9339 + ", uid=" + callingUid
9340 + " requires " + r.permission);
9341 return new ServiceLookupResult(null, r.permission);
9342 }
9343 return new ServiceLookupResult(r, null);
9344 }
9345 return null;
9346 }
9347
9348 private class ServiceRestarter implements Runnable {
9349 private ServiceRecord mService;
9350
9351 void setService(ServiceRecord service) {
9352 mService = service;
9353 }
9354
9355 public void run() {
9356 synchronized(ActivityManagerService.this) {
9357 performServiceRestartLocked(mService);
9358 }
9359 }
9360 }
9361
9362 private ServiceLookupResult retrieveServiceLocked(Intent service,
9363 String resolvedType, int callingPid, int callingUid) {
9364 ServiceRecord r = null;
9365 if (service.getComponent() != null) {
9366 r = mServices.get(service.getComponent());
9367 }
9368 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9369 r = mServicesByIntent.get(filter);
9370 if (r == null) {
9371 try {
9372 ResolveInfo rInfo =
9373 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009374 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009375 ServiceInfo sInfo =
9376 rInfo != null ? rInfo.serviceInfo : null;
9377 if (sInfo == null) {
9378 Log.w(TAG, "Unable to start service " + service +
9379 ": not found");
9380 return null;
9381 }
9382
9383 ComponentName name = new ComponentName(
9384 sInfo.applicationInfo.packageName, sInfo.name);
9385 r = mServices.get(name);
9386 if (r == null) {
9387 filter = new Intent.FilterComparison(service.cloneFilter());
9388 ServiceRestarter res = new ServiceRestarter();
9389 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9390 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9391 synchronized (stats) {
9392 ss = stats.getServiceStatsLocked(
9393 sInfo.applicationInfo.uid, sInfo.packageName,
9394 sInfo.name);
9395 }
9396 r = new ServiceRecord(ss, name, filter, sInfo, res);
9397 res.setService(r);
9398 mServices.put(name, r);
9399 mServicesByIntent.put(filter, r);
9400
9401 // Make sure this component isn't in the pending list.
9402 int N = mPendingServices.size();
9403 for (int i=0; i<N; i++) {
9404 ServiceRecord pr = mPendingServices.get(i);
9405 if (pr.name.equals(name)) {
9406 mPendingServices.remove(i);
9407 i--;
9408 N--;
9409 }
9410 }
9411 }
9412 } catch (RemoteException ex) {
9413 // pm is in same process, this will never happen.
9414 }
9415 }
9416 if (r != null) {
9417 if (checkComponentPermission(r.permission,
9418 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9419 != PackageManager.PERMISSION_GRANTED) {
9420 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9421 + " from pid=" + Binder.getCallingPid()
9422 + ", uid=" + Binder.getCallingUid()
9423 + " requires " + r.permission);
9424 return new ServiceLookupResult(null, r.permission);
9425 }
9426 return new ServiceLookupResult(r, null);
9427 }
9428 return null;
9429 }
9430
9431 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9432 long now = SystemClock.uptimeMillis();
9433 if (r.executeNesting == 0 && r.app != null) {
9434 if (r.app.executingServices.size() == 0) {
9435 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9436 msg.obj = r.app;
9437 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9438 }
9439 r.app.executingServices.add(r);
9440 }
9441 r.executeNesting++;
9442 r.executingStart = now;
9443 }
9444
9445 private final void sendServiceArgsLocked(ServiceRecord r,
9446 boolean oomAdjusted) {
9447 final int N = r.startArgs.size();
9448 if (N == 0) {
9449 return;
9450 }
9451
9452 final int BASEID = r.lastStartId - N + 1;
9453 int i = 0;
9454 while (i < N) {
9455 try {
9456 Intent args = r.startArgs.get(i);
9457 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9458 + r.name + " " + r.intent + " args=" + args);
9459 bumpServiceExecutingLocked(r);
9460 if (!oomAdjusted) {
9461 oomAdjusted = true;
9462 updateOomAdjLocked(r.app);
9463 }
9464 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9465 i++;
9466 } catch (Exception e) {
9467 break;
9468 }
9469 }
9470 if (i == N) {
9471 r.startArgs.clear();
9472 } else {
9473 while (i > 0) {
9474 r.startArgs.remove(0);
9475 i--;
9476 }
9477 }
9478 }
9479
9480 private final boolean requestServiceBindingLocked(ServiceRecord r,
9481 IntentBindRecord i, boolean rebind) {
9482 if (r.app == null || r.app.thread == null) {
9483 // If service is not currently running, can't yet bind.
9484 return false;
9485 }
9486 if ((!i.requested || rebind) && i.apps.size() > 0) {
9487 try {
9488 bumpServiceExecutingLocked(r);
9489 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9490 + ": shouldUnbind=" + i.hasBound);
9491 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9492 if (!rebind) {
9493 i.requested = true;
9494 }
9495 i.hasBound = true;
9496 i.doRebind = false;
9497 } catch (RemoteException e) {
9498 return false;
9499 }
9500 }
9501 return true;
9502 }
9503
9504 private final void requestServiceBindingsLocked(ServiceRecord r) {
9505 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9506 while (bindings.hasNext()) {
9507 IntentBindRecord i = bindings.next();
9508 if (!requestServiceBindingLocked(r, i, false)) {
9509 break;
9510 }
9511 }
9512 }
9513
9514 private final void realStartServiceLocked(ServiceRecord r,
9515 ProcessRecord app) throws RemoteException {
9516 if (app.thread == null) {
9517 throw new RemoteException();
9518 }
9519
9520 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009521 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009522
9523 app.services.add(r);
9524 bumpServiceExecutingLocked(r);
9525 updateLRUListLocked(app, true);
9526
9527 boolean created = false;
9528 try {
9529 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9530 + r.name + " " + r.intent);
9531 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9532 System.identityHashCode(r), r.shortName,
9533 r.intent.getIntent().toString(), r.app.pid);
9534 synchronized (r.stats.getBatteryStats()) {
9535 r.stats.startLaunchedLocked();
9536 }
9537 app.thread.scheduleCreateService(r, r.serviceInfo);
9538 created = true;
9539 } finally {
9540 if (!created) {
9541 app.services.remove(r);
9542 scheduleServiceRestartLocked(r);
9543 }
9544 }
9545
9546 requestServiceBindingsLocked(r);
9547 sendServiceArgsLocked(r, true);
9548 }
9549
9550 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9551 r.totalRestartCount++;
9552 if (r.restartDelay == 0) {
9553 r.restartCount++;
9554 r.restartDelay = SERVICE_RESTART_DURATION;
9555 } else {
9556 // If it has been a "reasonably long time" since the service
9557 // was started, then reset our restart duration back to
9558 // the beginning, so we don't infinitely increase the duration
9559 // on a service that just occasionally gets killed (which is
9560 // a normal case, due to process being killed to reclaim memory).
9561 long now = SystemClock.uptimeMillis();
9562 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9563 r.restartCount = 1;
9564 r.restartDelay = SERVICE_RESTART_DURATION;
9565 } else {
9566 r.restartDelay *= 2;
9567 }
9568 }
9569 if (!mRestartingServices.contains(r)) {
9570 mRestartingServices.add(r);
9571 }
9572 mHandler.removeCallbacks(r.restarter);
9573 mHandler.postDelayed(r.restarter, r.restartDelay);
9574 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9575 Log.w(TAG, "Scheduling restart of crashed service "
9576 + r.shortName + " in " + r.restartDelay + "ms");
9577 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9578 r.shortName, r.restartDelay);
9579
9580 Message msg = Message.obtain();
9581 msg.what = SERVICE_ERROR_MSG;
9582 msg.obj = r;
9583 mHandler.sendMessage(msg);
9584 }
9585
9586 final void performServiceRestartLocked(ServiceRecord r) {
9587 if (!mRestartingServices.contains(r)) {
9588 return;
9589 }
9590 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9591 }
9592
9593 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9594 if (r.restartDelay == 0) {
9595 return false;
9596 }
9597 r.resetRestartCounter();
9598 mRestartingServices.remove(r);
9599 mHandler.removeCallbacks(r.restarter);
9600 return true;
9601 }
9602
9603 private final boolean bringUpServiceLocked(ServiceRecord r,
9604 int intentFlags, boolean whileRestarting) {
9605 //Log.i(TAG, "Bring up service:");
9606 //r.dump(" ");
9607
9608 if (r.app != null) {
9609 sendServiceArgsLocked(r, false);
9610 return true;
9611 }
9612
9613 if (!whileRestarting && r.restartDelay > 0) {
9614 // If waiting for a restart, then do nothing.
9615 return true;
9616 }
9617
9618 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9619 + " " + r.intent);
9620
9621 final String appName = r.processName;
9622 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9623 if (app != null && app.thread != null) {
9624 try {
9625 realStartServiceLocked(r, app);
9626 return true;
9627 } catch (RemoteException e) {
9628 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9629 }
9630
9631 // If a dead object exception was thrown -- fall through to
9632 // restart the application.
9633 }
9634
9635 if (!mPendingServices.contains(r)) {
9636 // Not running -- get it started, and enqueue this service record
9637 // to be executed when the app comes up.
9638 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9639 "service", r.name) == null) {
9640 Log.w(TAG, "Unable to launch app "
9641 + r.appInfo.packageName + "/"
9642 + r.appInfo.uid + " for service "
9643 + r.intent.getIntent() + ": process is bad");
9644 bringDownServiceLocked(r, true);
9645 return false;
9646 }
9647 mPendingServices.add(r);
9648 }
9649 return true;
9650 }
9651
9652 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9653 //Log.i(TAG, "Bring down service:");
9654 //r.dump(" ");
9655
9656 // Does it still need to run?
9657 if (!force && r.startRequested) {
9658 return;
9659 }
9660 if (r.connections.size() > 0) {
9661 if (!force) {
9662 // XXX should probably keep a count of the number of auto-create
9663 // connections directly in the service.
9664 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9665 while (it.hasNext()) {
9666 ConnectionRecord cr = it.next();
9667 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9668 return;
9669 }
9670 }
9671 }
9672
9673 // Report to all of the connections that the service is no longer
9674 // available.
9675 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9676 while (it.hasNext()) {
9677 ConnectionRecord c = it.next();
9678 try {
9679 // todo: shouldn't be a synchronous call!
9680 c.conn.connected(r.name, null);
9681 } catch (Exception e) {
9682 Log.w(TAG, "Failure disconnecting service " + r.name +
9683 " to connection " + c.conn.asBinder() +
9684 " (in " + c.binding.client.processName + ")", e);
9685 }
9686 }
9687 }
9688
9689 // Tell the service that it has been unbound.
9690 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9691 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9692 while (it.hasNext()) {
9693 IntentBindRecord ibr = it.next();
9694 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9695 + ": hasBound=" + ibr.hasBound);
9696 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9697 try {
9698 bumpServiceExecutingLocked(r);
9699 updateOomAdjLocked(r.app);
9700 ibr.hasBound = false;
9701 r.app.thread.scheduleUnbindService(r,
9702 ibr.intent.getIntent());
9703 } catch (Exception e) {
9704 Log.w(TAG, "Exception when unbinding service "
9705 + r.shortName, e);
9706 serviceDoneExecutingLocked(r, true);
9707 }
9708 }
9709 }
9710 }
9711
9712 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9713 + " " + r.intent);
9714 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9715 System.identityHashCode(r), r.shortName,
9716 (r.app != null) ? r.app.pid : -1);
9717
9718 mServices.remove(r.name);
9719 mServicesByIntent.remove(r.intent);
9720 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9721 r.totalRestartCount = 0;
9722 unscheduleServiceRestartLocked(r);
9723
9724 // Also make sure it is not on the pending list.
9725 int N = mPendingServices.size();
9726 for (int i=0; i<N; i++) {
9727 if (mPendingServices.get(i) == r) {
9728 mPendingServices.remove(i);
9729 if (DEBUG_SERVICE) Log.v(
9730 TAG, "Removed pending service: " + r.shortName);
9731 i--;
9732 N--;
9733 }
9734 }
9735
9736 if (r.app != null) {
9737 synchronized (r.stats.getBatteryStats()) {
9738 r.stats.stopLaunchedLocked();
9739 }
9740 r.app.services.remove(r);
9741 if (r.app.thread != null) {
9742 updateServiceForegroundLocked(r.app, false);
9743 try {
9744 Log.i(TAG, "Stopping service: " + r.shortName);
9745 bumpServiceExecutingLocked(r);
9746 mStoppingServices.add(r);
9747 updateOomAdjLocked(r.app);
9748 r.app.thread.scheduleStopService(r);
9749 } catch (Exception e) {
9750 Log.w(TAG, "Exception when stopping service "
9751 + r.shortName, e);
9752 serviceDoneExecutingLocked(r, true);
9753 }
9754 } else {
9755 if (DEBUG_SERVICE) Log.v(
9756 TAG, "Removed service that has no process: " + r.shortName);
9757 }
9758 } else {
9759 if (DEBUG_SERVICE) Log.v(
9760 TAG, "Removed service that is not running: " + r.shortName);
9761 }
9762 }
9763
9764 ComponentName startServiceLocked(IApplicationThread caller,
9765 Intent service, String resolvedType,
9766 int callingPid, int callingUid) {
9767 synchronized(this) {
9768 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9769 + " type=" + resolvedType + " args=" + service.getExtras());
9770
9771 if (caller != null) {
9772 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9773 if (callerApp == null) {
9774 throw new SecurityException(
9775 "Unable to find app for caller " + caller
9776 + " (pid=" + Binder.getCallingPid()
9777 + ") when starting service " + service);
9778 }
9779 }
9780
9781 ServiceLookupResult res =
9782 retrieveServiceLocked(service, resolvedType,
9783 callingPid, callingUid);
9784 if (res == null) {
9785 return null;
9786 }
9787 if (res.record == null) {
9788 return new ComponentName("!", res.permission != null
9789 ? res.permission : "private to package");
9790 }
9791 ServiceRecord r = res.record;
9792 if (unscheduleServiceRestartLocked(r)) {
9793 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9794 + r.shortName);
9795 }
9796 r.startRequested = true;
9797 r.startArgs.add(service);
9798 r.lastStartId++;
9799 if (r.lastStartId < 1) {
9800 r.lastStartId = 1;
9801 }
9802 r.lastActivity = SystemClock.uptimeMillis();
9803 synchronized (r.stats.getBatteryStats()) {
9804 r.stats.startRunningLocked();
9805 }
9806 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
9807 return new ComponentName("!", "Service process is bad");
9808 }
9809 return r.name;
9810 }
9811 }
9812
9813 public ComponentName startService(IApplicationThread caller, Intent service,
9814 String resolvedType) {
9815 // Refuse possible leaked file descriptors
9816 if (service != null && service.hasFileDescriptors() == true) {
9817 throw new IllegalArgumentException("File descriptors passed in Intent");
9818 }
9819
9820 synchronized(this) {
9821 final int callingPid = Binder.getCallingPid();
9822 final int callingUid = Binder.getCallingUid();
9823 final long origId = Binder.clearCallingIdentity();
9824 ComponentName res = startServiceLocked(caller, service,
9825 resolvedType, callingPid, callingUid);
9826 Binder.restoreCallingIdentity(origId);
9827 return res;
9828 }
9829 }
9830
9831 ComponentName startServiceInPackage(int uid,
9832 Intent service, String resolvedType) {
9833 synchronized(this) {
9834 final long origId = Binder.clearCallingIdentity();
9835 ComponentName res = startServiceLocked(null, service,
9836 resolvedType, -1, uid);
9837 Binder.restoreCallingIdentity(origId);
9838 return res;
9839 }
9840 }
9841
9842 public int stopService(IApplicationThread caller, Intent service,
9843 String resolvedType) {
9844 // Refuse possible leaked file descriptors
9845 if (service != null && service.hasFileDescriptors() == true) {
9846 throw new IllegalArgumentException("File descriptors passed in Intent");
9847 }
9848
9849 synchronized(this) {
9850 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
9851 + " type=" + resolvedType);
9852
9853 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9854 if (caller != null && callerApp == null) {
9855 throw new SecurityException(
9856 "Unable to find app for caller " + caller
9857 + " (pid=" + Binder.getCallingPid()
9858 + ") when stopping service " + service);
9859 }
9860
9861 // If this service is active, make sure it is stopped.
9862 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9863 if (r != null) {
9864 if (r.record != null) {
9865 synchronized (r.record.stats.getBatteryStats()) {
9866 r.record.stats.stopRunningLocked();
9867 }
9868 r.record.startRequested = false;
9869 final long origId = Binder.clearCallingIdentity();
9870 bringDownServiceLocked(r.record, false);
9871 Binder.restoreCallingIdentity(origId);
9872 return 1;
9873 }
9874 return -1;
9875 }
9876 }
9877
9878 return 0;
9879 }
9880
9881 public IBinder peekService(Intent service, String resolvedType) {
9882 // Refuse possible leaked file descriptors
9883 if (service != null && service.hasFileDescriptors() == true) {
9884 throw new IllegalArgumentException("File descriptors passed in Intent");
9885 }
9886
9887 IBinder ret = null;
9888
9889 synchronized(this) {
9890 ServiceLookupResult r = findServiceLocked(service, resolvedType);
9891
9892 if (r != null) {
9893 // r.record is null if findServiceLocked() failed the caller permission check
9894 if (r.record == null) {
9895 throw new SecurityException(
9896 "Permission Denial: Accessing service " + r.record.name
9897 + " from pid=" + Binder.getCallingPid()
9898 + ", uid=" + Binder.getCallingUid()
9899 + " requires " + r.permission);
9900 }
9901 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
9902 if (ib != null) {
9903 ret = ib.binder;
9904 }
9905 }
9906 }
9907
9908 return ret;
9909 }
9910
9911 public boolean stopServiceToken(ComponentName className, IBinder token,
9912 int startId) {
9913 synchronized(this) {
9914 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
9915 + " " + token + " startId=" + startId);
9916 ServiceRecord r = findServiceLocked(className, token);
9917 if (r != null && (startId < 0 || r.lastStartId == startId)) {
9918 synchronized (r.stats.getBatteryStats()) {
9919 r.stats.stopRunningLocked();
9920 r.startRequested = false;
9921 }
9922 final long origId = Binder.clearCallingIdentity();
9923 bringDownServiceLocked(r, false);
9924 Binder.restoreCallingIdentity(origId);
9925 return true;
9926 }
9927 }
9928 return false;
9929 }
9930
9931 public void setServiceForeground(ComponentName className, IBinder token,
9932 boolean isForeground) {
9933 synchronized(this) {
9934 ServiceRecord r = findServiceLocked(className, token);
9935 if (r != null) {
9936 if (r.isForeground != isForeground) {
9937 final long origId = Binder.clearCallingIdentity();
9938 r.isForeground = isForeground;
9939 if (r.app != null) {
9940 updateServiceForegroundLocked(r.app, true);
9941 }
9942 Binder.restoreCallingIdentity(origId);
9943 }
9944 }
9945 }
9946 }
9947
9948 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
9949 boolean anyForeground = false;
9950 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
9951 if (sr.isForeground) {
9952 anyForeground = true;
9953 break;
9954 }
9955 }
9956 if (anyForeground != proc.foregroundServices) {
9957 proc.foregroundServices = anyForeground;
9958 if (oomAdj) {
9959 updateOomAdjLocked();
9960 }
9961 }
9962 }
9963
9964 public int bindService(IApplicationThread caller, IBinder token,
9965 Intent service, String resolvedType,
9966 IServiceConnection connection, int flags) {
9967 // Refuse possible leaked file descriptors
9968 if (service != null && service.hasFileDescriptors() == true) {
9969 throw new IllegalArgumentException("File descriptors passed in Intent");
9970 }
9971
9972 synchronized(this) {
9973 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
9974 + " type=" + resolvedType + " conn=" + connection.asBinder()
9975 + " flags=0x" + Integer.toHexString(flags));
9976 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9977 if (callerApp == null) {
9978 throw new SecurityException(
9979 "Unable to find app for caller " + caller
9980 + " (pid=" + Binder.getCallingPid()
9981 + ") when binding service " + service);
9982 }
9983
9984 HistoryRecord activity = null;
9985 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07009986 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009987 if (aindex < 0) {
9988 Log.w(TAG, "Binding with unknown activity: " + token);
9989 return 0;
9990 }
9991 activity = (HistoryRecord)mHistory.get(aindex);
9992 }
9993
9994 ServiceLookupResult res =
9995 retrieveServiceLocked(service, resolvedType,
9996 Binder.getCallingPid(), Binder.getCallingUid());
9997 if (res == null) {
9998 return 0;
9999 }
10000 if (res.record == null) {
10001 return -1;
10002 }
10003 ServiceRecord s = res.record;
10004
10005 final long origId = Binder.clearCallingIdentity();
10006
10007 if (unscheduleServiceRestartLocked(s)) {
10008 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10009 + s.shortName);
10010 }
10011
10012 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10013 ConnectionRecord c = new ConnectionRecord(b, activity,
10014 connection, flags);
10015
10016 IBinder binder = connection.asBinder();
10017 s.connections.put(binder, c);
10018 b.connections.add(c);
10019 if (activity != null) {
10020 if (activity.connections == null) {
10021 activity.connections = new HashSet<ConnectionRecord>();
10022 }
10023 activity.connections.add(c);
10024 }
10025 b.client.connections.add(c);
10026 mServiceConnections.put(binder, c);
10027
10028 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10029 s.lastActivity = SystemClock.uptimeMillis();
10030 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10031 return 0;
10032 }
10033 }
10034
10035 if (s.app != null) {
10036 // This could have made the service more important.
10037 updateOomAdjLocked(s.app);
10038 }
10039
10040 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10041 + ": received=" + b.intent.received
10042 + " apps=" + b.intent.apps.size()
10043 + " doRebind=" + b.intent.doRebind);
10044
10045 if (s.app != null && b.intent.received) {
10046 // Service is already running, so we can immediately
10047 // publish the connection.
10048 try {
10049 c.conn.connected(s.name, b.intent.binder);
10050 } catch (Exception e) {
10051 Log.w(TAG, "Failure sending service " + s.shortName
10052 + " to connection " + c.conn.asBinder()
10053 + " (in " + c.binding.client.processName + ")", e);
10054 }
10055
10056 // If this is the first app connected back to this binding,
10057 // and the service had previously asked to be told when
10058 // rebound, then do so.
10059 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10060 requestServiceBindingLocked(s, b.intent, true);
10061 }
10062 } else if (!b.intent.requested) {
10063 requestServiceBindingLocked(s, b.intent, false);
10064 }
10065
10066 Binder.restoreCallingIdentity(origId);
10067 }
10068
10069 return 1;
10070 }
10071
10072 private void removeConnectionLocked(
10073 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10074 IBinder binder = c.conn.asBinder();
10075 AppBindRecord b = c.binding;
10076 ServiceRecord s = b.service;
10077 s.connections.remove(binder);
10078 b.connections.remove(c);
10079 if (c.activity != null && c.activity != skipAct) {
10080 if (c.activity.connections != null) {
10081 c.activity.connections.remove(c);
10082 }
10083 }
10084 if (b.client != skipApp) {
10085 b.client.connections.remove(c);
10086 }
10087 mServiceConnections.remove(binder);
10088
10089 if (b.connections.size() == 0) {
10090 b.intent.apps.remove(b.client);
10091 }
10092
10093 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10094 + ": shouldUnbind=" + b.intent.hasBound);
10095 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10096 && b.intent.hasBound) {
10097 try {
10098 bumpServiceExecutingLocked(s);
10099 updateOomAdjLocked(s.app);
10100 b.intent.hasBound = false;
10101 // Assume the client doesn't want to know about a rebind;
10102 // we will deal with that later if it asks for one.
10103 b.intent.doRebind = false;
10104 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10105 } catch (Exception e) {
10106 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10107 serviceDoneExecutingLocked(s, true);
10108 }
10109 }
10110
10111 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10112 bringDownServiceLocked(s, false);
10113 }
10114 }
10115
10116 public boolean unbindService(IServiceConnection connection) {
10117 synchronized (this) {
10118 IBinder binder = connection.asBinder();
10119 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10120 ConnectionRecord r = mServiceConnections.get(binder);
10121 if (r == null) {
10122 Log.w(TAG, "Unbind failed: could not find connection for "
10123 + connection.asBinder());
10124 return false;
10125 }
10126
10127 final long origId = Binder.clearCallingIdentity();
10128
10129 removeConnectionLocked(r, null, null);
10130
10131 if (r.binding.service.app != null) {
10132 // This could have made the service less important.
10133 updateOomAdjLocked(r.binding.service.app);
10134 }
10135
10136 Binder.restoreCallingIdentity(origId);
10137 }
10138
10139 return true;
10140 }
10141
10142 public void publishService(IBinder token, Intent intent, IBinder service) {
10143 // Refuse possible leaked file descriptors
10144 if (intent != null && intent.hasFileDescriptors() == true) {
10145 throw new IllegalArgumentException("File descriptors passed in Intent");
10146 }
10147
10148 synchronized(this) {
10149 if (!(token instanceof ServiceRecord)) {
10150 throw new IllegalArgumentException("Invalid service token");
10151 }
10152 ServiceRecord r = (ServiceRecord)token;
10153
10154 final long origId = Binder.clearCallingIdentity();
10155
10156 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10157 + " " + intent + ": " + service);
10158 if (r != null) {
10159 Intent.FilterComparison filter
10160 = new Intent.FilterComparison(intent);
10161 IntentBindRecord b = r.bindings.get(filter);
10162 if (b != null && !b.received) {
10163 b.binder = service;
10164 b.requested = true;
10165 b.received = true;
10166 if (r.connections.size() > 0) {
10167 Iterator<ConnectionRecord> it
10168 = r.connections.values().iterator();
10169 while (it.hasNext()) {
10170 ConnectionRecord c = it.next();
10171 if (!filter.equals(c.binding.intent.intent)) {
10172 if (DEBUG_SERVICE) Log.v(
10173 TAG, "Not publishing to: " + c);
10174 if (DEBUG_SERVICE) Log.v(
10175 TAG, "Bound intent: " + c.binding.intent.intent);
10176 if (DEBUG_SERVICE) Log.v(
10177 TAG, "Published intent: " + intent);
10178 continue;
10179 }
10180 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10181 try {
10182 c.conn.connected(r.name, service);
10183 } catch (Exception e) {
10184 Log.w(TAG, "Failure sending service " + r.name +
10185 " to connection " + c.conn.asBinder() +
10186 " (in " + c.binding.client.processName + ")", e);
10187 }
10188 }
10189 }
10190 }
10191
10192 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10193
10194 Binder.restoreCallingIdentity(origId);
10195 }
10196 }
10197 }
10198
10199 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10200 // Refuse possible leaked file descriptors
10201 if (intent != null && intent.hasFileDescriptors() == true) {
10202 throw new IllegalArgumentException("File descriptors passed in Intent");
10203 }
10204
10205 synchronized(this) {
10206 if (!(token instanceof ServiceRecord)) {
10207 throw new IllegalArgumentException("Invalid service token");
10208 }
10209 ServiceRecord r = (ServiceRecord)token;
10210
10211 final long origId = Binder.clearCallingIdentity();
10212
10213 if (r != null) {
10214 Intent.FilterComparison filter
10215 = new Intent.FilterComparison(intent);
10216 IntentBindRecord b = r.bindings.get(filter);
10217 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10218 + " at " + b + ": apps="
10219 + (b != null ? b.apps.size() : 0));
10220 if (b != null) {
10221 if (b.apps.size() > 0) {
10222 // Applications have already bound since the last
10223 // unbind, so just rebind right here.
10224 requestServiceBindingLocked(r, b, true);
10225 } else {
10226 // Note to tell the service the next time there is
10227 // a new client.
10228 b.doRebind = true;
10229 }
10230 }
10231
10232 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10233
10234 Binder.restoreCallingIdentity(origId);
10235 }
10236 }
10237 }
10238
10239 public void serviceDoneExecuting(IBinder token) {
10240 synchronized(this) {
10241 if (!(token instanceof ServiceRecord)) {
10242 throw new IllegalArgumentException("Invalid service token");
10243 }
10244 ServiceRecord r = (ServiceRecord)token;
10245 boolean inStopping = mStoppingServices.contains(token);
10246 if (r != null) {
10247 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10248 + ": nesting=" + r.executeNesting
10249 + ", inStopping=" + inStopping);
10250 if (r != token) {
10251 Log.w(TAG, "Done executing service " + r.name
10252 + " with incorrect token: given " + token
10253 + ", expected " + r);
10254 return;
10255 }
10256
10257 final long origId = Binder.clearCallingIdentity();
10258 serviceDoneExecutingLocked(r, inStopping);
10259 Binder.restoreCallingIdentity(origId);
10260 } else {
10261 Log.w(TAG, "Done executing unknown service " + r.name
10262 + " with token " + token);
10263 }
10264 }
10265 }
10266
10267 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10268 r.executeNesting--;
10269 if (r.executeNesting <= 0 && r.app != null) {
10270 r.app.executingServices.remove(r);
10271 if (r.app.executingServices.size() == 0) {
10272 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10273 }
10274 if (inStopping) {
10275 mStoppingServices.remove(r);
10276 }
10277 updateOomAdjLocked(r.app);
10278 }
10279 }
10280
10281 void serviceTimeout(ProcessRecord proc) {
10282 synchronized(this) {
10283 if (proc.executingServices.size() == 0 || proc.thread == null) {
10284 return;
10285 }
10286 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10287 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10288 ServiceRecord timeout = null;
10289 long nextTime = 0;
10290 while (it.hasNext()) {
10291 ServiceRecord sr = it.next();
10292 if (sr.executingStart < maxTime) {
10293 timeout = sr;
10294 break;
10295 }
10296 if (sr.executingStart > nextTime) {
10297 nextTime = sr.executingStart;
10298 }
10299 }
10300 if (timeout != null && mLRUProcesses.contains(proc)) {
10301 Log.w(TAG, "Timeout executing service: " + timeout);
10302 appNotRespondingLocked(proc, null, "Executing service "
10303 + timeout.name);
10304 } else {
10305 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10306 msg.obj = proc;
10307 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10308 }
10309 }
10310 }
10311
10312 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010313 // BACKUP AND RESTORE
10314 // =========================================================
10315
10316 // Cause the target app to be launched if necessary and its backup agent
10317 // instantiated. The backup agent will invoke backupAgentCreated() on the
10318 // activity manager to announce its creation.
10319 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10320 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10321 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10322
10323 synchronized(this) {
10324 // !!! TODO: currently no check here that we're already bound
10325 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10326 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10327 synchronized (stats) {
10328 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10329 }
10330
10331 BackupRecord r = new BackupRecord(ss, app, backupMode);
10332 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10333 // startProcessLocked() returns existing proc's record if it's already running
10334 ProcessRecord proc = startProcessLocked(app.processName, app,
10335 false, 0, "backup", hostingName);
10336 if (proc == null) {
10337 Log.e(TAG, "Unable to start backup agent process " + r);
10338 return false;
10339 }
10340
10341 r.app = proc;
10342 mBackupTarget = r;
10343 mBackupAppName = app.packageName;
10344
Christopher Tate6fa95972009-06-05 18:43:55 -070010345 // Try not to kill the process during backup
10346 updateOomAdjLocked(proc);
10347
Christopher Tate181fafa2009-05-14 11:12:14 -070010348 // If the process is already attached, schedule the creation of the backup agent now.
10349 // If it is not yet live, this will be done when it attaches to the framework.
10350 if (proc.thread != null) {
10351 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10352 try {
10353 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10354 } catch (RemoteException e) {
10355 // !!! TODO: notify the backup manager that we crashed, or rely on
10356 // death notices, or...?
10357 }
10358 } else {
10359 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10360 }
10361 // Invariants: at this point, the target app process exists and the application
10362 // is either already running or in the process of coming up. mBackupTarget and
10363 // mBackupAppName describe the app, so that when it binds back to the AM we
10364 // know that it's scheduled for a backup-agent operation.
10365 }
10366
10367 return true;
10368 }
10369
10370 // A backup agent has just come up
10371 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10372 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10373 + " = " + agent);
10374
10375 synchronized(this) {
10376 if (!agentPackageName.equals(mBackupAppName)) {
10377 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10378 return;
10379 }
10380
Christopher Tate043dadc2009-06-02 16:11:00 -070010381 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010382 try {
10383 IBackupManager bm = IBackupManager.Stub.asInterface(
10384 ServiceManager.getService(Context.BACKUP_SERVICE));
10385 bm.agentConnected(agentPackageName, agent);
10386 } catch (RemoteException e) {
10387 // can't happen; the backup manager service is local
10388 } catch (Exception e) {
10389 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10390 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010391 } finally {
10392 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010393 }
10394 }
10395 }
10396
10397 // done with this agent
10398 public void unbindBackupAgent(ApplicationInfo appInfo) {
10399 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
10400
10401 synchronized(this) {
10402 if (!mBackupAppName.equals(appInfo.packageName)) {
10403 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10404 return;
10405 }
10406
Christopher Tate6fa95972009-06-05 18:43:55 -070010407 ProcessRecord proc = mBackupTarget.app;
10408 mBackupTarget = null;
10409 mBackupAppName = null;
10410
10411 // Not backing this app up any more; reset its OOM adjustment
10412 updateOomAdjLocked(proc);
10413
Christopher Tatec7b31e32009-06-10 15:49:30 -070010414 // If the app crashed during backup, 'thread' will be null here
10415 if (proc.thread != null) {
10416 try {
10417 proc.thread.scheduleDestroyBackupAgent(appInfo);
10418 } catch (Exception e) {
10419 Log.e(TAG, "Exception when unbinding backup agent:");
10420 e.printStackTrace();
10421 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010422 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010423 }
10424 }
10425 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010426 // BROADCASTS
10427 // =========================================================
10428
10429 private final List getStickies(String action, IntentFilter filter,
10430 List cur) {
10431 final ContentResolver resolver = mContext.getContentResolver();
10432 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10433 if (list == null) {
10434 return cur;
10435 }
10436 int N = list.size();
10437 for (int i=0; i<N; i++) {
10438 Intent intent = list.get(i);
10439 if (filter.match(resolver, intent, true, TAG) >= 0) {
10440 if (cur == null) {
10441 cur = new ArrayList<Intent>();
10442 }
10443 cur.add(intent);
10444 }
10445 }
10446 return cur;
10447 }
10448
10449 private final void scheduleBroadcastsLocked() {
10450 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10451 + mBroadcastsScheduled);
10452
10453 if (mBroadcastsScheduled) {
10454 return;
10455 }
10456 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10457 mBroadcastsScheduled = true;
10458 }
10459
10460 public Intent registerReceiver(IApplicationThread caller,
10461 IIntentReceiver receiver, IntentFilter filter, String permission) {
10462 synchronized(this) {
10463 ProcessRecord callerApp = null;
10464 if (caller != null) {
10465 callerApp = getRecordForAppLocked(caller);
10466 if (callerApp == null) {
10467 throw new SecurityException(
10468 "Unable to find app for caller " + caller
10469 + " (pid=" + Binder.getCallingPid()
10470 + ") when registering receiver " + receiver);
10471 }
10472 }
10473
10474 List allSticky = null;
10475
10476 // Look for any matching sticky broadcasts...
10477 Iterator actions = filter.actionsIterator();
10478 if (actions != null) {
10479 while (actions.hasNext()) {
10480 String action = (String)actions.next();
10481 allSticky = getStickies(action, filter, allSticky);
10482 }
10483 } else {
10484 allSticky = getStickies(null, filter, allSticky);
10485 }
10486
10487 // The first sticky in the list is returned directly back to
10488 // the client.
10489 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10490
10491 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10492 + ": " + sticky);
10493
10494 if (receiver == null) {
10495 return sticky;
10496 }
10497
10498 ReceiverList rl
10499 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10500 if (rl == null) {
10501 rl = new ReceiverList(this, callerApp,
10502 Binder.getCallingPid(),
10503 Binder.getCallingUid(), receiver);
10504 if (rl.app != null) {
10505 rl.app.receivers.add(rl);
10506 } else {
10507 try {
10508 receiver.asBinder().linkToDeath(rl, 0);
10509 } catch (RemoteException e) {
10510 return sticky;
10511 }
10512 rl.linkedToDeath = true;
10513 }
10514 mRegisteredReceivers.put(receiver.asBinder(), rl);
10515 }
10516 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10517 rl.add(bf);
10518 if (!bf.debugCheck()) {
10519 Log.w(TAG, "==> For Dynamic broadast");
10520 }
10521 mReceiverResolver.addFilter(bf);
10522
10523 // Enqueue broadcasts for all existing stickies that match
10524 // this filter.
10525 if (allSticky != null) {
10526 ArrayList receivers = new ArrayList();
10527 receivers.add(bf);
10528
10529 int N = allSticky.size();
10530 for (int i=0; i<N; i++) {
10531 Intent intent = (Intent)allSticky.get(i);
10532 BroadcastRecord r = new BroadcastRecord(intent, null,
10533 null, -1, -1, null, receivers, null, 0, null, null,
10534 false);
10535 if (mParallelBroadcasts.size() == 0) {
10536 scheduleBroadcastsLocked();
10537 }
10538 mParallelBroadcasts.add(r);
10539 }
10540 }
10541
10542 return sticky;
10543 }
10544 }
10545
10546 public void unregisterReceiver(IIntentReceiver receiver) {
10547 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10548
10549 boolean doNext = false;
10550
10551 synchronized(this) {
10552 ReceiverList rl
10553 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10554 if (rl != null) {
10555 if (rl.curBroadcast != null) {
10556 BroadcastRecord r = rl.curBroadcast;
10557 doNext = finishReceiverLocked(
10558 receiver.asBinder(), r.resultCode, r.resultData,
10559 r.resultExtras, r.resultAbort, true);
10560 }
10561
10562 if (rl.app != null) {
10563 rl.app.receivers.remove(rl);
10564 }
10565 removeReceiverLocked(rl);
10566 if (rl.linkedToDeath) {
10567 rl.linkedToDeath = false;
10568 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10569 }
10570 }
10571 }
10572
10573 if (!doNext) {
10574 return;
10575 }
10576
10577 final long origId = Binder.clearCallingIdentity();
10578 processNextBroadcast(false);
10579 trimApplications();
10580 Binder.restoreCallingIdentity(origId);
10581 }
10582
10583 void removeReceiverLocked(ReceiverList rl) {
10584 mRegisteredReceivers.remove(rl.receiver.asBinder());
10585 int N = rl.size();
10586 for (int i=0; i<N; i++) {
10587 mReceiverResolver.removeFilter(rl.get(i));
10588 }
10589 }
10590
10591 private final int broadcastIntentLocked(ProcessRecord callerApp,
10592 String callerPackage, Intent intent, String resolvedType,
10593 IIntentReceiver resultTo, int resultCode, String resultData,
10594 Bundle map, String requiredPermission,
10595 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10596 intent = new Intent(intent);
10597
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010598 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010599 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10600 + " ordered=" + ordered);
10601 if ((resultTo != null) && !ordered) {
10602 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10603 }
10604
10605 // Handle special intents: if this broadcast is from the package
10606 // manager about a package being removed, we need to remove all of
10607 // its activities from the history stack.
10608 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10609 intent.getAction());
10610 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10611 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10612 || uidRemoved) {
10613 if (checkComponentPermission(
10614 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10615 callingPid, callingUid, -1)
10616 == PackageManager.PERMISSION_GRANTED) {
10617 if (uidRemoved) {
10618 final Bundle intentExtras = intent.getExtras();
10619 final int uid = intentExtras != null
10620 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10621 if (uid >= 0) {
10622 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10623 synchronized (bs) {
10624 bs.removeUidStatsLocked(uid);
10625 }
10626 }
10627 } else {
10628 Uri data = intent.getData();
10629 String ssp;
10630 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10631 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10632 uninstallPackageLocked(ssp,
10633 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
10634 }
10635 }
10636 }
10637 } else {
10638 String msg = "Permission Denial: " + intent.getAction()
10639 + " broadcast from " + callerPackage + " (pid=" + callingPid
10640 + ", uid=" + callingUid + ")"
10641 + " requires "
10642 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10643 Log.w(TAG, msg);
10644 throw new SecurityException(msg);
10645 }
10646 }
10647
10648 /*
10649 * If this is the time zone changed action, queue up a message that will reset the timezone
10650 * of all currently running processes. This message will get queued up before the broadcast
10651 * happens.
10652 */
10653 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10654 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10655 }
10656
10657 // Add to the sticky list if requested.
10658 if (sticky) {
10659 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10660 callingPid, callingUid)
10661 != PackageManager.PERMISSION_GRANTED) {
10662 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10663 + callingPid + ", uid=" + callingUid
10664 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10665 Log.w(TAG, msg);
10666 throw new SecurityException(msg);
10667 }
10668 if (requiredPermission != null) {
10669 Log.w(TAG, "Can't broadcast sticky intent " + intent
10670 + " and enforce permission " + requiredPermission);
10671 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10672 }
10673 if (intent.getComponent() != null) {
10674 throw new SecurityException(
10675 "Sticky broadcasts can't target a specific component");
10676 }
10677 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10678 if (list == null) {
10679 list = new ArrayList<Intent>();
10680 mStickyBroadcasts.put(intent.getAction(), list);
10681 }
10682 int N = list.size();
10683 int i;
10684 for (i=0; i<N; i++) {
10685 if (intent.filterEquals(list.get(i))) {
10686 // This sticky already exists, replace it.
10687 list.set(i, new Intent(intent));
10688 break;
10689 }
10690 }
10691 if (i >= N) {
10692 list.add(new Intent(intent));
10693 }
10694 }
10695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010696 // Figure out who all will receive this broadcast.
10697 List receivers = null;
10698 List<BroadcastFilter> registeredReceivers = null;
10699 try {
10700 if (intent.getComponent() != null) {
10701 // Broadcast is going to one specific receiver class...
10702 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010703 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010704 if (ai != null) {
10705 receivers = new ArrayList();
10706 ResolveInfo ri = new ResolveInfo();
10707 ri.activityInfo = ai;
10708 receivers.add(ri);
10709 }
10710 } else {
10711 // Need to resolve the intent to interested receivers...
10712 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10713 == 0) {
10714 receivers =
10715 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010716 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010717 }
Mihai Preda074edef2009-05-18 17:13:31 +020010718 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010719 }
10720 } catch (RemoteException ex) {
10721 // pm is in same process, this will never happen.
10722 }
10723
10724 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10725 if (!ordered && NR > 0) {
10726 // If we are not serializing this broadcast, then send the
10727 // registered receivers separately so they don't wait for the
10728 // components to be launched.
10729 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10730 callerPackage, callingPid, callingUid, requiredPermission,
10731 registeredReceivers, resultTo, resultCode, resultData, map,
10732 ordered);
10733 if (DEBUG_BROADCAST) Log.v(
10734 TAG, "Enqueueing parallel broadcast " + r
10735 + ": prev had " + mParallelBroadcasts.size());
10736 mParallelBroadcasts.add(r);
10737 scheduleBroadcastsLocked();
10738 registeredReceivers = null;
10739 NR = 0;
10740 }
10741
10742 // Merge into one list.
10743 int ir = 0;
10744 if (receivers != null) {
10745 // A special case for PACKAGE_ADDED: do not allow the package
10746 // being added to see this broadcast. This prevents them from
10747 // using this as a back door to get run as soon as they are
10748 // installed. Maybe in the future we want to have a special install
10749 // broadcast or such for apps, but we'd like to deliberately make
10750 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010751 boolean skip = false;
10752 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010753 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010754 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10755 skip = true;
10756 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10757 skip = true;
10758 }
10759 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010760 ? intent.getData().getSchemeSpecificPart()
10761 : null;
10762 if (skipPackage != null && receivers != null) {
10763 int NT = receivers.size();
10764 for (int it=0; it<NT; it++) {
10765 ResolveInfo curt = (ResolveInfo)receivers.get(it);
10766 if (curt.activityInfo.packageName.equals(skipPackage)) {
10767 receivers.remove(it);
10768 it--;
10769 NT--;
10770 }
10771 }
10772 }
10773
10774 int NT = receivers != null ? receivers.size() : 0;
10775 int it = 0;
10776 ResolveInfo curt = null;
10777 BroadcastFilter curr = null;
10778 while (it < NT && ir < NR) {
10779 if (curt == null) {
10780 curt = (ResolveInfo)receivers.get(it);
10781 }
10782 if (curr == null) {
10783 curr = registeredReceivers.get(ir);
10784 }
10785 if (curr.getPriority() >= curt.priority) {
10786 // Insert this broadcast record into the final list.
10787 receivers.add(it, curr);
10788 ir++;
10789 curr = null;
10790 it++;
10791 NT++;
10792 } else {
10793 // Skip to the next ResolveInfo in the final list.
10794 it++;
10795 curt = null;
10796 }
10797 }
10798 }
10799 while (ir < NR) {
10800 if (receivers == null) {
10801 receivers = new ArrayList();
10802 }
10803 receivers.add(registeredReceivers.get(ir));
10804 ir++;
10805 }
10806
10807 if ((receivers != null && receivers.size() > 0)
10808 || resultTo != null) {
10809 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10810 callerPackage, callingPid, callingUid, requiredPermission,
10811 receivers, resultTo, resultCode, resultData, map, ordered);
10812 if (DEBUG_BROADCAST) Log.v(
10813 TAG, "Enqueueing ordered broadcast " + r
10814 + ": prev had " + mOrderedBroadcasts.size());
10815 if (DEBUG_BROADCAST) {
10816 int seq = r.intent.getIntExtra("seq", -1);
10817 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
10818 }
10819 mOrderedBroadcasts.add(r);
10820 scheduleBroadcastsLocked();
10821 }
10822
10823 return BROADCAST_SUCCESS;
10824 }
10825
10826 public final int broadcastIntent(IApplicationThread caller,
10827 Intent intent, String resolvedType, IIntentReceiver resultTo,
10828 int resultCode, String resultData, Bundle map,
10829 String requiredPermission, boolean serialized, boolean sticky) {
10830 // Refuse possible leaked file descriptors
10831 if (intent != null && intent.hasFileDescriptors() == true) {
10832 throw new IllegalArgumentException("File descriptors passed in Intent");
10833 }
10834
10835 synchronized(this) {
10836 if (!mSystemReady) {
10837 // if the caller really truly claims to know what they're doing, go
10838 // ahead and allow the broadcast without launching any receivers
10839 int flags = intent.getFlags();
10840 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
10841 intent = new Intent(intent);
10842 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
10843 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
10844 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
10845 + " before boot completion");
10846 throw new IllegalStateException("Cannot broadcast before boot completed");
10847 }
10848 }
10849
10850 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10851 final int callingPid = Binder.getCallingPid();
10852 final int callingUid = Binder.getCallingUid();
10853 final long origId = Binder.clearCallingIdentity();
10854 int res = broadcastIntentLocked(callerApp,
10855 callerApp != null ? callerApp.info.packageName : null,
10856 intent, resolvedType, resultTo,
10857 resultCode, resultData, map, requiredPermission, serialized,
10858 sticky, callingPid, callingUid);
10859 Binder.restoreCallingIdentity(origId);
10860 return res;
10861 }
10862 }
10863
10864 int broadcastIntentInPackage(String packageName, int uid,
10865 Intent intent, String resolvedType, IIntentReceiver resultTo,
10866 int resultCode, String resultData, Bundle map,
10867 String requiredPermission, boolean serialized, boolean sticky) {
10868 synchronized(this) {
10869 final long origId = Binder.clearCallingIdentity();
10870 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
10871 resultTo, resultCode, resultData, map, requiredPermission,
10872 serialized, sticky, -1, uid);
10873 Binder.restoreCallingIdentity(origId);
10874 return res;
10875 }
10876 }
10877
10878 public final void unbroadcastIntent(IApplicationThread caller,
10879 Intent intent) {
10880 // Refuse possible leaked file descriptors
10881 if (intent != null && intent.hasFileDescriptors() == true) {
10882 throw new IllegalArgumentException("File descriptors passed in Intent");
10883 }
10884
10885 synchronized(this) {
10886 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
10887 != PackageManager.PERMISSION_GRANTED) {
10888 String msg = "Permission Denial: unbroadcastIntent() from pid="
10889 + Binder.getCallingPid()
10890 + ", uid=" + Binder.getCallingUid()
10891 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10892 Log.w(TAG, msg);
10893 throw new SecurityException(msg);
10894 }
10895 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10896 if (list != null) {
10897 int N = list.size();
10898 int i;
10899 for (i=0; i<N; i++) {
10900 if (intent.filterEquals(list.get(i))) {
10901 list.remove(i);
10902 break;
10903 }
10904 }
10905 }
10906 }
10907 }
10908
10909 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
10910 String resultData, Bundle resultExtras, boolean resultAbort,
10911 boolean explicit) {
10912 if (mOrderedBroadcasts.size() == 0) {
10913 if (explicit) {
10914 Log.w(TAG, "finishReceiver called but no pending broadcasts");
10915 }
10916 return false;
10917 }
10918 BroadcastRecord r = mOrderedBroadcasts.get(0);
10919 if (r.receiver == null) {
10920 if (explicit) {
10921 Log.w(TAG, "finishReceiver called but none active");
10922 }
10923 return false;
10924 }
10925 if (r.receiver != receiver) {
10926 Log.w(TAG, "finishReceiver called but active receiver is different");
10927 return false;
10928 }
10929 int state = r.state;
10930 r.state = r.IDLE;
10931 if (state == r.IDLE) {
10932 if (explicit) {
10933 Log.w(TAG, "finishReceiver called but state is IDLE");
10934 }
10935 }
10936 r.receiver = null;
10937 r.intent.setComponent(null);
10938 if (r.curApp != null) {
10939 r.curApp.curReceiver = null;
10940 }
10941 if (r.curFilter != null) {
10942 r.curFilter.receiverList.curBroadcast = null;
10943 }
10944 r.curFilter = null;
10945 r.curApp = null;
10946 r.curComponent = null;
10947 r.curReceiver = null;
10948 mPendingBroadcast = null;
10949
10950 r.resultCode = resultCode;
10951 r.resultData = resultData;
10952 r.resultExtras = resultExtras;
10953 r.resultAbort = resultAbort;
10954
10955 // We will process the next receiver right now if this is finishing
10956 // an app receiver (which is always asynchronous) or after we have
10957 // come back from calling a receiver.
10958 return state == BroadcastRecord.APP_RECEIVE
10959 || state == BroadcastRecord.CALL_DONE_RECEIVE;
10960 }
10961
10962 public void finishReceiver(IBinder who, int resultCode, String resultData,
10963 Bundle resultExtras, boolean resultAbort) {
10964 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
10965
10966 // Refuse possible leaked file descriptors
10967 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
10968 throw new IllegalArgumentException("File descriptors passed in Bundle");
10969 }
10970
10971 boolean doNext;
10972
10973 final long origId = Binder.clearCallingIdentity();
10974
10975 synchronized(this) {
10976 doNext = finishReceiverLocked(
10977 who, resultCode, resultData, resultExtras, resultAbort, true);
10978 }
10979
10980 if (doNext) {
10981 processNextBroadcast(false);
10982 }
10983 trimApplications();
10984
10985 Binder.restoreCallingIdentity(origId);
10986 }
10987
10988 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
10989 if (r.nextReceiver > 0) {
10990 Object curReceiver = r.receivers.get(r.nextReceiver-1);
10991 if (curReceiver instanceof BroadcastFilter) {
10992 BroadcastFilter bf = (BroadcastFilter) curReceiver;
10993 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
10994 System.identityHashCode(r),
10995 r.intent.getAction(),
10996 r.nextReceiver - 1,
10997 System.identityHashCode(bf));
10998 } else {
10999 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11000 System.identityHashCode(r),
11001 r.intent.getAction(),
11002 r.nextReceiver - 1,
11003 ((ResolveInfo)curReceiver).toString());
11004 }
11005 } else {
11006 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11007 + r);
11008 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11009 System.identityHashCode(r),
11010 r.intent.getAction(),
11011 r.nextReceiver,
11012 "NONE");
11013 }
11014 }
11015
11016 private final void broadcastTimeout() {
11017 synchronized (this) {
11018 if (mOrderedBroadcasts.size() == 0) {
11019 return;
11020 }
11021 long now = SystemClock.uptimeMillis();
11022 BroadcastRecord r = mOrderedBroadcasts.get(0);
11023 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11024 if (DEBUG_BROADCAST) Log.v(TAG,
11025 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11026 + (r.startTime + BROADCAST_TIMEOUT));
11027 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11028 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11029 return;
11030 }
11031
11032 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11033 r.startTime = now;
11034 r.anrCount++;
11035
11036 // Current receiver has passed its expiration date.
11037 if (r.nextReceiver <= 0) {
11038 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11039 return;
11040 }
11041
11042 ProcessRecord app = null;
11043
11044 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11045 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11046 logBroadcastReceiverDiscard(r);
11047 if (curReceiver instanceof BroadcastFilter) {
11048 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11049 if (bf.receiverList.pid != 0
11050 && bf.receiverList.pid != MY_PID) {
11051 synchronized (this.mPidsSelfLocked) {
11052 app = this.mPidsSelfLocked.get(
11053 bf.receiverList.pid);
11054 }
11055 }
11056 } else {
11057 app = r.curApp;
11058 }
11059
11060 if (app != null) {
11061 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11062 }
11063
11064 if (mPendingBroadcast == r) {
11065 mPendingBroadcast = null;
11066 }
11067
11068 // Move on to the next receiver.
11069 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11070 r.resultExtras, r.resultAbort, true);
11071 scheduleBroadcastsLocked();
11072 }
11073 }
11074
11075 private final void processCurBroadcastLocked(BroadcastRecord r,
11076 ProcessRecord app) throws RemoteException {
11077 if (app.thread == null) {
11078 throw new RemoteException();
11079 }
11080 r.receiver = app.thread.asBinder();
11081 r.curApp = app;
11082 app.curReceiver = r;
11083 updateLRUListLocked(app, true);
11084
11085 // Tell the application to launch this receiver.
11086 r.intent.setComponent(r.curComponent);
11087
11088 boolean started = false;
11089 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011090 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011091 "Delivering to component " + r.curComponent
11092 + ": " + r);
11093 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11094 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11095 started = true;
11096 } finally {
11097 if (!started) {
11098 r.receiver = null;
11099 r.curApp = null;
11100 app.curReceiver = null;
11101 }
11102 }
11103
11104 }
11105
11106 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11107 Intent intent, int resultCode, String data,
11108 Bundle extras, boolean ordered) throws RemoteException {
11109 if (app != null && app.thread != null) {
11110 // If we have an app thread, do the call through that so it is
11111 // correctly ordered with other one-way calls.
11112 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11113 data, extras, ordered);
11114 } else {
11115 receiver.performReceive(intent, resultCode, data, extras, ordered);
11116 }
11117 }
11118
11119 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11120 BroadcastFilter filter, boolean ordered) {
11121 boolean skip = false;
11122 if (filter.requiredPermission != null) {
11123 int perm = checkComponentPermission(filter.requiredPermission,
11124 r.callingPid, r.callingUid, -1);
11125 if (perm != PackageManager.PERMISSION_GRANTED) {
11126 Log.w(TAG, "Permission Denial: broadcasting "
11127 + r.intent.toString()
11128 + " from " + r.callerPackage + " (pid="
11129 + r.callingPid + ", uid=" + r.callingUid + ")"
11130 + " requires " + filter.requiredPermission
11131 + " due to registered receiver " + filter);
11132 skip = true;
11133 }
11134 }
11135 if (r.requiredPermission != null) {
11136 int perm = checkComponentPermission(r.requiredPermission,
11137 filter.receiverList.pid, filter.receiverList.uid, -1);
11138 if (perm != PackageManager.PERMISSION_GRANTED) {
11139 Log.w(TAG, "Permission Denial: receiving "
11140 + r.intent.toString()
11141 + " to " + filter.receiverList.app
11142 + " (pid=" + filter.receiverList.pid
11143 + ", uid=" + filter.receiverList.uid + ")"
11144 + " requires " + r.requiredPermission
11145 + " due to sender " + r.callerPackage
11146 + " (uid " + r.callingUid + ")");
11147 skip = true;
11148 }
11149 }
11150
11151 if (!skip) {
11152 // If this is not being sent as an ordered broadcast, then we
11153 // don't want to touch the fields that keep track of the current
11154 // state of ordered broadcasts.
11155 if (ordered) {
11156 r.receiver = filter.receiverList.receiver.asBinder();
11157 r.curFilter = filter;
11158 filter.receiverList.curBroadcast = r;
11159 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011160 if (filter.receiverList.app != null) {
11161 // Bump hosting application to no longer be in background
11162 // scheduling class. Note that we can't do that if there
11163 // isn't an app... but we can only be in that case for
11164 // things that directly call the IActivityManager API, which
11165 // are already core system stuff so don't matter for this.
11166 r.curApp = filter.receiverList.app;
11167 filter.receiverList.app.curReceiver = r;
11168 updateOomAdjLocked();
11169 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011170 }
11171 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011172 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011173 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011174 Log.i(TAG, "Delivering to " + filter.receiverList.app
11175 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011176 }
11177 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11178 new Intent(r.intent), r.resultCode,
11179 r.resultData, r.resultExtras, r.ordered);
11180 if (ordered) {
11181 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11182 }
11183 } catch (RemoteException e) {
11184 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11185 if (ordered) {
11186 r.receiver = null;
11187 r.curFilter = null;
11188 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011189 if (filter.receiverList.app != null) {
11190 filter.receiverList.app.curReceiver = null;
11191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011192 }
11193 }
11194 }
11195 }
11196
11197 private final void processNextBroadcast(boolean fromMsg) {
11198 synchronized(this) {
11199 BroadcastRecord r;
11200
11201 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11202 + mParallelBroadcasts.size() + " broadcasts, "
11203 + mOrderedBroadcasts.size() + " serialized broadcasts");
11204
11205 updateCpuStats();
11206
11207 if (fromMsg) {
11208 mBroadcastsScheduled = false;
11209 }
11210
11211 // First, deliver any non-serialized broadcasts right away.
11212 while (mParallelBroadcasts.size() > 0) {
11213 r = mParallelBroadcasts.remove(0);
11214 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011215 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11216 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011217 for (int i=0; i<N; i++) {
11218 Object target = r.receivers.get(i);
11219 if (DEBUG_BROADCAST) Log.v(TAG,
11220 "Delivering non-serialized to registered "
11221 + target + ": " + r);
11222 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11223 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011224 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11225 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011226 }
11227
11228 // Now take care of the next serialized one...
11229
11230 // If we are waiting for a process to come up to handle the next
11231 // broadcast, then do nothing at this point. Just in case, we
11232 // check that the process we're waiting for still exists.
11233 if (mPendingBroadcast != null) {
11234 Log.i(TAG, "processNextBroadcast: waiting for "
11235 + mPendingBroadcast.curApp);
11236
11237 boolean isDead;
11238 synchronized (mPidsSelfLocked) {
11239 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11240 }
11241 if (!isDead) {
11242 // It's still alive, so keep waiting
11243 return;
11244 } else {
11245 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11246 + " died before responding to broadcast");
11247 mPendingBroadcast = null;
11248 }
11249 }
11250
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011251 boolean looped = false;
11252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011253 do {
11254 if (mOrderedBroadcasts.size() == 0) {
11255 // No more broadcasts pending, so all done!
11256 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011257 if (looped) {
11258 // If we had finished the last ordered broadcast, then
11259 // make sure all processes have correct oom and sched
11260 // adjustments.
11261 updateOomAdjLocked();
11262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011263 return;
11264 }
11265 r = mOrderedBroadcasts.get(0);
11266 boolean forceReceive = false;
11267
11268 // Ensure that even if something goes awry with the timeout
11269 // detection, we catch "hung" broadcasts here, discard them,
11270 // and continue to make progress.
11271 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11272 long now = SystemClock.uptimeMillis();
11273 if (r.dispatchTime > 0) {
11274 if ((numReceivers > 0) &&
11275 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11276 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11277 + " now=" + now
11278 + " dispatchTime=" + r.dispatchTime
11279 + " startTime=" + r.startTime
11280 + " intent=" + r.intent
11281 + " numReceivers=" + numReceivers
11282 + " nextReceiver=" + r.nextReceiver
11283 + " state=" + r.state);
11284 broadcastTimeout(); // forcibly finish this broadcast
11285 forceReceive = true;
11286 r.state = BroadcastRecord.IDLE;
11287 }
11288 }
11289
11290 if (r.state != BroadcastRecord.IDLE) {
11291 if (DEBUG_BROADCAST) Log.d(TAG,
11292 "processNextBroadcast() called when not idle (state="
11293 + r.state + ")");
11294 return;
11295 }
11296
11297 if (r.receivers == null || r.nextReceiver >= numReceivers
11298 || r.resultAbort || forceReceive) {
11299 // No more receivers for this broadcast! Send the final
11300 // result if requested...
11301 if (r.resultTo != null) {
11302 try {
11303 if (DEBUG_BROADCAST) {
11304 int seq = r.intent.getIntExtra("seq", -1);
11305 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11306 + " seq=" + seq + " app=" + r.callerApp);
11307 }
11308 performReceive(r.callerApp, r.resultTo,
11309 new Intent(r.intent), r.resultCode,
11310 r.resultData, r.resultExtras, false);
11311 } catch (RemoteException e) {
11312 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11313 }
11314 }
11315
11316 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11317 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11318
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011319 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11320 + r);
11321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011322 // ... and on to the next...
11323 mOrderedBroadcasts.remove(0);
11324 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011325 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011326 continue;
11327 }
11328 } while (r == null);
11329
11330 // Get the next receiver...
11331 int recIdx = r.nextReceiver++;
11332
11333 // Keep track of when this receiver started, and make sure there
11334 // is a timeout message pending to kill it if need be.
11335 r.startTime = SystemClock.uptimeMillis();
11336 if (recIdx == 0) {
11337 r.dispatchTime = r.startTime;
11338
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011339 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11340 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011341 if (DEBUG_BROADCAST) Log.v(TAG,
11342 "Submitting BROADCAST_TIMEOUT_MSG for "
11343 + (r.startTime + BROADCAST_TIMEOUT));
11344 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11345 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11346 }
11347
11348 Object nextReceiver = r.receivers.get(recIdx);
11349 if (nextReceiver instanceof BroadcastFilter) {
11350 // Simple case: this is a registered receiver who gets
11351 // a direct call.
11352 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11353 if (DEBUG_BROADCAST) Log.v(TAG,
11354 "Delivering serialized to registered "
11355 + filter + ": " + r);
11356 deliverToRegisteredReceiver(r, filter, r.ordered);
11357 if (r.receiver == null || !r.ordered) {
11358 // The receiver has already finished, so schedule to
11359 // process the next one.
11360 r.state = BroadcastRecord.IDLE;
11361 scheduleBroadcastsLocked();
11362 }
11363 return;
11364 }
11365
11366 // Hard case: need to instantiate the receiver, possibly
11367 // starting its application process to host it.
11368
11369 ResolveInfo info =
11370 (ResolveInfo)nextReceiver;
11371
11372 boolean skip = false;
11373 int perm = checkComponentPermission(info.activityInfo.permission,
11374 r.callingPid, r.callingUid,
11375 info.activityInfo.exported
11376 ? -1 : info.activityInfo.applicationInfo.uid);
11377 if (perm != PackageManager.PERMISSION_GRANTED) {
11378 Log.w(TAG, "Permission Denial: broadcasting "
11379 + r.intent.toString()
11380 + " from " + r.callerPackage + " (pid=" + r.callingPid
11381 + ", uid=" + r.callingUid + ")"
11382 + " requires " + info.activityInfo.permission
11383 + " due to receiver " + info.activityInfo.packageName
11384 + "/" + info.activityInfo.name);
11385 skip = true;
11386 }
11387 if (r.callingUid != Process.SYSTEM_UID &&
11388 r.requiredPermission != null) {
11389 try {
11390 perm = ActivityThread.getPackageManager().
11391 checkPermission(r.requiredPermission,
11392 info.activityInfo.applicationInfo.packageName);
11393 } catch (RemoteException e) {
11394 perm = PackageManager.PERMISSION_DENIED;
11395 }
11396 if (perm != PackageManager.PERMISSION_GRANTED) {
11397 Log.w(TAG, "Permission Denial: receiving "
11398 + r.intent + " to "
11399 + info.activityInfo.applicationInfo.packageName
11400 + " requires " + r.requiredPermission
11401 + " due to sender " + r.callerPackage
11402 + " (uid " + r.callingUid + ")");
11403 skip = true;
11404 }
11405 }
11406 if (r.curApp != null && r.curApp.crashing) {
11407 // If the target process is crashing, just skip it.
11408 skip = true;
11409 }
11410
11411 if (skip) {
11412 r.receiver = null;
11413 r.curFilter = null;
11414 r.state = BroadcastRecord.IDLE;
11415 scheduleBroadcastsLocked();
11416 return;
11417 }
11418
11419 r.state = BroadcastRecord.APP_RECEIVE;
11420 String targetProcess = info.activityInfo.processName;
11421 r.curComponent = new ComponentName(
11422 info.activityInfo.applicationInfo.packageName,
11423 info.activityInfo.name);
11424 r.curReceiver = info.activityInfo;
11425
11426 // Is this receiver's application already running?
11427 ProcessRecord app = getProcessRecordLocked(targetProcess,
11428 info.activityInfo.applicationInfo.uid);
11429 if (app != null && app.thread != null) {
11430 try {
11431 processCurBroadcastLocked(r, app);
11432 return;
11433 } catch (RemoteException e) {
11434 Log.w(TAG, "Exception when sending broadcast to "
11435 + r.curComponent, e);
11436 }
11437
11438 // If a dead object exception was thrown -- fall through to
11439 // restart the application.
11440 }
11441
11442 // Not running -- get it started, and enqueue this history record
11443 // to be executed when the app comes up.
11444 if ((r.curApp=startProcessLocked(targetProcess,
11445 info.activityInfo.applicationInfo, true,
11446 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11447 "broadcast", r.curComponent)) == null) {
11448 // Ah, this recipient is unavailable. Finish it if necessary,
11449 // and mark the broadcast record as ready for the next.
11450 Log.w(TAG, "Unable to launch app "
11451 + info.activityInfo.applicationInfo.packageName + "/"
11452 + info.activityInfo.applicationInfo.uid + " for broadcast "
11453 + r.intent + ": process is bad");
11454 logBroadcastReceiverDiscard(r);
11455 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11456 r.resultExtras, r.resultAbort, true);
11457 scheduleBroadcastsLocked();
11458 r.state = BroadcastRecord.IDLE;
11459 return;
11460 }
11461
11462 mPendingBroadcast = r;
11463 }
11464 }
11465
11466 // =========================================================
11467 // INSTRUMENTATION
11468 // =========================================================
11469
11470 public boolean startInstrumentation(ComponentName className,
11471 String profileFile, int flags, Bundle arguments,
11472 IInstrumentationWatcher watcher) {
11473 // Refuse possible leaked file descriptors
11474 if (arguments != null && arguments.hasFileDescriptors()) {
11475 throw new IllegalArgumentException("File descriptors passed in Bundle");
11476 }
11477
11478 synchronized(this) {
11479 InstrumentationInfo ii = null;
11480 ApplicationInfo ai = null;
11481 try {
11482 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011483 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011484 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011485 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011486 } catch (PackageManager.NameNotFoundException e) {
11487 }
11488 if (ii == null) {
11489 reportStartInstrumentationFailure(watcher, className,
11490 "Unable to find instrumentation info for: " + className);
11491 return false;
11492 }
11493 if (ai == null) {
11494 reportStartInstrumentationFailure(watcher, className,
11495 "Unable to find instrumentation target package: " + ii.targetPackage);
11496 return false;
11497 }
11498
11499 int match = mContext.getPackageManager().checkSignatures(
11500 ii.targetPackage, ii.packageName);
11501 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11502 String msg = "Permission Denial: starting instrumentation "
11503 + className + " from pid="
11504 + Binder.getCallingPid()
11505 + ", uid=" + Binder.getCallingPid()
11506 + " not allowed because package " + ii.packageName
11507 + " does not have a signature matching the target "
11508 + ii.targetPackage;
11509 reportStartInstrumentationFailure(watcher, className, msg);
11510 throw new SecurityException(msg);
11511 }
11512
11513 final long origId = Binder.clearCallingIdentity();
11514 uninstallPackageLocked(ii.targetPackage, -1, true);
11515 ProcessRecord app = addAppLocked(ai);
11516 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011517 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011518 app.instrumentationProfileFile = profileFile;
11519 app.instrumentationArguments = arguments;
11520 app.instrumentationWatcher = watcher;
11521 app.instrumentationResultClass = className;
11522 Binder.restoreCallingIdentity(origId);
11523 }
11524
11525 return true;
11526 }
11527
11528 /**
11529 * Report errors that occur while attempting to start Instrumentation. Always writes the
11530 * error to the logs, but if somebody is watching, send the report there too. This enables
11531 * the "am" command to report errors with more information.
11532 *
11533 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11534 * @param cn The component name of the instrumentation.
11535 * @param report The error report.
11536 */
11537 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11538 ComponentName cn, String report) {
11539 Log.w(TAG, report);
11540 try {
11541 if (watcher != null) {
11542 Bundle results = new Bundle();
11543 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11544 results.putString("Error", report);
11545 watcher.instrumentationStatus(cn, -1, results);
11546 }
11547 } catch (RemoteException e) {
11548 Log.w(TAG, e);
11549 }
11550 }
11551
11552 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11553 if (app.instrumentationWatcher != null) {
11554 try {
11555 // NOTE: IInstrumentationWatcher *must* be oneway here
11556 app.instrumentationWatcher.instrumentationFinished(
11557 app.instrumentationClass,
11558 resultCode,
11559 results);
11560 } catch (RemoteException e) {
11561 }
11562 }
11563 app.instrumentationWatcher = null;
11564 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011565 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011566 app.instrumentationProfileFile = null;
11567 app.instrumentationArguments = null;
11568
11569 uninstallPackageLocked(app.processName, -1, false);
11570 }
11571
11572 public void finishInstrumentation(IApplicationThread target,
11573 int resultCode, Bundle results) {
11574 // Refuse possible leaked file descriptors
11575 if (results != null && results.hasFileDescriptors()) {
11576 throw new IllegalArgumentException("File descriptors passed in Intent");
11577 }
11578
11579 synchronized(this) {
11580 ProcessRecord app = getRecordForAppLocked(target);
11581 if (app == null) {
11582 Log.w(TAG, "finishInstrumentation: no app for " + target);
11583 return;
11584 }
11585 final long origId = Binder.clearCallingIdentity();
11586 finishInstrumentationLocked(app, resultCode, results);
11587 Binder.restoreCallingIdentity(origId);
11588 }
11589 }
11590
11591 // =========================================================
11592 // CONFIGURATION
11593 // =========================================================
11594
11595 public ConfigurationInfo getDeviceConfigurationInfo() {
11596 ConfigurationInfo config = new ConfigurationInfo();
11597 synchronized (this) {
11598 config.reqTouchScreen = mConfiguration.touchscreen;
11599 config.reqKeyboardType = mConfiguration.keyboard;
11600 config.reqNavigation = mConfiguration.navigation;
11601 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11602 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11603 }
11604 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11605 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11606 }
11607 }
11608 return config;
11609 }
11610
11611 public Configuration getConfiguration() {
11612 Configuration ci;
11613 synchronized(this) {
11614 ci = new Configuration(mConfiguration);
11615 }
11616 return ci;
11617 }
11618
11619 public void updateConfiguration(Configuration values) {
11620 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11621 "updateConfiguration()");
11622
11623 synchronized(this) {
11624 if (values == null && mWindowManager != null) {
11625 // sentinel: fetch the current configuration from the window manager
11626 values = mWindowManager.computeNewConfiguration();
11627 }
11628
11629 final long origId = Binder.clearCallingIdentity();
11630 updateConfigurationLocked(values, null);
11631 Binder.restoreCallingIdentity(origId);
11632 }
11633 }
11634
11635 /**
11636 * Do either or both things: (1) change the current configuration, and (2)
11637 * make sure the given activity is running with the (now) current
11638 * configuration. Returns true if the activity has been left running, or
11639 * false if <var>starting</var> is being destroyed to match the new
11640 * configuration.
11641 */
11642 public boolean updateConfigurationLocked(Configuration values,
11643 HistoryRecord starting) {
11644 int changes = 0;
11645
11646 boolean kept = true;
11647
11648 if (values != null) {
11649 Configuration newConfig = new Configuration(mConfiguration);
11650 changes = newConfig.updateFrom(values);
11651 if (changes != 0) {
11652 if (DEBUG_SWITCH) {
11653 Log.i(TAG, "Updating configuration to: " + values);
11654 }
11655
11656 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11657
11658 if (values.locale != null) {
11659 saveLocaleLocked(values.locale,
11660 !values.locale.equals(mConfiguration.locale),
11661 values.userSetLocale);
11662 }
11663
11664 mConfiguration = newConfig;
11665
11666 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11667 msg.obj = new Configuration(mConfiguration);
11668 mHandler.sendMessage(msg);
11669
11670 final int N = mLRUProcesses.size();
11671 for (int i=0; i<N; i++) {
11672 ProcessRecord app = mLRUProcesses.get(i);
11673 try {
11674 if (app.thread != null) {
11675 app.thread.scheduleConfigurationChanged(mConfiguration);
11676 }
11677 } catch (Exception e) {
11678 }
11679 }
11680 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11681 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11682 null, false, false, MY_PID, Process.SYSTEM_UID);
11683 }
11684 }
11685
11686 if (changes != 0 && starting == null) {
11687 // If the configuration changed, and the caller is not already
11688 // in the process of starting an activity, then find the top
11689 // activity to check if its configuration needs to change.
11690 starting = topRunningActivityLocked(null);
11691 }
11692
11693 if (starting != null) {
11694 kept = ensureActivityConfigurationLocked(starting, changes);
11695 if (kept) {
11696 // If this didn't result in the starting activity being
11697 // destroyed, then we need to make sure at this point that all
11698 // other activities are made visible.
11699 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11700 + ", ensuring others are correct.");
11701 ensureActivitiesVisibleLocked(starting, changes);
11702 }
11703 }
11704
11705 return kept;
11706 }
11707
11708 private final boolean relaunchActivityLocked(HistoryRecord r,
11709 int changes, boolean andResume) {
11710 List<ResultInfo> results = null;
11711 List<Intent> newIntents = null;
11712 if (andResume) {
11713 results = r.results;
11714 newIntents = r.newIntents;
11715 }
11716 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11717 + " with results=" + results + " newIntents=" + newIntents
11718 + " andResume=" + andResume);
11719 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11720 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11721 r.task.taskId, r.shortComponentName);
11722
11723 r.startFreezingScreenLocked(r.app, 0);
11724
11725 try {
11726 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11727 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11728 changes, !andResume);
11729 // Note: don't need to call pauseIfSleepingLocked() here, because
11730 // the caller will only pass in 'andResume' if this activity is
11731 // currently resumed, which implies we aren't sleeping.
11732 } catch (RemoteException e) {
11733 return false;
11734 }
11735
11736 if (andResume) {
11737 r.results = null;
11738 r.newIntents = null;
11739 }
11740
11741 return true;
11742 }
11743
11744 /**
11745 * Make sure the given activity matches the current configuration. Returns
11746 * false if the activity had to be destroyed. Returns true if the
11747 * configuration is the same, or the activity will remain running as-is
11748 * for whatever reason. Ensures the HistoryRecord is updated with the
11749 * correct configuration and all other bookkeeping is handled.
11750 */
11751 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11752 int globalChanges) {
11753 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11754
11755 // Short circuit: if the two configurations are the exact same
11756 // object (the common case), then there is nothing to do.
11757 Configuration newConfig = mConfiguration;
11758 if (r.configuration == newConfig) {
11759 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
11760 return true;
11761 }
11762
11763 // We don't worry about activities that are finishing.
11764 if (r.finishing) {
11765 if (DEBUG_SWITCH) Log.i(TAG,
11766 "Configuration doesn't matter in finishing " + r);
11767 r.stopFreezingScreenLocked(false);
11768 return true;
11769 }
11770
11771 // Okay we now are going to make this activity have the new config.
11772 // But then we need to figure out how it needs to deal with that.
11773 Configuration oldConfig = r.configuration;
11774 r.configuration = newConfig;
11775
11776 // If the activity isn't currently running, just leave the new
11777 // configuration and it will pick that up next time it starts.
11778 if (r.app == null || r.app.thread == null) {
11779 if (DEBUG_SWITCH) Log.i(TAG,
11780 "Configuration doesn't matter not running " + r);
11781 r.stopFreezingScreenLocked(false);
11782 return true;
11783 }
11784
11785 // If the activity isn't persistent, there is a chance we will
11786 // need to restart it.
11787 if (!r.persistent) {
11788
11789 // Figure out what has changed between the two configurations.
11790 int changes = oldConfig.diff(newConfig);
11791 if (DEBUG_SWITCH) {
11792 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
11793 + Integer.toHexString(changes) + ", handles=0x"
11794 + Integer.toHexString(r.info.configChanges));
11795 }
11796 if ((changes&(~r.info.configChanges)) != 0) {
11797 // Aha, the activity isn't handling the change, so DIE DIE DIE.
11798 r.configChangeFlags |= changes;
11799 r.startFreezingScreenLocked(r.app, globalChanges);
11800 if (r.app == null || r.app.thread == null) {
11801 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
11802 destroyActivityLocked(r, true);
11803 } else if (r.state == ActivityState.PAUSING) {
11804 // A little annoying: we are waiting for this activity to
11805 // finish pausing. Let's not do anything now, but just
11806 // flag that it needs to be restarted when done pausing.
11807 r.configDestroy = true;
11808 return true;
11809 } else if (r.state == ActivityState.RESUMED) {
11810 // Try to optimize this case: the configuration is changing
11811 // and we need to restart the top, resumed activity.
11812 // Instead of doing the normal handshaking, just say
11813 // "restart!".
11814 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11815 relaunchActivityLocked(r, r.configChangeFlags, true);
11816 r.configChangeFlags = 0;
11817 } else {
11818 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
11819 relaunchActivityLocked(r, r.configChangeFlags, false);
11820 r.configChangeFlags = 0;
11821 }
11822
11823 // All done... tell the caller we weren't able to keep this
11824 // activity around.
11825 return false;
11826 }
11827 }
11828
11829 // Default case: the activity can handle this new configuration, so
11830 // hand it over. Note that we don't need to give it the new
11831 // configuration, since we always send configuration changes to all
11832 // process when they happen so it can just use whatever configuration
11833 // it last got.
11834 if (r.app != null && r.app.thread != null) {
11835 try {
11836 r.app.thread.scheduleActivityConfigurationChanged(r);
11837 } catch (RemoteException e) {
11838 // If process died, whatever.
11839 }
11840 }
11841 r.stopFreezingScreenLocked(false);
11842
11843 return true;
11844 }
11845
11846 /**
11847 * Save the locale. You must be inside a synchronized (this) block.
11848 */
11849 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
11850 if(isDiff) {
11851 SystemProperties.set("user.language", l.getLanguage());
11852 SystemProperties.set("user.region", l.getCountry());
11853 }
11854
11855 if(isPersist) {
11856 SystemProperties.set("persist.sys.language", l.getLanguage());
11857 SystemProperties.set("persist.sys.country", l.getCountry());
11858 SystemProperties.set("persist.sys.localevar", l.getVariant());
11859 }
11860 }
11861
11862 // =========================================================
11863 // LIFETIME MANAGEMENT
11864 // =========================================================
11865
11866 private final int computeOomAdjLocked(
11867 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
11868 if (mAdjSeq == app.adjSeq) {
11869 // This adjustment has already been computed.
11870 return app.curAdj;
11871 }
11872
11873 if (app.thread == null) {
11874 app.adjSeq = mAdjSeq;
11875 return (app.curAdj=EMPTY_APP_ADJ);
11876 }
11877
11878 app.isForeground = false;
11879
The Android Open Source Project4df24232009-03-05 14:34:35 -080011880 // Determine the importance of the process, starting with most
11881 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011882 int adj;
11883 int N;
11884 if (app == TOP_APP || app.instrumentationClass != null
11885 || app.persistentActivities > 0) {
11886 // The last app on the list is the foreground app.
11887 adj = FOREGROUND_APP_ADJ;
11888 app.isForeground = true;
11889 } else if (app.curReceiver != null ||
11890 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
11891 // An app that is currently receiving a broadcast also
11892 // counts as being in the foreground.
11893 adj = FOREGROUND_APP_ADJ;
11894 } else if (app.executingServices.size() > 0) {
11895 // An app that is currently executing a service callback also
11896 // counts as being in the foreground.
11897 adj = FOREGROUND_APP_ADJ;
11898 } else if (app.foregroundServices || app.forcingToForeground != null) {
11899 // The user is aware of this app, so make it visible.
11900 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080011901 } else if (app == mHomeProcess) {
11902 // This process is hosting what we currently consider to be the
11903 // home app, so we don't want to let it go into the background.
11904 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011905 } else if ((N=app.activities.size()) != 0) {
11906 // This app is in the background with paused activities.
11907 adj = hiddenAdj;
11908 for (int j=0; j<N; j++) {
11909 if (((HistoryRecord)app.activities.get(j)).visible) {
11910 // This app has a visible activity!
11911 adj = VISIBLE_APP_ADJ;
11912 break;
11913 }
11914 }
11915 } else {
11916 // A very not-needed process.
11917 adj = EMPTY_APP_ADJ;
11918 }
11919
The Android Open Source Project4df24232009-03-05 14:34:35 -080011920 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011921 // there are applications dependent on our services or providers, but
11922 // this gives us a baseline and makes sure we don't get into an
11923 // infinite recursion.
11924 app.adjSeq = mAdjSeq;
11925 app.curRawAdj = adj;
11926 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
11927
Christopher Tate6fa95972009-06-05 18:43:55 -070011928 if (mBackupTarget != null && app == mBackupTarget.app) {
11929 // If possible we want to avoid killing apps while they're being backed up
11930 if (adj > BACKUP_APP_ADJ) {
11931 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
11932 adj = BACKUP_APP_ADJ;
11933 }
11934 }
11935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011936 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
11937 // If this process has active services running in it, we would
11938 // like to avoid killing it unless it would prevent the current
11939 // application from running.
11940 if (adj > hiddenAdj) {
11941 adj = hiddenAdj;
11942 }
11943 final long now = SystemClock.uptimeMillis();
11944 // This process is more important if the top activity is
11945 // bound to the service.
11946 Iterator jt = app.services.iterator();
11947 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11948 ServiceRecord s = (ServiceRecord)jt.next();
11949 if (s.startRequested) {
11950 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
11951 // This service has seen some activity within
11952 // recent memory, so we will keep its process ahead
11953 // of the background processes.
11954 if (adj > SECONDARY_SERVER_ADJ) {
11955 adj = SECONDARY_SERVER_ADJ;
11956 }
11957 } else {
11958 // This service has been inactive for too long, just
11959 // put it with the rest of the background processes.
11960 if (adj > hiddenAdj) {
11961 adj = hiddenAdj;
11962 }
11963 }
11964 }
11965 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
11966 Iterator<ConnectionRecord> kt
11967 = s.connections.values().iterator();
11968 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
11969 // XXX should compute this based on the max of
11970 // all connected clients.
11971 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070011972 if (cr.binding.client == app) {
11973 // Binding to ourself is not interesting.
11974 continue;
11975 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011976 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
11977 ProcessRecord client = cr.binding.client;
11978 int myHiddenAdj = hiddenAdj;
11979 if (myHiddenAdj > client.hiddenAdj) {
11980 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
11981 myHiddenAdj = client.hiddenAdj;
11982 } else {
11983 myHiddenAdj = VISIBLE_APP_ADJ;
11984 }
11985 }
11986 int clientAdj = computeOomAdjLocked(
11987 client, myHiddenAdj, TOP_APP);
11988 if (adj > clientAdj) {
11989 adj = clientAdj > VISIBLE_APP_ADJ
11990 ? clientAdj : VISIBLE_APP_ADJ;
11991 }
11992 }
11993 HistoryRecord a = cr.activity;
11994 //if (a != null) {
11995 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
11996 //}
11997 if (a != null && adj > FOREGROUND_APP_ADJ &&
11998 (a.state == ActivityState.RESUMED
11999 || a.state == ActivityState.PAUSING)) {
12000 adj = FOREGROUND_APP_ADJ;
12001 }
12002 }
12003 }
12004 }
12005 }
12006
12007 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12008 // If this process has published any content providers, then
12009 // its adjustment makes it at least as important as any of the
12010 // processes using those providers, and no less important than
12011 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12012 if (adj > CONTENT_PROVIDER_ADJ) {
12013 adj = CONTENT_PROVIDER_ADJ;
12014 }
12015 Iterator jt = app.pubProviders.values().iterator();
12016 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12017 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12018 if (cpr.clients.size() != 0) {
12019 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12020 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12021 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012022 if (client == app) {
12023 // Being our own client is not interesting.
12024 continue;
12025 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012026 int myHiddenAdj = hiddenAdj;
12027 if (myHiddenAdj > client.hiddenAdj) {
12028 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12029 myHiddenAdj = client.hiddenAdj;
12030 } else {
12031 myHiddenAdj = FOREGROUND_APP_ADJ;
12032 }
12033 }
12034 int clientAdj = computeOomAdjLocked(
12035 client, myHiddenAdj, TOP_APP);
12036 if (adj > clientAdj) {
12037 adj = clientAdj > FOREGROUND_APP_ADJ
12038 ? clientAdj : FOREGROUND_APP_ADJ;
12039 }
12040 }
12041 }
12042 // If the provider has external (non-framework) process
12043 // dependencies, ensure that its adjustment is at least
12044 // FOREGROUND_APP_ADJ.
12045 if (cpr.externals != 0) {
12046 if (adj > FOREGROUND_APP_ADJ) {
12047 adj = FOREGROUND_APP_ADJ;
12048 }
12049 }
12050 }
12051 }
12052
12053 app.curRawAdj = adj;
12054
12055 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12056 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12057 if (adj > app.maxAdj) {
12058 adj = app.maxAdj;
12059 }
12060
12061 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012062 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12063 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12064 : Process.THREAD_GROUP_DEFAULT;
12065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012066 return adj;
12067 }
12068
12069 /**
12070 * Ask a given process to GC right now.
12071 */
12072 final void performAppGcLocked(ProcessRecord app) {
12073 try {
12074 app.lastRequestedGc = SystemClock.uptimeMillis();
12075 if (app.thread != null) {
12076 app.thread.processInBackground();
12077 }
12078 } catch (Exception e) {
12079 // whatever.
12080 }
12081 }
12082
12083 /**
12084 * Returns true if things are idle enough to perform GCs.
12085 */
12086 private final boolean canGcNow() {
12087 return mParallelBroadcasts.size() == 0
12088 && mOrderedBroadcasts.size() == 0
12089 && (mSleeping || (mResumedActivity != null &&
12090 mResumedActivity.idle));
12091 }
12092
12093 /**
12094 * Perform GCs on all processes that are waiting for it, but only
12095 * if things are idle.
12096 */
12097 final void performAppGcsLocked() {
12098 final int N = mProcessesToGc.size();
12099 if (N <= 0) {
12100 return;
12101 }
12102 if (canGcNow()) {
12103 while (mProcessesToGc.size() > 0) {
12104 ProcessRecord proc = mProcessesToGc.remove(0);
12105 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12106 // To avoid spamming the system, we will GC processes one
12107 // at a time, waiting a few seconds between each.
12108 performAppGcLocked(proc);
12109 scheduleAppGcsLocked();
12110 return;
12111 }
12112 }
12113 }
12114 }
12115
12116 /**
12117 * If all looks good, perform GCs on all processes waiting for them.
12118 */
12119 final void performAppGcsIfAppropriateLocked() {
12120 if (canGcNow()) {
12121 performAppGcsLocked();
12122 return;
12123 }
12124 // Still not idle, wait some more.
12125 scheduleAppGcsLocked();
12126 }
12127
12128 /**
12129 * Schedule the execution of all pending app GCs.
12130 */
12131 final void scheduleAppGcsLocked() {
12132 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12133 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12134 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12135 }
12136
12137 /**
12138 * Set up to ask a process to GC itself. This will either do it
12139 * immediately, or put it on the list of processes to gc the next
12140 * time things are idle.
12141 */
12142 final void scheduleAppGcLocked(ProcessRecord app) {
12143 long now = SystemClock.uptimeMillis();
12144 if ((app.lastRequestedGc+5000) > now) {
12145 return;
12146 }
12147 if (!mProcessesToGc.contains(app)) {
12148 mProcessesToGc.add(app);
12149 scheduleAppGcsLocked();
12150 }
12151 }
12152
12153 private final boolean updateOomAdjLocked(
12154 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12155 app.hiddenAdj = hiddenAdj;
12156
12157 if (app.thread == null) {
12158 return true;
12159 }
12160
12161 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12162
12163 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12164 //Thread priority adjustment is disabled out to see
12165 //how the kernel scheduler performs.
12166 if (false) {
12167 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12168 app.setIsForeground = app.isForeground;
12169 if (app.pid != MY_PID) {
12170 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12171 + " to " + (app.isForeground
12172 ? Process.THREAD_PRIORITY_FOREGROUND
12173 : Process.THREAD_PRIORITY_DEFAULT));
12174 try {
12175 Process.setThreadPriority(app.pid, app.isForeground
12176 ? Process.THREAD_PRIORITY_FOREGROUND
12177 : Process.THREAD_PRIORITY_DEFAULT);
12178 } catch (RuntimeException e) {
12179 Log.w(TAG, "Exception trying to set priority of application thread "
12180 + app.pid, e);
12181 }
12182 }
12183 }
12184 }
12185 if (app.pid != 0 && app.pid != MY_PID) {
12186 if (app.curRawAdj != app.setRawAdj) {
12187 if (app.curRawAdj > FOREGROUND_APP_ADJ
12188 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12189 // If this app is transitioning from foreground to
12190 // non-foreground, have it do a gc.
12191 scheduleAppGcLocked(app);
12192 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12193 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12194 // Likewise do a gc when an app is moving in to the
12195 // background (such as a service stopping).
12196 scheduleAppGcLocked(app);
12197 }
12198 app.setRawAdj = app.curRawAdj;
12199 }
12200 if (adj != app.setAdj) {
12201 if (Process.setOomAdj(app.pid, adj)) {
12202 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12203 TAG, "Set app " + app.processName +
12204 " oom adj to " + adj);
12205 app.setAdj = adj;
12206 } else {
12207 return false;
12208 }
12209 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012210 if (app.setSchedGroup != app.curSchedGroup) {
12211 app.setSchedGroup = app.curSchedGroup;
12212 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12213 "Setting process group of " + app.processName
12214 + " to " + app.curSchedGroup);
12215 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012216 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012217 try {
12218 Process.setProcessGroup(app.pid, app.curSchedGroup);
12219 } catch (Exception e) {
12220 Log.w(TAG, "Failed setting process group of " + app.pid
12221 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012222 e.printStackTrace();
12223 } finally {
12224 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012225 }
12226 }
12227 if (false) {
12228 if (app.thread != null) {
12229 try {
12230 app.thread.setSchedulingGroup(app.curSchedGroup);
12231 } catch (RemoteException e) {
12232 }
12233 }
12234 }
12235 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012236 }
12237
12238 return true;
12239 }
12240
12241 private final HistoryRecord resumedAppLocked() {
12242 HistoryRecord resumedActivity = mResumedActivity;
12243 if (resumedActivity == null || resumedActivity.app == null) {
12244 resumedActivity = mPausingActivity;
12245 if (resumedActivity == null || resumedActivity.app == null) {
12246 resumedActivity = topRunningActivityLocked(null);
12247 }
12248 }
12249 return resumedActivity;
12250 }
12251
12252 private final boolean updateOomAdjLocked(ProcessRecord app) {
12253 final HistoryRecord TOP_ACT = resumedAppLocked();
12254 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12255 int curAdj = app.curAdj;
12256 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12257 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12258
12259 mAdjSeq++;
12260
12261 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12262 if (res) {
12263 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12264 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12265 if (nowHidden != wasHidden) {
12266 // Changed to/from hidden state, so apps after it in the LRU
12267 // list may also be changed.
12268 updateOomAdjLocked();
12269 }
12270 }
12271 return res;
12272 }
12273
12274 private final boolean updateOomAdjLocked() {
12275 boolean didOomAdj = true;
12276 final HistoryRecord TOP_ACT = resumedAppLocked();
12277 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12278
12279 if (false) {
12280 RuntimeException e = new RuntimeException();
12281 e.fillInStackTrace();
12282 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12283 }
12284
12285 mAdjSeq++;
12286
12287 // First try updating the OOM adjustment for each of the
12288 // application processes based on their current state.
12289 int i = mLRUProcesses.size();
12290 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12291 while (i > 0) {
12292 i--;
12293 ProcessRecord app = mLRUProcesses.get(i);
12294 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12295 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12296 && app.curAdj == curHiddenAdj) {
12297 curHiddenAdj++;
12298 }
12299 } else {
12300 didOomAdj = false;
12301 }
12302 }
12303
12304 // todo: for now pretend like OOM ADJ didn't work, because things
12305 // aren't behaving as expected on Linux -- it's not killing processes.
12306 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12307 }
12308
12309 private final void trimApplications() {
12310 synchronized (this) {
12311 int i;
12312
12313 // First remove any unused application processes whose package
12314 // has been removed.
12315 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12316 final ProcessRecord app = mRemovedProcesses.get(i);
12317 if (app.activities.size() == 0
12318 && app.curReceiver == null && app.services.size() == 0) {
12319 Log.i(
12320 TAG, "Exiting empty application process "
12321 + app.processName + " ("
12322 + (app.thread != null ? app.thread.asBinder() : null)
12323 + ")\n");
12324 if (app.pid > 0 && app.pid != MY_PID) {
12325 Process.killProcess(app.pid);
12326 } else {
12327 try {
12328 app.thread.scheduleExit();
12329 } catch (Exception e) {
12330 // Ignore exceptions.
12331 }
12332 }
12333 cleanUpApplicationRecordLocked(app, false, -1);
12334 mRemovedProcesses.remove(i);
12335
12336 if (app.persistent) {
12337 if (app.persistent) {
12338 addAppLocked(app.info);
12339 }
12340 }
12341 }
12342 }
12343
12344 // Now try updating the OOM adjustment for each of the
12345 // application processes based on their current state.
12346 // If the setOomAdj() API is not supported, then go with our
12347 // back-up plan...
12348 if (!updateOomAdjLocked()) {
12349
12350 // Count how many processes are running services.
12351 int numServiceProcs = 0;
12352 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12353 final ProcessRecord app = mLRUProcesses.get(i);
12354
12355 if (app.persistent || app.services.size() != 0
12356 || app.curReceiver != null
12357 || app.persistentActivities > 0) {
12358 // Don't count processes holding services against our
12359 // maximum process count.
12360 if (localLOGV) Log.v(
12361 TAG, "Not trimming app " + app + " with services: "
12362 + app.services);
12363 numServiceProcs++;
12364 }
12365 }
12366
12367 int curMaxProcs = mProcessLimit;
12368 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12369 if (mAlwaysFinishActivities) {
12370 curMaxProcs = 1;
12371 }
12372 curMaxProcs += numServiceProcs;
12373
12374 // Quit as many processes as we can to get down to the desired
12375 // process count. First remove any processes that no longer
12376 // have activites running in them.
12377 for ( i=0;
12378 i<mLRUProcesses.size()
12379 && mLRUProcesses.size() > curMaxProcs;
12380 i++) {
12381 final ProcessRecord app = mLRUProcesses.get(i);
12382 // Quit an application only if it is not currently
12383 // running any activities.
12384 if (!app.persistent && app.activities.size() == 0
12385 && app.curReceiver == null && app.services.size() == 0) {
12386 Log.i(
12387 TAG, "Exiting empty application process "
12388 + app.processName + " ("
12389 + (app.thread != null ? app.thread.asBinder() : null)
12390 + ")\n");
12391 if (app.pid > 0 && app.pid != MY_PID) {
12392 Process.killProcess(app.pid);
12393 } else {
12394 try {
12395 app.thread.scheduleExit();
12396 } catch (Exception e) {
12397 // Ignore exceptions.
12398 }
12399 }
12400 // todo: For now we assume the application is not buggy
12401 // or evil, and will quit as a result of our request.
12402 // Eventually we need to drive this off of the death
12403 // notification, and kill the process if it takes too long.
12404 cleanUpApplicationRecordLocked(app, false, i);
12405 i--;
12406 }
12407 }
12408
12409 // If we still have too many processes, now from the least
12410 // recently used process we start finishing activities.
12411 if (Config.LOGV) Log.v(
12412 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12413 " of " + curMaxProcs + " processes");
12414 for ( i=0;
12415 i<mLRUProcesses.size()
12416 && mLRUProcesses.size() > curMaxProcs;
12417 i++) {
12418 final ProcessRecord app = mLRUProcesses.get(i);
12419 // Quit the application only if we have a state saved for
12420 // all of its activities.
12421 boolean canQuit = !app.persistent && app.curReceiver == null
12422 && app.services.size() == 0
12423 && app.persistentActivities == 0;
12424 int NUMA = app.activities.size();
12425 int j;
12426 if (Config.LOGV) Log.v(
12427 TAG, "Looking to quit " + app.processName);
12428 for (j=0; j<NUMA && canQuit; j++) {
12429 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12430 if (Config.LOGV) Log.v(
12431 TAG, " " + r.intent.getComponent().flattenToShortString()
12432 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12433 canQuit = (r.haveState || !r.stateNotNeeded)
12434 && !r.visible && r.stopped;
12435 }
12436 if (canQuit) {
12437 // Finish all of the activities, and then the app itself.
12438 for (j=0; j<NUMA; j++) {
12439 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12440 if (!r.finishing) {
12441 destroyActivityLocked(r, false);
12442 }
12443 r.resultTo = null;
12444 }
12445 Log.i(TAG, "Exiting application process "
12446 + app.processName + " ("
12447 + (app.thread != null ? app.thread.asBinder() : null)
12448 + ")\n");
12449 if (app.pid > 0 && app.pid != MY_PID) {
12450 Process.killProcess(app.pid);
12451 } else {
12452 try {
12453 app.thread.scheduleExit();
12454 } catch (Exception e) {
12455 // Ignore exceptions.
12456 }
12457 }
12458 // todo: For now we assume the application is not buggy
12459 // or evil, and will quit as a result of our request.
12460 // Eventually we need to drive this off of the death
12461 // notification, and kill the process if it takes too long.
12462 cleanUpApplicationRecordLocked(app, false, i);
12463 i--;
12464 //dump();
12465 }
12466 }
12467
12468 }
12469
12470 int curMaxActivities = MAX_ACTIVITIES;
12471 if (mAlwaysFinishActivities) {
12472 curMaxActivities = 1;
12473 }
12474
12475 // Finally, if there are too many activities now running, try to
12476 // finish as many as we can to get back down to the limit.
12477 for ( i=0;
12478 i<mLRUActivities.size()
12479 && mLRUActivities.size() > curMaxActivities;
12480 i++) {
12481 final HistoryRecord r
12482 = (HistoryRecord)mLRUActivities.get(i);
12483
12484 // We can finish this one if we have its icicle saved and
12485 // it is not persistent.
12486 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12487 && r.stopped && !r.persistent && !r.finishing) {
12488 final int origSize = mLRUActivities.size();
12489 destroyActivityLocked(r, true);
12490
12491 // This will remove it from the LRU list, so keep
12492 // our index at the same value. Note that this check to
12493 // see if the size changes is just paranoia -- if
12494 // something unexpected happens, we don't want to end up
12495 // in an infinite loop.
12496 if (origSize > mLRUActivities.size()) {
12497 i--;
12498 }
12499 }
12500 }
12501 }
12502 }
12503
12504 /** This method sends the specified signal to each of the persistent apps */
12505 public void signalPersistentProcesses(int sig) throws RemoteException {
12506 if (sig != Process.SIGNAL_USR1) {
12507 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12508 }
12509
12510 synchronized (this) {
12511 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12512 != PackageManager.PERMISSION_GRANTED) {
12513 throw new SecurityException("Requires permission "
12514 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12515 }
12516
12517 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12518 ProcessRecord r = mLRUProcesses.get(i);
12519 if (r.thread != null && r.persistent) {
12520 Process.sendSignal(r.pid, sig);
12521 }
12522 }
12523 }
12524 }
12525
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012526 public boolean profileControl(String process, boolean start,
12527 String path) throws RemoteException {
12528
12529 synchronized (this) {
12530 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12531 // its own permission.
12532 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12533 != PackageManager.PERMISSION_GRANTED) {
12534 throw new SecurityException("Requires permission "
12535 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
12536 }
12537
12538 ProcessRecord proc = null;
12539 try {
12540 int pid = Integer.parseInt(process);
12541 synchronized (mPidsSelfLocked) {
12542 proc = mPidsSelfLocked.get(pid);
12543 }
12544 } catch (NumberFormatException e) {
12545 }
12546
12547 if (proc == null) {
12548 HashMap<String, SparseArray<ProcessRecord>> all
12549 = mProcessNames.getMap();
12550 SparseArray<ProcessRecord> procs = all.get(process);
12551 if (procs != null && procs.size() > 0) {
12552 proc = procs.valueAt(0);
12553 }
12554 }
12555
12556 if (proc == null || proc.thread == null) {
12557 throw new IllegalArgumentException("Unknown process: " + process);
12558 }
12559
12560 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12561 if (isSecure) {
12562 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12563 throw new SecurityException("Process not debuggable: " + proc);
12564 }
12565 }
12566
12567 try {
12568 proc.thread.profilerControl(start, path);
12569 return true;
12570 } catch (RemoteException e) {
12571 throw new IllegalStateException("Process disappeared");
12572 }
12573 }
12574 }
12575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012576 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12577 public void monitor() {
12578 synchronized (this) { }
12579 }
12580}